<commit_before>//! Procedural macro for the `#[async]` attribute.
//!
//! This crate is an implementation of the `#[async]` attribute as a procedural
//! macro. This is nightly-only for now as it's using the unstable features of
//! procedural macros. Furthermore it's generating code that's using a new
//! keyword, `yield`, and a new construct, generators, both of which are also
//! unstable.
//!
//! Currently this crate depends on `syn` and `quote` to do all the heavy
//! lifting, this is just a very small shim around creating a closure/future out
//! of a generator.

#![feature(proc_macro)]
#![recursion_limit = "128"]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;
extern crate syn;

use proc_macro::{TokenStream, TokenTree, Delimiter, TokenNode};
use syn::*;
use syn::fold::Folder;

#[proc_macro_attribute]
pub fn async(attribute: TokenStream, function: TokenStream) -> TokenStream {
    // Handle arguments to the #[async] attribute, if any
    let attribute = attribute.to_string();
    let boxed = if attribute == "( boxed )" {
        true
    } else if attribute == "" {
        false
    } else {
        panic!("the #[async] attribute currently only takes `boxed` as an arg");
    };

    // Parse our item, expecting a function. This function may be an actual
    // top-level function or it could be a method (typically dictated by the
    // arguments). We then extract everything we'd like to use.
    let Item { attrs, node } = syn::parse(function)
        .expect("failed to parse tokens as a function");
    let ItemFn {
        ident,
        vis,
        unsafety,
        constness,
        abi,
        block,
        decl,
        ..
    } = match node {
        ItemKind::Fn(item) => item,
        _ => panic!("#[async] can only be applied to functions"),
    };
    let FnDecl { inputs, output, variadic, generics, .. } = { *decl };
    let where_clause = &generics.where_clause;
    assert!(!variadic, "variadic functions cannot be async");
    let output = match output {
        FunctionRetTy::Ty(t, _) => t,
        FunctionRetTy::Default => {
            TyTup {
                tys: Default::default(),
                lone_comma: Default::default(),
                paren_token: Default::default(),
            }.into()
        }
    };

    // We've got to get a bit creative with our handling of arguments. For a
    // number of reasons we translate this:
    //
    //      fn foo(ref a: u32) -> Result<u32, u32> {
    //          // ...
    //      }
    //
    // into roughly:
    //
    //      fn foo(__arg_0: u32) -> impl Future<...> {
    //          gen(move || {
    //              let ref a = __arg0;
    //
    //              // ...
    //          })
    //      }
    //
    // The intention here is to ensure that all local function variables get
    // moved into the generator we're creating, and they're also all then bound
    // appropriately according to their patterns and whatnot.
    //
    // We notably skip everything related to `self` which typically doesn't have
    // many patterns with it and just gets captured naturally.
    let mut inputs_no_patterns = Vec::new();
    let mut patterns = Vec::new();
    let mut temp_bindings = Vec::new();
    for (i, input) in inputs.into_iter().enumerate() {
        let input = input.into_item();

        // `self: Box<Self>` will get captured naturally
        let mut is_input_no_pattern = false;
        if let FnArg::Captured(ref arg) = input {
            if let Pat::Ident(PatIdent { ref ident, ..}) = arg.pat {
                if ident == "self" {
                    is_input_no_pattern = true;
                }
            }
        }
        if is_input_no_pattern {
            inputs_no_patterns.push(input);
            continue
        }

        match input {
            // `a: B`
            FnArg::Captured(ArgCaptured { pat, ty, .. }) => {
                patterns.push(pat);
                let ident = Ident::from(format!("__arg_{}", i));
                temp_bindings.push(ident.clone());
                let pat = PatIdent {
                    mode: BindingMode::ByValue(Mutability::Immutable),
                    ident: ident,
                    at_token: None,
                    subpat: None,
                };
                inputs_no_patterns.push(ArgCaptured {
                    pat: pat.into(),
                    ty: ty,
                    colon_token: Default::default(),
                }.into());
            }

            // Other `self`-related arguments get captured naturally
            _ => {
                inputs_no_patterns.push(input);
            }
        }
    }

    // This is the point where we handle
    //
    //      #[async]
    //      for x in y {
    //      }
    //
    // Basically just take all those expression and expand them.
    let block = ExpandAsyncFor.fold_block(*block);

    // TODO: can we lift the restriction that `futures` must be at the root of
    //       the crate?
    let return_ty = if boxed {
        quote! {
            Box<::futures::Future<
                Item = <#output as ::futures::__rt::MyTry>::MyOk,
                Error = <#output as ::futures::__rt::MyTry>::MyError,
            >>
        }
    } else {
        // Dunno why this is buggy, hits weird typecheck errors in tests
        //
        // quote! {
        //     impl ::futures::Future<
        //         Item = <#output as ::futures::__rt::MyTry>::MyOk,
        //         Error = <#output as ::futures::__rt::MyTry>::MyError,
        //     >
        // }

        quote! { impl ::futures::__rt::MyFuture<#output> }
    };

    let maybe_boxed = if boxed {
        quote! { Box::new }
    } else {
        quote! { }
    };

    let output = quote! {
        #(#attrs)*
        #vis #unsafety #abi #constness
        fn #ident #generics(#(#inputs_no_patterns),*) -> #return_ty
            #where_clause
        {
            #maybe_boxed (::futures::__rt::gen(move || {
                let __e = {
                    #( let #patterns = #temp_bindings; )*
                    #block
                };

                // Ensure that this closure is a generator, even if it doesn't
                // have any `yield` statements.
                #[allow(unreachable_code)]
                {
                    return __e;
                    loop { yield }
                }
            }))
        }
    };

    // println!("{}", output);
    output.into()
}

#[proc_macro]
pub fn async_block(input: TokenStream) -> TokenStream {
    let input = TokenStream::from(TokenTree {
        kind: TokenNode::Group(Delimiter::Brace, input),
        span: Default::default(),
    });
    let expr = syn::parse(input)
        .expect("failed to parse tokens as an expression");
    let expr = ExpandAsyncFor.fold_expr(expr);

    (quote! {
        ::futures::__rt::gen(move || { #expr })
    }).into()
}

struct ExpandAsyncFor;

impl Folder for ExpandAsyncFor {
    fn fold_expr(&mut self, expr: Expr) -> Expr {
        let expr = fold::noop_fold_expr(self, expr);
        if expr.attrs.len() != 1 {
            return expr
        }
        // TODO: more validation here
        if expr.attrs[0].path.segments.get(0).item().ident != "async" {
            return expr
        }
        let all = match expr.node {
            ExprKind::ForLoop(item) => item,
            _ => panic!("only for expressions can have #[async]"),
        };
        let ExprForLoop { pat, expr, body, label, colon_token, .. } = all;

        // Basically just expand to a `poll` loop
        let tokens = quote! {{
            let mut __stream = #expr;
            #label
            #colon_token
            loop {
                let #pat = {
                    extern crate futures_await;
                    let r = futures_await::Stream::poll(&mut __stream)?;
                    match r {
                        futures_await::Async::Ready(e) => {
                            match e {
                                futures_await::__rt::Some(e) => e,
                                futures_await::__rt::None => break,
                            }
                        }
                        futures_await::Async::NotReady => {
                            yield;
                            continue
                        }
                    }
                };

                #body
            }
        }};
        syn::parse(tokens.into()).unwrap()
    }

    // Don't recurse into items
    fn fold_item(&mut self, item: Item) -> Item {
        item
    }
}
<commit_msg>Use type ascription to improve error message<commit_after>//! Procedural macro for the `#[async]` attribute.
//!
//! This crate is an implementation of the `#[async]` attribute as a procedural
//! macro. This is nightly-only for now as it's using the unstable features of
//! procedural macros. Furthermore it's generating code that's using a new
//! keyword, `yield`, and a new construct, generators, both of which are also
//! unstable.
//!
//! Currently this crate depends on `syn` and `quote` to do all the heavy
//! lifting, this is just a very small shim around creating a closure/future out
//! of a generator.

#![feature(proc_macro)]
#![recursion_limit = "128"]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;
extern crate syn;

use proc_macro::{TokenStream, TokenTree, Delimiter, TokenNode};
use syn::*;
use syn::fold::Folder;

#[proc_macro_attribute]
pub fn async(attribute: TokenStream, function: TokenStream) -> TokenStream {
    // Handle arguments to the #[async] attribute, if any
    let attribute = attribute.to_string();
    let boxed = if attribute == "( boxed )" {
        true
    } else if attribute == "" {
        false
    } else {
        panic!("the #[async] attribute currently only takes `boxed` as an arg");
    };

    // Parse our item, expecting a function. This function may be an actual
    // top-level function or it could be a method (typically dictated by the
    // arguments). We then extract everything we'd like to use.
    let Item { attrs, node } = syn::parse(function)
        .expect("failed to parse tokens as a function");
    let ItemFn {
        ident,
        vis,
        unsafety,
        constness,
        abi,
        block,
        decl,
        ..
    } = match node {
        ItemKind::Fn(item) => item,
        _ => panic!("#[async] can only be applied to functions"),
    };
    let FnDecl { inputs, output, variadic, generics, .. } = { *decl };
    let where_clause = &generics.where_clause;
    assert!(!variadic, "variadic functions cannot be async");
    let output = match output {
        FunctionRetTy::Ty(t, _) => t,
        FunctionRetTy::Default => {
            TyTup {
                tys: Default::default(),
                lone_comma: Default::default(),
                paren_token: Default::default(),
            }.into()
        }
    };

    // We've got to get a bit creative with our handling of arguments. For a
    // number of reasons we translate this:
    //
    //      fn foo(ref a: u32) -> Result<u32, u32> {
    //          // ...
    //      }
    //
    // into roughly:
    //
    //      fn foo(__arg_0: u32) -> impl Future<...> {
    //          gen(move || {
    //              let ref a = __arg0;
    //
    //              // ...
    //          })
    //      }
    //
    // The intention here is to ensure that all local function variables get
    // moved into the generator we're creating, and they're also all then bound
    // appropriately according to their patterns and whatnot.
    //
    // We notably skip everything related to `self` which typically doesn't have
    // many patterns with it and just gets captured naturally.
    let mut inputs_no_patterns = Vec::new();
    let mut patterns = Vec::new();
    let mut temp_bindings = Vec::new();
    for (i, input) in inputs.into_iter().enumerate() {
        let input = input.into_item();

        // `self: Box<Self>` will get captured naturally
        let mut is_input_no_pattern = false;
        if let FnArg::Captured(ref arg) = input {
            if let Pat::Ident(PatIdent { ref ident, ..}) = arg.pat {
                if ident == "self" {
                    is_input_no_pattern = true;
                }
            }
        }
        if is_input_no_pattern {
            inputs_no_patterns.push(input);
            continue
        }

        match input {
            // `a: B`
            FnArg::Captured(ArgCaptured { pat, ty, .. }) => {
                patterns.push(pat);
                let ident = Ident::from(format!("__arg_{}", i));
                temp_bindings.push(ident.clone());
                let pat = PatIdent {
                    mode: BindingMode::ByValue(Mutability::Immutable),
                    ident: ident,
                    at_token: None,
                    subpat: None,
                };
                inputs_no_patterns.push(ArgCaptured {
                    pat: pat.into(),
                    ty: ty,
                    colon_token: Default::default(),
                }.into());
            }

            // Other `self`-related arguments get captured naturally
            _ => {
                inputs_no_patterns.push(input);
            }
        }
    }

    // This is the point where we handle
    //
    //      #[async]
    //      for x in y {
    //      }
    //
    // Basically just take all those expression and expand them.
    let block = ExpandAsyncFor.fold_block(*block);

    // TODO: can we lift the restriction that `futures` must be at the root of
    //       the crate?
    let return_ty = if boxed {
        quote! {
            Box<::futures::Future<
                Item = <#output as ::futures::__rt::MyTry>::MyOk,
                Error = <#output as ::futures::__rt::MyTry>::MyError,
            >>
        }
    } else {
        // Dunno why this is buggy, hits weird typecheck errors in tests
        //
        // quote! {
        //     impl ::futures::Future<
        //         Item = <#output as ::futures::__rt::MyTry>::MyOk,
        //         Error = <#output as ::futures::__rt::MyTry>::MyError,
        //     >
        // }

        quote! { impl ::futures::__rt::MyFuture<#output> }
    };

    let maybe_boxed = if boxed {
        quote! { Box::new }
    } else {
        quote! { }
    };

    let output = quote! {
        #(#attrs)*
        #vis #unsafety #abi #constness
        fn #ident #generics(#(#inputs_no_patterns),*) -> #return_ty
            #where_clause
        {
            #maybe_boxed (::futures::__rt::gen(move || {
                let __e: #output = {
                    #( let #patterns = #temp_bindings; )*
                    #block
                };

                // Ensure that this closure is a generator, even if it doesn't
                // have any `yield` statements.
                #[allow(unreachable_code)]
                {
                    return __e;
                    loop { yield }
                }
            }))
        }
    };

    // println!("{}", output);
    output.into()
}

#[proc_macro]
pub fn async_block(input: TokenStream) -> TokenStream {
    let input = TokenStream::from(TokenTree {
        kind: TokenNode::Group(Delimiter::Brace, input),
        span: Default::default(),
    });
    let expr = syn::parse(input)
        .expect("failed to parse tokens as an expression");
    let expr = ExpandAsyncFor.fold_expr(expr);

    (quote! {
        ::futures::__rt::gen(move || { #expr })
    }).into()
}

struct ExpandAsyncFor;

impl Folder for ExpandAsyncFor {
    fn fold_expr(&mut self, expr: Expr) -> Expr {
        let expr = fold::noop_fold_expr(self, expr);
        if expr.attrs.len() != 1 {
            return expr
        }
        // TODO: more validation here
        if expr.attrs[0].path.segments.get(0).item().ident != "async" {
            return expr
        }
        let all = match expr.node {
            ExprKind::ForLoop(item) => item,
            _ => panic!("only for expressions can have #[async]"),
        };
        let ExprForLoop { pat, expr, body, label, colon_token, .. } = all;

        // Basically just expand to a `poll` loop
        let tokens = quote! {{
            let mut __stream = #expr;
            #label
            #colon_token
            loop {
                let #pat = {
                    extern crate futures_await;
                    let r = futures_await::Stream::poll(&mut __stream)?;
                    match r {
                        futures_await::Async::Ready(e) => {
                            match e {
                                futures_await::__rt::Some(e) => e,
                                futures_await::__rt::None => break,
                            }
                        }
                        futures_await::Async::NotReady => {
                            yield;
                            continue
                        }
                    }
                };

                #body
            }
        }};
        syn::parse(tokens.into()).unwrap()
    }

    // Don't recurse into items
    fn fold_item(&mut self, item: Item) -> Item {
        item
    }
}
<|endoftext|>


<commit_before>//! Additional combinators for testing futures.

mod assert_unmoved;
use self::assert_unmoved::AssertUnmoved;

mod pending_once;
use self::pending_once::PendingOnce;

use futures_core::future::Future;
use futures_executor;
use std::thread;

/// Additional combinators for testing futures.
pub trait FutureTestExt: Future {
    /// Asserts that the given is not moved after being polled.
    ///
    /// A check for movement is performed each time the future is polled
    /// and when `Drop` is called.
    ///
    /// Aside from keeping track of the location at which the future was first
    /// polled and providing assertions, this future adds no runtime behavior
    /// and simply delegates to the child future.
    fn assert_unmoved(self) -> AssertUnmoved<Self>
    where
        Self: Sized,
    {
        AssertUnmoved::new(self)
    }

    /// Introduces one [`Poll::Pending`](futures_core::task::Poll::Pending)
    /// before polling the given future.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, futures_api)]
    /// use futures::task::Poll;
    /// use futures::future::FutureExt;
    /// use futures_test::task;
    /// use futures_test::future::FutureTestExt;
    /// use pin_utils::pin_mut;
    ///
    /// let future = (async { 5 }).pending_once();
    /// pin_mut!(future);
    ///
    /// let lw = &task::noop_local_waker_ref();
    ///
    /// assert_eq!(future.poll_unpin(lw), Poll::Pending);
    /// assert_eq!(future.poll_unpin(lw), Poll::Ready(5));
    /// ```
    fn pending_once(self) -> PendingOnce<Self>
    where
        Self: Sized,
    {
        pending_once::PendingOnce::new(self)
    }

    /// Runs this future on a dedicated executor running in a background thread.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, futures_api)]
    /// use futures::channel::oneshot;
    /// use futures::executor::block_on;
    /// use futures_test::future::FutureTestExt;
    ///
    /// let (tx, rx) = oneshot::channel::<i32>();
    ///
    /// (async { tx.send(5).unwrap() }).run_in_background();
    ///
    /// assert_eq!(block_on(rx), Ok(5));
    /// ```
    fn run_in_background(self)
    where
        Self: Sized + Send + 'static,
        Self::Output: Send,
    {
        thread::spawn(|| futures_executor::block_on(self));
    }
}

impl<Fut> FutureTestExt for Fut where Fut: Future {}
<commit_msg>Make AssertUnmoved and PendingOnce public<commit_after>//! Additional combinators for testing futures.

mod assert_unmoved;
pub use self::assert_unmoved::AssertUnmoved;

mod pending_once;
pub use self::pending_once::PendingOnce;

use futures_core::future::Future;
use futures_executor;
use std::thread;

/// Additional combinators for testing futures.
pub trait FutureTestExt: Future {
    /// Asserts that the given is not moved after being polled.
    ///
    /// A check for movement is performed each time the future is polled
    /// and when `Drop` is called.
    ///
    /// Aside from keeping track of the location at which the future was first
    /// polled and providing assertions, this future adds no runtime behavior
    /// and simply delegates to the child future.
    fn assert_unmoved(self) -> AssertUnmoved<Self>
    where
        Self: Sized,
    {
        AssertUnmoved::new(self)
    }

    /// Introduces one [`Poll::Pending`](futures_core::task::Poll::Pending)
    /// before polling the given future.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, futures_api)]
    /// use futures::task::Poll;
    /// use futures::future::FutureExt;
    /// use futures_test::task;
    /// use futures_test::future::FutureTestExt;
    /// use pin_utils::pin_mut;
    ///
    /// let future = (async { 5 }).pending_once();
    /// pin_mut!(future);
    ///
    /// let lw = &task::noop_local_waker_ref();
    ///
    /// assert_eq!(future.poll_unpin(lw), Poll::Pending);
    /// assert_eq!(future.poll_unpin(lw), Poll::Ready(5));
    /// ```
    fn pending_once(self) -> PendingOnce<Self>
    where
        Self: Sized,
    {
        pending_once::PendingOnce::new(self)
    }

    /// Runs this future on a dedicated executor running in a background thread.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, futures_api)]
    /// use futures::channel::oneshot;
    /// use futures::executor::block_on;
    /// use futures_test::future::FutureTestExt;
    ///
    /// let (tx, rx) = oneshot::channel::<i32>();
    ///
    /// (async { tx.send(5).unwrap() }).run_in_background();
    ///
    /// assert_eq!(block_on(rx), Ok(5));
    /// ```
    fn run_in_background(self)
    where
        Self: Sized + Send + 'static,
        Self::Output: Send,
    {
        thread::spawn(|| futures_executor::block_on(self));
    }
}

impl<Fut> FutureTestExt for Fut where Fut: Future {}
<|endoftext|>


<commit_before>use grammar::*;
use ast::*;
use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;
use num::rational::BigRational;

#[derive(Clone, Eq, Debug, PartialEq)]
pub enum Value {
    Number(BigRational),
    CharString(String),
    Boolean(bool),
    Map(BTreeMap<Rc<Value>, Rc<Value>>),
    Closure(u8, Closure),
    Fn(u8, Closure),
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub enum Instruction {
    Push(Literal),
    Fetch(String),
    LocalAssign(String),
    Assign(String),
    Call(u8),
    // Set(String, Value),
}

pub type InstructionSequence = Vec<Instruction>;
pub type BindingMap = Rc<RefCell<BTreeMap<String, Value>>>;

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Closure {
    instructions: Box<InstructionSequence>,
    parent_bindings: BindingMap,
}

impl Closure {
    pub fn new(instructions: InstructionSequence, parent_bindings: &BindingMap) -> Closure {
        Closure {
            instructions: Box::new(instructions),
            parent_bindings: parent_bindings.clone(),
        }
    }
}

#[derive(Clone, Eq, Debug, PartialEq)]
struct Frame {
    bindings: BindingMap,
    exception_handlers: Vec<()>,
}

impl Frame {
    pub fn new() -> Frame {
        Frame {
            bindings: Rc::new(RefCell::new(BTreeMap::new())),
            exception_handlers: Vec::new(),
        }
    }

    pub fn local_assign(&mut self, binding_name: &str, value: Value) {
        self.bindings.borrow_mut().insert(binding_name.to_owned(), value);
    }
}

fn compile_statement<'a>(statement: &'a Statement) -> InstructionSequence {
    match statement {
        &Statement::Assign(local, ref binding_name, ref expression) => {
            let mut instructions = compile_expression(expression);
            let instruction = match local {
                true => Instruction::LocalAssign(binding_name.to_owned()),
                false => Instruction::Assign(binding_name.to_owned()),
            };
            instructions.push(instruction);
            instructions
        },
        &Statement::Call(ref binding_name, ref expressions) => {
            let mut instructions = expressions
                .iter()
                .flat_map(|exp| compile_expression(exp))
                .collect::<InstructionSequence>();
            instructions.push(Instruction::Fetch(binding_name.to_owned()));
            instructions.push(Instruction::Call(expressions.len() as u8));
            instructions
        },
        // _ => panic!("not implemented"),
    }
}

fn compile_expression<'a>(expression: &'a Expression) -> InstructionSequence {
    match expression {
        &Expression::Literal(ref literal) => {
            vec![Instruction::Push(literal.to_owned())]
        },
        &Expression::Identifier(ref binding_name) => {
            vec![Instruction::Fetch(binding_name.to_owned())]
        }
        _ => panic!("not implemented"),
        // &Expression::Identifier(_) => { vec![] },
        // &Expression::BinOp(_, _, _) => { vec![] },
    }
}

fn compile<'a>(statements: &'a Vec<Statement>) -> InstructionSequence {
    let mut instructions = InstructionSequence::new();

    for statement in statements.iter() {
        instructions.extend(compile_statement(&statement).iter().cloned());
    }

    instructions
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Vm {
    instructions: Rc<InstructionSequence>,
    pc: usize,
    stack: Vec<Value>,
    frames: Vec<Frame>,
}

impl Vm {
    pub fn new(source: &str) -> Vm {
        let stmts = statements(source);
        // println!("{:?}", stmts);
        let instructions = compile(&stmts.unwrap());
        // println!("{:?}", instructions);
        let mut frame = Frame::new();

        let mut vm = Vm{
            instructions: Rc::new(instructions),
            pc: 0,
            stack: Vec::new(),
            frames: vec![frame],
        };
        vm
    }

    pub fn run<'b, 'c>(&'b mut self) {
        loop {
            let insn_result = Vm::next_instruction(self);
            let instruction;

            match insn_result {
                Some(i) => instruction = i,
                None => break,
            }

            match instruction {
                Instruction::Push(ref value) => {
                    let top_bindings = &mut self.frames.last_mut().unwrap().bindings;
                    self.stack.push(Vm::literal_to_value(value, top_bindings))
                    // Vm::push_value(&mut self.stack, top_activation, value)
                },
                Instruction::LocalAssign(ref binding_name) => {
                    let value = self.stack.pop().unwrap();
                    self.frames.last_mut().unwrap().local_assign(binding_name, value)
                },
                Instruction::Call(arg_size) => {
                    let (closure_arg_size, closure) = match self.stack.pop() {
                        Some(Value::Closure(arg_size, closure)) => (arg_size, closure),
                        _ => panic!("expected a closure"),
                    };
                    // if arg_size != closure_arg_size {
                    //     panic!("wrong number of arguments")
                    // };
                    // make sure closure
                    // verify args
                    // push frame
                    // make new activation
                    // assign values
                    // change iseq
                },
                _ => ()//panic!("unknown instruction {:?}", instruction)
            };
        };
    }

    fn next_instruction(vm: &mut Vm) -> Option<Instruction> {
        let instruction = match vm.instructions.get(vm.pc) {
            Some(i) => Some(i.clone()),
            None => None,
        };

        vm.pc += 1;

        instruction
    }

    fn literal_to_value<'b>(literal: &'b Literal, top_bindings: &BindingMap) -> Value {
        match literal {
            &Literal::Number(ref num) => Value::Number(num.to_owned()),
            &Literal::CharString(ref str) => Value::CharString(str.to_string()),
            &Literal::Fn(ref args, ref statements) => {
                // Statements should be compiled ahead of time
                let closure = Closure::new(compile(&statements), top_bindings);
                Value::Closure(args.len() as u8, closure)
            },
            _ => panic!("not implemented"),
        }
    }
}

#[cfg(test)]
mod test_vm {
    use super::*;
    use ast::*;
    use std::rc::Rc;
    use grammar::test_helpers::*;

    #[test]
    fn test_new_populates_basic_instructions() {
        let vm = Vm::new("let a = 1\nlet b = \"\"\n");
        assert_eq!(
            Rc::new(vec![
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::LocalAssign("a".to_owned()),
                Instruction::Push(Literal::CharString("".to_string())),
                Instruction::LocalAssign("b".to_owned()),
            ]),
            vm.instructions
        )
    }

    fn test_new_populates_function_instructions() {
        let vm = Vm::new("let b = def(x)\nend\nb(1)");
        assert_eq!(
            Rc::new(vec![
                Instruction::Push(Literal::Fn(Box::new(vec!["x".to_owned()]), Box::new(vec![]))),
                Instruction::LocalAssign("b".to_owned()),
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::Fetch("b".to_owned()),
                Instruction::Call(1),
            ]),
            vm.instructions
        )
    }

    #[test]
    fn test_run_simple() {
        let mut vm = Vm::new("let a = 1");
        vm.run();
        assert_eq!(
            Value::Number(build_ratio(1, 1)),
            vm.frames.last().unwrap().bindings.borrow().get("a").unwrap().to_owned()
        );
        ()
    }

    #[test]
    #[ignore]
    fn test_function_call() {
        let source =
            "let a = \"\"\
            let x = def() do
              a = 1
            end\
            x()";

        let mut vm = Vm::new(source);
        vm.run();
        assert_eq!(
            Value::Number(build_ratio(1, 1)),
            vm.frames.last().unwrap().bindings.borrow().get("a").unwrap().to_owned()
        );
        ()
    }

    #[test]
    #[should_panic]
    fn test_calling_non_function() {
        let source =
            "let x = \"\"\
            x()";

        let mut vm = Vm::new(source);
        vm.run();
    }

    #[test]
    #[should_panic]
    fn test_function_with_wrong_arg_count() {
        let source =
            "let x = def(a, b) do
              a = 1
            end\
            x(1, 1)";

        let mut vm = Vm::new(source);
        vm.run();
    }
}
<commit_msg>Call "works"<commit_after>use grammar::*;
use ast::*;
use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;
use num::rational::BigRational;

#[derive(Clone, Eq, Debug, PartialEq)]
pub enum Value {
    Number(BigRational),
    CharString(String),
    Boolean(bool),
    Map(BTreeMap<Rc<Value>, Rc<Value>>),
    Closure(Box<Vec<String>>, Closure),
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub enum Instruction {
    Push(Literal),
    Fetch(String),
    LocalAssign(String),
    Assign(String),
    Call(usize),
    Nop,
    // Set(String, Value),
}

pub type InstructionSequence = Vec<Instruction>;

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct BindingMap {
    map: Rc<RefCell<BTreeMap<String, Value>>>,
    parent: Option<Box<BindingMap>>,
}

impl BindingMap {
    fn new(parent: Option<&BindingMap>) -> BindingMap {
        let parent = match parent {
            Some(map) => Some(Box::new(map.clone())),
            None => None,
        };
        BindingMap {
            map: Rc::new(RefCell::new(BTreeMap::new())),
            parent: parent,
        }
    }

    pub fn fetch(&self, binding_name: &String) -> Option<Value> {
        match self.map.borrow().get(binding_name) {
            Some(value) => Some(value.clone()),
            None => {
                match self.parent {
                    Some(ref parent) => parent.fetch(binding_name),
                    None => None,
                }
            },
        }
    }

    pub fn local_assign(&mut self, binding_name: &String, value: Value) {
        self.map.borrow_mut().insert(binding_name.to_owned(), value);
    }

    pub fn assign(&mut self, binding_name: &String, value: Value) {
        match self.has_binding(binding_name) {
            true => self.local_assign(binding_name, value),
            false => match self.parent {
                Some(ref mut parent) => parent.assign(binding_name, value),
                None => panic!("no such binding"),
            }
        }
    }

    pub fn has_binding(&self, binding_name: &String) -> bool {
        self.map.borrow().contains_key(binding_name)
    }
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Closure {
    instructions: Rc<InstructionSequence>,
    parent_bindings: BindingMap,
}

impl Closure {
    pub fn new(instructions: InstructionSequence, parent_bindings: &BindingMap) -> Closure {
        Closure {
            instructions: Rc::new(instructions),
            parent_bindings: parent_bindings.clone(),
        }
    }
}

#[derive(Clone, Eq, Debug, PartialEq)]
struct Frame {
    bindings: BindingMap,
    exception_handlers: Vec<()>,
}

impl Frame {
    pub fn new(bindings: BindingMap) -> Frame {
        Frame {
            bindings: bindings,
            exception_handlers: Vec::new(),
        }
    }
}

fn compile_statement<'a>(statement: &'a Statement) -> InstructionSequence {
    match statement {
        &Statement::Assign(local, ref binding_name, ref expression) => {
            let mut instructions = compile_expression(expression);
            let instruction = match local {
                true => Instruction::LocalAssign(binding_name.to_owned()),
                false => Instruction::Assign(binding_name.to_owned()),
            };
            instructions.push(instruction);
            instructions
        },
        &Statement::Call(ref binding_name, ref expressions) => {
            let mut instructions = expressions
                .iter()
                .flat_map(|exp| compile_expression(exp))
                .collect::<InstructionSequence>();
            instructions.push(Instruction::Fetch(binding_name.to_owned()));
            instructions.push(Instruction::Call(expressions.len()));
            instructions
        },
        // _ => panic!("not implemented"),
    }
}

fn compile_expression<'a>(expression: &'a Expression) -> InstructionSequence {
    match expression {
        &Expression::Literal(ref literal) => {
            vec![Instruction::Push(literal.to_owned())]
        },
        &Expression::Identifier(ref binding_name) => {
            vec![Instruction::Fetch(binding_name.to_owned())]
        }
        _ => panic!("not implemented"),
        // &Expression::Identifier(_) => { vec![] },
        // &Expression::BinOp(_, _, _) => { vec![] },
    }
}

fn compile<'a>(statements: &'a Vec<Statement>) -> InstructionSequence {
    let mut instructions = InstructionSequence::new();

    for statement in statements.iter() {
        instructions.extend(compile_statement(&statement).iter().cloned());
    }

    instructions
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Vm {
    instructions: Rc<InstructionSequence>,
    pc: usize,
    stack: Vec<Value>,
    frames: Vec<Frame>,
}

impl Vm {
    pub fn new(source: &str) -> Vm {
        let stmts = statements(source);
        let instructions = compile(&stmts.unwrap());
        let mut map = BindingMap::new(None);
        let mut frame = Frame::new(map);

        let mut vm = Vm {
            instructions: Rc::new(instructions),
            pc: 0,
            stack: Vec::new(),
            frames: vec![frame],
        };
        vm
    }

    pub fn run<'b>(&'b mut self) {
        loop {
            let insn_result = Vm::next_instruction(self);
            let instruction;

            match insn_result {
                Some(i) => instruction = i,
                None => break,
            }

            match instruction {
                Instruction::Push(ref value) => {
                    let top_bindings = &mut self.frames.last_mut().unwrap().bindings;
                    self.stack.push(Vm::literal_to_value(value, top_bindings))
                },
                Instruction::Assign(ref binding_name) => {
                    let value = self.stack.pop().unwrap();
                    self.frames.last_mut().unwrap().bindings.assign(binding_name, value)
                },
                Instruction::LocalAssign(ref binding_name) => {
                    let value = self.stack.pop().unwrap();
                    self.frames.last_mut().unwrap().bindings.local_assign(binding_name, value)
                },
                Instruction::Call(arg_size) => {
                    let (closure_args, closure) = match self.stack.pop() {
                        Some(Value::Closure(arg_names, closure)) => (arg_names, closure),
                        Some(x) => panic!("expected a closure, got {:?}", x),
                        None => panic!("expected a closure, got None"),
                    };
                    if arg_size != closure_args.len() {
                        panic!(
                            "wrong number of arguments, expected {:?}, got {:?}",
                            closure_args.len(),
                            arg_size
                        )
                    };
                    let mut map = BindingMap::new(Some(&closure.parent_bindings));
                    for arg_name in closure_args.iter().rev() {
                        map.local_assign(arg_name, self.stack.pop().unwrap());
                    }
                    self.frames.push(Frame::new(map));
                    self.instructions = closure.instructions.clone();
                    self.pc = 0;
                },
                Instruction::Fetch(ref binding_name) => {
                    let value = self.frames.last().unwrap().bindings.fetch(binding_name).unwrap();
                    self.stack.push(value);
                },
                _ => panic!("unknown instruction {:?}", instruction),
            };
        };
    }

    fn next_instruction(vm: &mut Vm) -> Option<Instruction> {
        let instruction = match vm.instructions.get(vm.pc) {
            Some(i) => Some(i.clone()),
            None => None,
        };

        vm.pc += 1;

        instruction
    }

    fn literal_to_value<'b>(literal: &'b Literal, top_bindings: &BindingMap) -> Value {
        match literal {
            &Literal::Number(ref num) => Value::Number(num.to_owned()),
            &Literal::CharString(ref str) => Value::CharString(str.to_string()),
            &Literal::Fn(ref args, ref statements) => {
                // Statements should be compiled ahead of time
                let closure = Closure::new(compile(&statements), top_bindings);
                Value::Closure(args.clone(), closure)
            },
            _ => panic!("not implemented"),
        }
    }
}

#[cfg(test)]
mod test_binding_map {
    use super::*;
    use std::collections::BTreeMap;
    use std::rc::Rc;
    use std::cell::RefCell;

    #[test]
    fn test_new() {
        assert_eq!(
            Rc::new(RefCell::new(BTreeMap::new())),
            BindingMap::new(None).map
        )
    }

    #[test]
    fn test_has_binding() {
        let mut map = BindingMap::new(None);
        assert_eq!(
            false,
            map.has_binding(&"toto".to_owned())
        )
    }

    #[test]
    fn test_local_assign() {
        let mut map = BindingMap::new(None);
        map.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        assert!(map.has_binding(&"toto".to_owned()))
    }

    #[test]
    fn test_fetch() {
        let mut map = BindingMap::new(None);
        map.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        assert_eq!(
            Some(Value::CharString("value".to_owned())),
            map.fetch(&"toto".to_owned())
        )
    }

    #[test]
    fn test_delegates_fetch() {
        let mut parent = BindingMap::new(None);
        parent.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        let map = BindingMap::new(Some(&parent));

        assert_eq!(
            Some(Value::CharString("value".to_owned())),
            map.fetch(&"toto".to_owned())
        )
    }

    #[test]
    fn test_delegates_assign() {
        let mut parent = BindingMap::new(None);
        parent.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        let mut map = BindingMap::new(Some(&parent));
        map.assign(&"toto".to_owned(), Value::CharString("new_value".to_owned()));

        assert_eq!(
            Some(Value::CharString("new_value".to_owned())),
            parent.fetch(&"toto".to_owned())
        )
    }
}

#[cfg(test)]
mod test_vm {
    use super::*;
    use ast::*;
    use std::rc::Rc;
    use grammar::test_helpers::*;

    #[test]
    fn test_new_populates_basic_instructions() {
        let vm = Vm::new("let a = 1\nlet b = \"\"\n");
        assert_eq!(
            Rc::new(vec![
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::LocalAssign("a".to_owned()),
                Instruction::Push(Literal::CharString("".to_string())),
                Instruction::LocalAssign("b".to_owned()),
            ]),
            vm.instructions
        )
    }

    #[test]
    fn test_new_populates_function_instructions() {
        let vm = Vm::new("let b = def(x) do\nend\nb(1)");
        assert_eq!(
            Rc::new(vec![
                Instruction::Push(Literal::Fn(Box::new(vec!["x".to_owned()]), Box::new(vec![]))),
                Instruction::LocalAssign("b".to_owned()),
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::Fetch("b".to_owned()),
                Instruction::Call(1),
            ]),
            vm.instructions
        )
    }

    #[test]
    fn test_run_simple() {
        let mut vm = Vm::new("let a = 1");
        vm.run();
        assert_eq!(
            Value::Number(build_ratio(1, 1)),
            vm.frames.last().unwrap().bindings.fetch(&"a".to_owned()).unwrap().to_owned()
        )
    }

    #[test]
    fn test_function_call() {
        let source =
        "let a = \"\"\
            let x = def() do
              a = 1
            end\
            x()";

        let mut vm = Vm::new(source);
        vm.run();
        assert_eq!(
        Value::Number(build_ratio(1, 1)),
        vm.frames.last().unwrap().bindings.fetch(&"a".to_owned()).unwrap().to_owned()
        )
    }

    #[test]
    fn test_function_call_with_args() {
        let source =
            "\
            let a = \"\"\
            let b = \"\"\
            let x = def(c, d) do
              a = c
              b = d
            end\
            x(1, 2)";

        let mut vm = Vm::new(source);
        vm.run();
        assert_eq!(
            Value::Number(build_ratio(1, 1)),
            vm.frames.last().unwrap().bindings.fetch(&"a".to_owned()).unwrap().to_owned()
        );
        assert_eq!(
            Value::Number(build_ratio(2, 1)),
            vm.frames.last().unwrap().bindings.fetch(&"b".to_owned()).unwrap().to_owned()
        )
    }

    #[test]
    #[should_panic(expected="expected a closure")]
    fn test_calling_non_function() {
        let source =
            "let x = \"\"\
            x()";

        let mut vm = Vm::new(source);
        vm.run();
    }

    #[test]
    #[should_panic(expected="wrong number of arguments")]
    fn test_function_with_wrong_arg_count() {
        let source =
            "let x = def(a, b) do
            end\
            x(1)";

        let mut vm = Vm::new(source);
        vm.run();
    }
}
<|endoftext|>


<commit_before>use clap::ArgMatches;
use std::env;
use std::error::Error;
use std::fs;
use std::io::Read;
use std::path::PathBuf;
use toml;

use super::find_project_root;
use print_schema;

#[derive(Deserialize, Default)]
#[serde(deny_unknown_fields)]
pub struct Config {
    #[serde(default)]
    pub print_schema: PrintSchema,
}

impl Config {
    pub fn file_path(matches: &ArgMatches) -> PathBuf {
        matches
            .value_of("CONFIG_FILE")
            .map(PathBuf::from)
            .or_else(|| env::var_os("DIESEL_CONFIG_FILE").map(PathBuf::from))
            .unwrap_or_else(|| find_project_root().unwrap_or_default().join("diesel.toml"))
    }

    pub fn read(matches: &ArgMatches) -> Result<Self, Box<Error>> {
        let path = Self::file_path(matches);

        if path.exists() {
            let mut bytes = Vec::new();
            fs::File::open(path)?.read_to_end(&mut bytes)?;
            toml::from_slice(&bytes).map_err(Into::into)
        } else {
            Ok(Self::default())
        }
    }
}

#[derive(Default, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PrintSchema {
    #[serde(default)]
    pub file: Option<PathBuf>,
    #[serde(default)]
    pub with_docs: bool,
    #[serde(default)]
    pub filter: print_schema::Filtering,
    #[serde(default)]
    pub schema: Option<String>,
    #[serde(default)]
    pub patch_file: Option<PathBuf>,
    #[serde(default)]
    pub import_types: Option<Vec<String>>,
}

impl PrintSchema {
    pub fn schema_name(&self) -> Option<&str> {
        self.schema.as_ref().map(|s| &**s)
    }

    pub fn import_types(&self) -> Option<&[String]> {
        self.import_types.as_ref().map(|v| &**v)
    }
}
<commit_msg>Fix failing build<commit_after>// FIXME: https://github.com/rust-lang-nursery/rust-clippy/issues/2910
#![cfg_attr(feature = "clippy", allow(useless_attribute))]

use clap::ArgMatches;
use std::env;
use std::error::Error;
use std::fs;
use std::io::Read;
use std::path::PathBuf;
use toml;

use super::find_project_root;
use print_schema;

#[derive(Deserialize, Default)]
#[serde(deny_unknown_fields)]
pub struct Config {
    #[serde(default)]
    pub print_schema: PrintSchema,
}

impl Config {
    pub fn file_path(matches: &ArgMatches) -> PathBuf {
        matches
            .value_of("CONFIG_FILE")
            .map(PathBuf::from)
            .or_else(|| env::var_os("DIESEL_CONFIG_FILE").map(PathBuf::from))
            .unwrap_or_else(|| find_project_root().unwrap_or_default().join("diesel.toml"))
    }

    pub fn read(matches: &ArgMatches) -> Result<Self, Box<Error>> {
        let path = Self::file_path(matches);

        if path.exists() {
            let mut bytes = Vec::new();
            fs::File::open(path)?.read_to_end(&mut bytes)?;
            toml::from_slice(&bytes).map_err(Into::into)
        } else {
            Ok(Self::default())
        }
    }
}

#[derive(Default, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PrintSchema {
    #[serde(default)]
    pub file: Option<PathBuf>,
    #[serde(default)]
    pub with_docs: bool,
    #[serde(default)]
    pub filter: print_schema::Filtering,
    #[serde(default)]
    pub schema: Option<String>,
    #[serde(default)]
    pub patch_file: Option<PathBuf>,
    #[serde(default)]
    pub import_types: Option<Vec<String>>,
}

impl PrintSchema {
    pub fn schema_name(&self) -> Option<&str> {
        self.schema.as_ref().map(|s| &**s)
    }

    pub fn import_types(&self) -> Option<&[String]> {
        self.import_types.as_ref().map(|v| &**v)
    }
}
<|endoftext|>


<commit_before>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{self, Command};

use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-hermit-kernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	#[cfg(feature = "instrument")]
	cmd.env("RUSTFLAGS", "-Z instrument-mcount");
	// if instrument is not set, ensure that instrument is not in environment variables!
	#[cfg(not(feature = "instrument"))]
	cmd.env(
		"RUSTFLAGS",
		env::var("RUSTFLAGS")
			.unwrap_or_else(|_| "".into())
			.replace("-Z instrument-mcount", ""),
	);

	let output = cmd.output().expect("Unable to build kernel");
	let stdout = std::string::String::from_utf8(output.stdout);
	let stderr = std::string::String::from_utf8(output.stderr);

	println!("Build libhermit-rs output-status: {}", output.status);
	println!("Build libhermit-rs output-stdout: {}", stdout.unwrap());
	println!("Build libhermit-rs output-stderr: {}", stderr.unwrap());
	assert!(output.status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-hermit-kernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	if profile == "debug" {
		// get access to llvm tools shipped in the llvm-tools-preview rustup component
		let llvm_tools = match llvm_tools::LlvmTools::new() {
			Ok(tools) => tools,
			Err(llvm_tools::Error::NotFound) => {
				eprintln!("Error: llvm-tools not found");
				eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
				eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
				process::exit(1);
			}
			Err(err) => {
				eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
				process::exit(1);
			}
		};

		let lib = lib_location.join("libhermit.a");

		// determine llvm_objcopy
		let llvm_objcopy = llvm_tools
			.tool(&llvm_tools::exe("llvm-objcopy"))
			.expect("llvm_objcopy not found in llvm-tools");

		// rename symbols
		let mut cmd = Command::new(llvm_objcopy);
		cmd.arg("--redefine-sym")
			.arg("memcpy=kernel_memcpy")
			.arg("--redefine-sym")
			.arg("memmove=kernel_memmove")
			.arg("--redefine-sym")
			.arg("memset=kernel_memset")
			.arg("--redefine-sym")
			.arg("memcmp=kernel_memcmp")
			.arg("--redefine-sym")
			.arg("bcmp=kernel_bcmp")
			.arg(lib.display().to_string());

		println!("cmd {:?}", cmd);
		let output = cmd.output().expect("Unable to rename symbols");
		let stdout = std::string::String::from_utf8(output.stdout);
		let stderr = std::string::String::from_utf8(output.stderr);
		println!("Rename symbols output-status: {}", output.status);
		println!("Rename symbols output-stdout: {}", stdout.unwrap());
		println!("Rename symbols output-stderr: {}", stderr.unwrap());
		assert!(output.status.success());
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	let _output = Command::new("cargo")
		.current_dir(out_dir)
		.arg("download")
		.arg("--output")
		.arg(src_dir.clone().into_os_string())
		.arg("--extract")
		.arg("rusty-hermit")
		.output()
		.expect("Unable to download rusty-hermit. Please install `cargo-download`.");

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.clone().join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<commit_msg>add comment to explain the technique to avoid collisions<commit_after>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{self, Command};

use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-hermit-kernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	#[cfg(feature = "instrument")]
	cmd.env("RUSTFLAGS", "-Z instrument-mcount");
	// if instrument is not set, ensure that instrument is not in environment variables!
	#[cfg(not(feature = "instrument"))]
	cmd.env(
		"RUSTFLAGS",
		env::var("RUSTFLAGS")
			.unwrap_or_else(|_| "".into())
			.replace("-Z instrument-mcount", ""),
	);

	let output = cmd.output().expect("Unable to build kernel");
	let stdout = std::string::String::from_utf8(output.stdout);
	let stderr = std::string::String::from_utf8(output.stderr);

	println!("Build libhermit-rs output-status: {}", output.status);
	println!("Build libhermit-rs output-stdout: {}", stdout.unwrap());
	println!("Build libhermit-rs output-stderr: {}", stderr.unwrap());
	assert!(output.status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-hermit-kernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	// in case of a debug version of the library, we have to avoid a symbol collision.
	// Kernel and user space has its own versions of memcpy, memset, etc,
	// Consequently, we rename the functions in the libos to avoid collisions.
	// In addition, it provides us the offer to create a optimized version of memcpy
	// in user space.
	if profile == "debug" {
		// get access to llvm tools shipped in the llvm-tools-preview rustup component
		let llvm_tools = match llvm_tools::LlvmTools::new() {
			Ok(tools) => tools,
			Err(llvm_tools::Error::NotFound) => {
				eprintln!("Error: llvm-tools not found");
				eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
				eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
				process::exit(1);
			}
			Err(err) => {
				eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
				process::exit(1);
			}
		};

		let lib = lib_location.join("libhermit.a");

		// determine llvm_objcopy
		let llvm_objcopy = llvm_tools
			.tool(&llvm_tools::exe("llvm-objcopy"))
			.expect("llvm_objcopy not found in llvm-tools");

		// rename symbols
		let mut cmd = Command::new(llvm_objcopy);
		cmd.arg("--redefine-sym")
			.arg("memcpy=kernel_memcpy")
			.arg("--redefine-sym")
			.arg("memmove=kernel_memmove")
			.arg("--redefine-sym")
			.arg("memset=kernel_memset")
			.arg("--redefine-sym")
			.arg("memcmp=kernel_memcmp")
			.arg("--redefine-sym")
			.arg("bcmp=kernel_bcmp")
			.arg(lib.display().to_string());

		println!("cmd {:?}", cmd);
		let output = cmd.output().expect("Unable to rename symbols");
		let stdout = std::string::String::from_utf8(output.stdout);
		let stderr = std::string::String::from_utf8(output.stderr);
		println!("Rename symbols output-status: {}", output.status);
		println!("Rename symbols output-stdout: {}", stdout.unwrap());
		println!("Rename symbols output-stderr: {}", stderr.unwrap());
		assert!(output.status.success());
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	let _output = Command::new("cargo")
		.current_dir(out_dir)
		.arg("download")
		.arg("--output")
		.arg(src_dir.clone().into_os_string())
		.arg("--extract")
		.arg("rusty-hermit")
		.output()
		.expect("Unable to download rusty-hermit. Please install `cargo-download`.");

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.clone().join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<|endoftext|>


<commit_before>use std::env;

use dotenv::dotenv;
use diesel;
use diesel::prelude::*;
use diesel::pg::PgConnection;

use super::models::*;
use ::services::schema;

pub struct Backend {
    connection: PgConnection
}

impl Backend {
    pub fn new() -> Self {
        dotenv().ok();

        let database_url = env::var("DATABASE_URL")
            .expect("DATABASE_URL must be set");
        let connection = PgConnection::establish(&database_url)
            .expect(&format!("Error connecting to {}", database_url));

        Self {
            connection
        }
    }

    pub fn vote(&self, user: &str, entity: &str, up: i32, down: i32) {
        use self::schema::{users, voteables, votes};

        let entity = &entity.to_lowercase();

        use self::schema::users::dsl as us;
        let mut res: Vec<User> = us::users.filter(us::user_id.eq(user))
                                          .load(&self.connection).unwrap();
        let user = match res.len() {
            0 => {
                let new_user = NewUser { user_id: user };
                diesel::insert(&new_user).into(users::table)
                    .get_result(&self.connection)
                    .expect("Error creating new user")
            },
            _ => res.pop().unwrap(),
        };

        use self::schema::voteables::dsl::*;
        let mut res: Vec<Voteable> = voteables.filter(value.eq(entity))
                                              .load(&self.connection).unwrap();
        let mut voteable= match res.len() {
            0 => {
                let new_voteable = NewVoteable {
                    value: entity,
                    total_up: 0,
                    total_down: 0,
                };

                diesel::insert(&new_voteable).into(voteables::table)
                    .get_result(&self.connection)
                    .expect("Error creating new voteable")
            },

            _ => res.pop().unwrap(),
        };

        voteable.total_up += up;
        voteable.total_down += down;
        voteable.save_changes::<Voteable>(&self.connection);

        use ::services::schema::votes::dsl as vts;
        let mut res: Vec<Vote> = vts::votes.filter(vts::user_id.eq(user.id))
                                           .filter(vts::voteable_id.eq(voteable.id))
                                           .load(&self.connection).unwrap();
        let mut vote = match res.len() {
            0 => {
                let new_vote = NewVote{
                    user_id: user.id,
                    voteable_id: voteable.id,
                    up: 0,
                    down: 0,
                };

                diesel::insert(&new_vote).into(votes::table)
                    .get_result(&self.connection)
                    .expect("Error creating new vote")
            },
            _ => res.pop().unwrap(),
        };

        vote.up += up;
        vote.down += down;
        vote.save_changes::<Vote>(&self.connection);
    }

    pub fn get_upvotes(&self, entity: &str) -> Option<Voteable> {
        use self::schema::voteables::dsl::*;

        let entity = &entity.to_lowercase();

        let mut res = voteables.filter(value.eq(entity))
                               .load(&self.connection).unwrap();
        match res.len() {
            0 => None,
            _ => Some(res.pop().unwrap()),
        }
    }
}
<commit_msg>Fix crash when trying to karma things w/long names<commit_after>use std::env;

use dotenv::dotenv;
use diesel;
use diesel::prelude::*;
use diesel::pg::PgConnection;

use super::models::*;
use ::services::schema;

pub struct Backend {
    connection: PgConnection
}

impl Backend {
    pub fn new() -> Self {
        dotenv().ok();

        let database_url = env::var("DATABASE_URL")
            .expect("DATABASE_URL must be set");
        let connection = PgConnection::establish(&database_url)
            .expect(&format!("Error connecting to {}", database_url));

        Self {
            connection
        }
    }

    pub fn vote(&self, user: &str, entity: &str, up: i32, down: i32) {
        use self::schema::{users, voteables, votes};

        let entity = &entity.to_lowercase();

        use self::schema::users::dsl as us;
        let mut res: Vec<User> = us::users.filter(us::user_id.eq(user))
                                          .load(&self.connection).unwrap();
        let user = match res.len() {
            0 => {
                let new_user = NewUser { user_id: user };
                diesel::insert(&new_user).into(users::table)
                    .get_result(&self.connection)
                    .expect("Error creating new user")
            },
            _ => res.pop().unwrap(),
        };

        use self::schema::voteables::dsl::*;
        let mut res: Vec<Voteable> = voteables.filter(value.eq(entity))
                                              .load(&self.connection).unwrap();
        let mut voteable = match res.len() {
            0 => {
                let new_voteable = NewVoteable {
                    value: entity,
                    total_up: 0,
                    total_down: 0,
                };

                let res = diesel::insert(&new_voteable)
                                  .into(voteables::table)
                                  .get_result(&self.connection);

                if let Err(e) = res{
                    return;
                }

                res.unwrap()
            },

            _ => res.pop().unwrap(),
        };

        voteable.total_up += up;
        voteable.total_down += down;
        voteable.save_changes::<Voteable>(&self.connection);

        use ::services::schema::votes::dsl as vts;
        let mut res: Vec<Vote> = vts::votes.filter(vts::user_id.eq(user.id))
                                           .filter(vts::voteable_id.eq(voteable.id))
                                           .load(&self.connection).unwrap();
        let mut vote = match res.len() {
            0 => {
                let new_vote = NewVote{
                    user_id: user.id,
                    voteable_id: voteable.id,
                    up: 0,
                    down: 0,
                };

                diesel::insert(&new_vote).into(votes::table)
                    .get_result(&self.connection)
                    .expect("Error creating new vote")
            },
            _ => res.pop().unwrap(),
        };

        vote.up += up;
        vote.down += down;
        vote.save_changes::<Vote>(&self.connection);
    }

    pub fn get_upvotes(&self, entity: &str) -> Option<Voteable> {
        use self::schema::voteables::dsl::*;

        let entity = &entity.to_lowercase();

        let mut res = voteables.filter(value.eq(entity))
                               .load(&self.connection).unwrap();
        match res.len() {
            0 => None,
            _ => Some(res.pop().unwrap()),
        }
    }
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014, 2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library 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 2.1 of the License, or (at your option) any later version.
//
// This library 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 library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use refcount::{Refcount, Ref};
use types::{FALSE, TRUE};
use types::{gboolean, gint, gpointer, guint};
use util::{box_free, box_from_pointer, box_into_pointer, into_destroy_notify};
use wrap;
use wrap::Wrapper;

use glib as ffi;
use gobject;
use std::convert;
use std::marker;
use std::mem;

pub const PRIORITY_DEFAULT      : gint = ffi::G_PRIORITY_DEFAULT;
pub const PRIORITY_DEFAULT_IDLE : gint = ffi::G_PRIORITY_DEFAULT_IDLE;
pub const PRIORITY_HIGH         : gint = ffi::G_PRIORITY_HIGH;
pub const PRIORITY_HIGH_IDLE    : gint = ffi::G_PRIORITY_HIGH_IDLE;
pub const PRIORITY_LOW          : gint = ffi::G_PRIORITY_LOW;

pub enum CallbackResult { Remove, Continue }
pub use self::CallbackResult::*;

pub struct RawCallback {
    func: ffi::GSourceFunc,
    data: gpointer,
    destroy: ffi::GDestroyNotify
}

impl Drop for RawCallback {
    fn drop(&mut self) {
        (self.destroy)(self.data);
    }
}

unsafe fn into_source_func(func: unsafe extern "C" fn(gpointer) -> gboolean)
                          -> ffi::GSourceFunc
{
    mem::transmute(func)
}

unsafe extern "C" fn source_func<F>(callback_data: gpointer) -> gboolean
    where F: FnMut() -> CallbackResult
{
    let mut callback: Box<F> = box_from_pointer(callback_data);
    let res = callback();
    mem::forget(callback);
    match res {
        Remove => FALSE,
        Continue => TRUE
    }
}

unsafe extern "C" fn source_once_func<F>(callback_data: gpointer) -> gboolean
    where F: FnOnce()
{
    let mut holder: Box<Option<F>> = box_from_pointer(callback_data);
    let callback = holder.take().expect("a callback closure expected");
    mem::forget(holder);
    callback();
    FALSE
}

pub struct SourceCallback(RawCallback);

impl Into<RawCallback> for SourceCallback {
    #[inline]
    fn into(self) -> RawCallback {
        self.0
    }
}

impl SourceCallback {
    pub fn new<F>(closure: F) -> Self
        where F: Send + 'static, F: FnMut() -> CallbackResult
    {
        let boxed_closure = Box::new(closure);
        SourceCallback(unsafe {
            RawCallback {
                func: into_source_func(source_func::<F>),
                data: box_into_pointer(boxed_closure),
                destroy: into_destroy_notify(box_free::<F>)
            }
        })
    }

    pub fn once<F>(closure: F) -> Self
        where F: Send + 'static, F: FnOnce()
    {
        let holder = Box::new(Some(closure));
        SourceCallback(unsafe {
            RawCallback {
                func: into_source_func(source_once_func::<F>),
                data: box_into_pointer(holder),
                destroy: into_destroy_notify(box_free::<Option<F>>)
            }
        })
    }
}

#[repr(C)]
pub struct MainContext {
    raw: ffi::GMainContext
}

unsafe impl Send for MainContext { }
unsafe impl Sync for MainContext { }
unsafe impl Wrapper for MainContext {
    type Raw = ffi::GMainContext;
}

impl MainContext {
    pub fn default() -> &'static MainContext {
        unsafe {
            wrap::from_raw(ffi::g_main_context_default())
        }
    }

    pub fn invoke(&self, callback: SourceCallback) {
        self.invoke_full(PRIORITY_DEFAULT, callback)
    }

    pub fn invoke_full(&self, priority: gint, callback: SourceCallback) {
        let raw: RawCallback = callback.into();
        unsafe {
            ffi::g_main_context_invoke_full(self.as_mut_ptr(),
                    priority, raw.func, raw.data, Some(raw.destroy));
        }
        mem::forget(raw);
    }
}

impl Refcount for MainContext {

    unsafe fn inc_ref(&self) {
        ffi::g_main_context_ref(self.as_mut_ptr());
    }

    unsafe fn dec_ref(&self) {
        ffi::g_main_context_unref(self.as_mut_ptr());
    }
}

g_impl_boxed_type_for_ref!(MainContext, gobject::g_main_context_get_type);

#[repr(C)]
pub struct MainLoop {
    raw: ffi::GMainLoop
}

unsafe impl Send for MainLoop { }
unsafe impl Sync for MainLoop { }
unsafe impl Wrapper for MainLoop {
    type Raw = ffi::GMainLoop;
}

pub struct LoopRunner {
    mainloop: *mut ffi::GMainLoop,
}

impl LoopRunner {
    pub fn new() -> LoopRunner {
        unsafe {
            let ctx = ffi::g_main_context_new();
            let mainloop = ffi::g_main_loop_new(ctx, FALSE);
            ffi::g_main_context_unref(ctx);

            LoopRunner { mainloop: mainloop }
        }
    }

    pub fn run_after<F>(&self, setup: F) where F: FnOnce(Ref<MainLoop>) {
        unsafe {
            let ctx = ffi::g_main_loop_get_context(self.mainloop);
            ffi::g_main_context_push_thread_default(ctx);

            setup(Ref::new(wrap::from_raw(self.mainloop)));

            ffi::g_main_loop_run(self.mainloop);

            ffi::g_main_context_pop_thread_default(ctx);
        }
    }
}

impl Drop for LoopRunner {
    fn drop(&mut self) {
        unsafe {
            ffi::g_main_loop_unref(self.mainloop);
        }
    }
}

impl MainLoop {

    pub fn get_context(&self) -> &MainContext {
        unsafe {
            let ctx = ffi::g_main_loop_get_context(self.as_mut_ptr());
            wrap::from_raw(ctx)
        }
    }

    pub fn quit(&self) {
        unsafe {
            ffi::g_main_loop_quit(self.as_mut_ptr());
        }
    }
}

impl Refcount for MainLoop {

    unsafe fn inc_ref(&self) {
        ffi::g_main_loop_ref(self.as_mut_ptr());
    }

    unsafe fn dec_ref(&self) {
        ffi::g_main_loop_unref(self.as_mut_ptr());
    }
}

g_impl_boxed_type_for_ref!(MainLoop, gobject::g_main_loop_get_type);
<commit_msg>mainloop: support for GSource<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014, 2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library 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 2.1 of the License, or (at your option) any later version.
//
// This library 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 library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use refcount::{Refcount, Ref};
use types::{FALSE, TRUE};
use types::{gboolean, gint, gpointer, guint};
use util::{box_free, box_from_pointer, box_into_pointer, into_destroy_notify};
use wrap;
use wrap::Wrapper;

use glib as ffi;
use gobject;
use std::convert;
use std::marker;
use std::mem;

pub const PRIORITY_DEFAULT      : gint = ffi::G_PRIORITY_DEFAULT;
pub const PRIORITY_DEFAULT_IDLE : gint = ffi::G_PRIORITY_DEFAULT_IDLE;
pub const PRIORITY_HIGH         : gint = ffi::G_PRIORITY_HIGH;
pub const PRIORITY_HIGH_IDLE    : gint = ffi::G_PRIORITY_HIGH_IDLE;
pub const PRIORITY_LOW          : gint = ffi::G_PRIORITY_LOW;

pub enum CallbackResult { Remove, Continue }
pub use self::CallbackResult::*;

pub struct RawCallback {
    func: ffi::GSourceFunc,
    data: gpointer,
    destroy: ffi::GDestroyNotify
}

impl Drop for RawCallback {
    fn drop(&mut self) {
        (self.destroy)(self.data);
    }
}

unsafe fn into_source_func(func: unsafe extern "C" fn(gpointer) -> gboolean)
                          -> ffi::GSourceFunc
{
    mem::transmute(func)
}

unsafe extern "C" fn source_func<F>(callback_data: gpointer) -> gboolean
    where F: FnMut() -> CallbackResult
{
    let mut callback: Box<F> = box_from_pointer(callback_data);
    let res = callback();
    mem::forget(callback);
    match res {
        Remove => FALSE,
        Continue => TRUE
    }
}

unsafe extern "C" fn source_once_func<F>(callback_data: gpointer) -> gboolean
    where F: FnOnce()
{
    let mut holder: Box<Option<F>> = box_from_pointer(callback_data);
    let callback = holder.take().expect("a callback closure expected");
    mem::forget(holder);
    callback();
    FALSE
}

pub struct SourceCallback(RawCallback);

impl Into<RawCallback> for SourceCallback {
    #[inline]
    fn into(self) -> RawCallback {
        self.0
    }
}

impl SourceCallback {
    pub fn new<F>(closure: F) -> Self
        where F: Send + 'static, F: FnMut() -> CallbackResult
    {
        let boxed_closure = Box::new(closure);
        SourceCallback(unsafe {
            RawCallback {
                func: into_source_func(source_func::<F>),
                data: box_into_pointer(boxed_closure),
                destroy: into_destroy_notify(box_free::<F>)
            }
        })
    }

    pub fn once<F>(closure: F) -> Self
        where F: Send + 'static, F: FnOnce()
    {
        let holder = Box::new(Some(closure));
        SourceCallback(unsafe {
            RawCallback {
                func: into_source_func(source_once_func::<F>),
                data: box_into_pointer(holder),
                destroy: into_destroy_notify(box_free::<Option<F>>)
            }
        })
    }
}

#[repr(C)]
pub struct MainContext {
    raw: ffi::GMainContext
}

unsafe impl Send for MainContext { }
unsafe impl Sync for MainContext { }
unsafe impl Wrapper for MainContext {
    type Raw = ffi::GMainContext;
}

impl MainContext {
    pub fn default() -> &'static MainContext {
        unsafe {
            wrap::from_raw(ffi::g_main_context_default())
        }
    }

    pub fn invoke(&self, callback: SourceCallback) {
        self.invoke_full(PRIORITY_DEFAULT, callback)
    }

    pub fn invoke_full(&self, priority: gint, callback: SourceCallback) {
        let raw: RawCallback = callback.into();
        unsafe {
            ffi::g_main_context_invoke_full(self.as_mut_ptr(),
                    priority, raw.func, raw.data, Some(raw.destroy));
        }
        mem::forget(raw);
    }
}

impl Refcount for MainContext {

    unsafe fn inc_ref(&self) {
        ffi::g_main_context_ref(self.as_mut_ptr());
    }

    unsafe fn dec_ref(&self) {
        ffi::g_main_context_unref(self.as_mut_ptr());
    }
}

g_impl_boxed_type_for_ref!(MainContext, gobject::g_main_context_get_type);

#[repr(C)]
pub struct Source<Callback = SourceCallback> {
    raw: ffi::GSource,
    phantom_data: marker::PhantomData<Callback>
}

#[repr(C)]
pub struct AttachedSource<Callback> {
    raw: ffi::GSource,
    phantom_data: marker::PhantomData<Callback>
}

unsafe impl<C> Send for Source<C> where C: Into<RawCallback> { }

unsafe impl<C> Send for AttachedSource<C> where C: Into<RawCallback> { }
unsafe impl<C> Sync for AttachedSource<C> where C: Into<RawCallback> { }

macro_rules! common_source_impls {
    ($name:ident) => {
        unsafe impl<C> Wrapper for $name<C> {
            type Raw = ffi::GSource;
        }

        impl<C> Refcount for $name<C> {
            unsafe fn inc_ref(&self) {
                ffi::g_source_ref(self.as_mut_ptr());
            }
            unsafe fn dec_ref(&self) {
                ffi::g_source_unref(self.as_mut_ptr());
            }
        }
    }
}

common_source_impls!(Source);
common_source_impls!(AttachedSource);

impl<C> Source<C> where C: Into<RawCallback> {
    pub fn set_callback(&self, callback: C)
    {
        let raw: RawCallback = callback.into();
        unsafe {
            ffi::g_source_set_callback(self.as_mut_ptr(),
                    raw.func, raw.data, Some(raw.destroy));
        }
        mem::forget(raw);
    }

    pub fn set_priority(&self, priority: gint) {
        unsafe {
            ffi::g_source_set_priority(self.as_mut_ptr(), priority);
        }
    }
}

impl<C> Ref<Source<C>> {
    pub fn attach(self, ctx: &MainContext) -> Ref<AttachedSource<C>> {
        unsafe {
            let source_ptr = self.as_mut_ptr();
            ffi::g_source_attach(source_ptr, ctx.as_mut_ptr());
            mem::forget(self);
            Ref::from_raw(source_ptr)
        }
    }
}

impl<C> AttachedSource<C> {
    #[inline]
    pub fn as_source(&self) -> &Source<C> {
        unsafe { wrap::from_raw(self.as_ptr()) }
    }

    pub fn destroy(&self) {
        unsafe { ffi::g_source_destroy(self.as_mut_ptr()) }
    }
}

impl<C> convert::AsRef<Source<C>> for AttachedSource<C> {
    #[inline]
    fn as_ref(&self) -> &Source<C> {
        self.as_source()
    }
}

pub fn idle_source_new() -> Ref<Source> {
    unsafe {
        let source = ffi::g_idle_source_new();
        Ref::from_raw(source)
    }
}

pub fn timeout_source_new(interval: guint) -> Ref<Source> {
    unsafe {
        let source = ffi::g_timeout_source_new(interval);
        Ref::from_raw(source)
    }
}

pub fn timeout_source_new_seconds(interval: guint) -> Ref<Source> {
    unsafe {
        let source = ffi::g_timeout_source_new_seconds(interval);
        Ref::from_raw(source)
    }
}

#[repr(C)]
pub struct MainLoop {
    raw: ffi::GMainLoop
}

unsafe impl Send for MainLoop { }
unsafe impl Sync for MainLoop { }
unsafe impl Wrapper for MainLoop {
    type Raw = ffi::GMainLoop;
}

pub struct LoopRunner {
    mainloop: *mut ffi::GMainLoop,
}

impl LoopRunner {
    pub fn new() -> LoopRunner {
        unsafe {
            let ctx = ffi::g_main_context_new();
            let mainloop = ffi::g_main_loop_new(ctx, FALSE);
            ffi::g_main_context_unref(ctx);

            LoopRunner { mainloop: mainloop }
        }
    }

    pub fn run_after<F>(&self, setup: F) where F: FnOnce(Ref<MainLoop>) {
        unsafe {
            let ctx = ffi::g_main_loop_get_context(self.mainloop);
            ffi::g_main_context_push_thread_default(ctx);

            setup(Ref::new(wrap::from_raw(self.mainloop)));

            ffi::g_main_loop_run(self.mainloop);

            ffi::g_main_context_pop_thread_default(ctx);
        }
    }
}

impl Drop for LoopRunner {
    fn drop(&mut self) {
        unsafe {
            ffi::g_main_loop_unref(self.mainloop);
        }
    }
}

impl MainLoop {

    pub fn get_context(&self) -> &MainContext {
        unsafe {
            let ctx = ffi::g_main_loop_get_context(self.as_mut_ptr());
            wrap::from_raw(ctx)
        }
    }

    pub fn quit(&self) {
        unsafe {
            ffi::g_main_loop_quit(self.as_mut_ptr());
        }
    }
}

impl Refcount for MainLoop {

    unsafe fn inc_ref(&self) {
        ffi::g_main_loop_ref(self.as_mut_ptr());
    }

    unsafe fn dec_ref(&self) {
        ffi::g_main_loop_unref(self.as_mut_ptr());
    }
}

g_impl_boxed_type_for_ref!(MainLoop, gobject::g_main_loop_get_type);
<|endoftext|>


<commit_before>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use num::PrimInt;

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[derive(Clone)]
#[repr(C, packed)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[repr(C, packed)]
#[derive(Copy, Clone)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl PartialEq for HwAddr {
    fn eq(&self, rhs: &Self) -> bool {
        self.bytes[0] == rhs.bytes[0] &&
        self.bytes[1] == rhs.bytes[1] &&
        self.bytes[2] == rhs.bytes[2] &&
        self.bytes[3] == rhs.bytes[3] &&
        self.bytes[4] == rhs.bytes[4] &&
        self.bytes[5] == rhs.bytes[5]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<commit_msg>net/defs: Add type Ipv4Addr<commit_after>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use num::PrimInt;

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[derive(Clone)]
#[repr(C, packed)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[repr(C, packed)]
#[derive(Copy, Clone, PartialEq)]
/// An Ipv4 address
pub struct Ipv4Addr {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
}

impl Ipv4Addr {
    /// Creates a new IPv4 address
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`
    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Ipv4Addr {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }

}

impl Display for Ipv4Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}.{}.{}.{}", self.a, self.b, self.c,
                                 self.d))
    }
}

#[repr(C, packed)]
#[derive(Copy, Clone)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl PartialEq for HwAddr {
    fn eq(&self, rhs: &Self) -> bool {
        self.bytes[0] == rhs.bytes[0] &&
        self.bytes[1] == rhs.bytes[1] &&
        self.bytes[2] == rhs.bytes[2] &&
        self.bytes[3] == rhs.bytes[3] &&
        self.bytes[4] == rhs.bytes[4] &&
        self.bytes[5] == rhs.bytes[5]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<|endoftext|>