<commit_before>/// Figure 8.5: Print a description of the exit status, and
/// Figure 8.6: Demonstrate various exit statuses
///
/// Takeaway: Rust intercepts the division by zero with its panic handler.
/// To make the exception "fall through" we need to replace rusts panic handler
/// by our own (at least that's what the guys on IRC suggested). Sadly in order to
/// go sure that it was *really* a division by zero we need to do a string comparison..
///
/// $ f06-exit-status
/// normal termination, exit status = 7
/// abnormal termination, signal number = 6
/// abnormal termination, signal number = 8

extern crate libc;
extern crate apue;

use libc::{c_int, SIGFPE};
use libc::{exit, wait, fork, abort, raise};
use apue::{LibcResult, err_sys, pr_exit};
use std::panic;

fn handle_panic(e: &panic::PanicInfo) {
    match e.payload().downcast_ref::<String>() {
        Some(as_string) if as_string == "attempt to divide by zero" => {
            unsafe { raise(SIGFPE) };
        }
        _ => {
            panic!("unknown error occurred");
        }
    }
}

fn main() {
    panic::set_hook(Box::new(handle_panic));
    unsafe {
        let mut status: c_int = 0;
        let mut pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            exit(7);
        }
        if wait(&mut status) != pid {
            // wait for child
            err_sys("wait error");
        }
        pr_exit(status);

        pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            abort(); // generate SIGABRT
        }
        if wait(&mut status) != pid {
            // wait for child
            err_sys("wait error");
        }
        pr_exit(status);

        pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            let z = 0;
            status /= z; // divide by 0 generates SIGFPE
        }

        if wait(&mut status) != pid {
            err_sys("wait error");
        }
        pr_exit(status);
    }
}
<commit_msg>fix f06-exit-status for linux<commit_after>/// Figure 8.5: Print a description of the exit status, and
/// Figure 8.6: Demonstrate various exit statuses
///
/// Takeaway: Rust intercepts the division by zero with its panic handler.
/// To make the exception "fall through" we need to replace rusts panic handler
/// by our own (at least that's what the guys on IRC suggested). Sadly in order to
/// go sure that it was *really* a division by zero we need to do a string comparison..
///
/// mac only:
/// $ f06-exit-status
/// normal termination, exit status = 7
/// abnormal termination, signal number = 6
/// abnormal termination, signal number = 8
///
/// linux only:
/// $ f06-exit-status
/// normal termination, exit status = 7
/// abnormal termination, signal number = 6  (core file generated)
/// abnormal termination, signal number = 8  (core file generated)

extern crate libc;
extern crate apue;

use libc::{c_int, SIGFPE};
use libc::{exit, wait, fork, abort, raise};
use apue::{LibcResult, err_sys, pr_exit};
use std::panic;

fn handle_panic(e: &panic::PanicInfo) {
    match e.payload().downcast_ref::<String>() {
        Some(as_string) if as_string == "attempt to divide by zero" => {
            unsafe { raise(SIGFPE) };
        }
        _ => {
            panic!("unknown error occurred");
        }
    }
}

fn main() {
    panic::set_hook(Box::new(handle_panic));
    unsafe {
        let mut status: c_int = 0;
        let mut pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            exit(7);
        }
        if wait(&mut status) != pid {
            // wait for child
            err_sys("wait error");
        }
        pr_exit(status);

        pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            abort(); // generate SIGABRT
        }
        if wait(&mut status) != pid {
            // wait for child
            err_sys("wait error");
        }
        pr_exit(status);

        pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            let z = 0;
            status /= z; // divide by 0 generates SIGFPE
        }

        if wait(&mut status) != pid {
            err_sys("wait error");
        }
        pr_exit(status);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLBRElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLBRElementDerived;
use dom::bindings::error::ErrorResult;
use dom::bindings::js::{JSRef, Temporary};
use dom::document::Document;
use dom::element::HTMLBRElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLBRElement {
    pub htmlelement: HTMLElement,
}

impl HTMLBRElementDerived for EventTarget {
    fn is_htmlbrelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLBRElementTypeId))
    }
}

impl HTMLBRElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLBRElement {
        HTMLBRElement {
            htmlelement: HTMLElement::new_inherited(HTMLBRElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLBRElement> {
        let element = HTMLBRElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLBRElementBinding::Wrap)
    }
}

pub trait HTMLBRElementMethods {
    fn Clear(&self) -> DOMString;
    fn SetClear(&mut self, _text: DOMString) -> ErrorResult;
}

impl<'a> HTMLBRElementMethods for JSRef<'a, HTMLBRElement> {
    fn Clear(&self) -> DOMString {
        "".to_owned()
    }

    fn SetClear(&mut self, _text: DOMString) -> ErrorResult {
        Ok(())
    }
}
<commit_msg>Remove needless '&mut self' from HTMLBRElementMethods.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLBRElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLBRElementDerived;
use dom::bindings::error::ErrorResult;
use dom::bindings::js::{JSRef, Temporary};
use dom::document::Document;
use dom::element::HTMLBRElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLBRElement {
    pub htmlelement: HTMLElement,
}

impl HTMLBRElementDerived for EventTarget {
    fn is_htmlbrelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLBRElementTypeId))
    }
}

impl HTMLBRElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLBRElement {
        HTMLBRElement {
            htmlelement: HTMLElement::new_inherited(HTMLBRElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLBRElement> {
        let element = HTMLBRElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLBRElementBinding::Wrap)
    }
}

pub trait HTMLBRElementMethods {
    fn Clear(&self) -> DOMString;
    fn SetClear(&self, _text: DOMString) -> ErrorResult;
}

impl<'a> HTMLBRElementMethods for JSRef<'a, HTMLBRElement> {
    fn Clear(&self) -> DOMString {
        "".to_owned()
    }

    fn SetClear(&self, _text: DOMString) -> ErrorResult {
        Ok(())
    }
}
<|endoftext|>


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

use std::collections::hashmap::HashSet;
use std::gc::{Gc, GC};
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::{respan, DUMMY_SP};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::{ToTokens, ExtParseUtils};
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::intern;

use builder::meta_args::{ToTyHash, set_ty_params_for_task};
use node;
use super::{Builder, TokenString, add_node_dependency};

pub fn attach(builder: &mut Builder, _: &mut ExtCtxt, node: Rc<node::Node>) {
  node.materializer.set(Some(verify));
  let mcu_node = builder.pt.get_by_path("mcu").unwrap();

  let maybe_task_node = node.get_by_path("single_task");
  if maybe_task_node.is_some() {
    let task_node = maybe_task_node.unwrap();
    task_node.materializer.set(Some(build_single_task));
    add_node_dependency(&node, &task_node);
    add_node_dependency(&task_node, &mcu_node);

    let maybe_args_node = task_node.get_by_path("args");
    if maybe_args_node.is_some() {
      let args_node = maybe_args_node.unwrap();
      for (_, ref attr) in args_node.attributes.borrow().iter() {
        match attr.value {
          node::RefValue(ref refname) => {
            let refnode = builder.pt.get_by_name(refname.as_slice()).unwrap();
            add_node_dependency(&task_node, &refnode);
          },
          _ => (),
        }
      }
    }
  }
}

pub fn verify(_: &mut Builder, cx: &mut ExtCtxt, node: Rc<node::Node>) {
  node.expect_no_attributes(cx);
  node.expect_subnodes(cx, ["single_task"]);
  if node.get_by_path("single_task").is_none() {
    cx.parse_sess().span_diagnostic.span_err(node.name_span,
        "subnode `single_task` must be present");
  }
}

fn build_single_task(builder: &mut Builder, cx: &mut ExtCtxt,
    node: Rc<node::Node>) {
  let some_loop_fn = node.get_required_string_attr(cx, "loop");
  match some_loop_fn {
    Some(loop_fn) => {
      let args_node = node.get_by_path("args");
      let args = match args_node.and_then(|args| {
        Some(build_args(builder, cx, &loop_fn, args))
      }) {
        None => vec!(),
        Some(arg) => vec!(arg),
      };

      let call_expr = cx.expr_call_ident(
          node.get_attr("loop").value_span,
          cx.ident_of(loop_fn.as_slice()),
          args);
      let loop_stmt = quote_stmt!(&*cx, loop { $call_expr; } );
      builder.add_main_statement(loop_stmt);
    },
    None => (),
  }
}

fn build_args(builder: &mut Builder, cx: &mut ExtCtxt,
    struct_name: &String, node: Rc<node::Node>) -> Gc<ast::Expr> {
  let mut fields = vec!();
  let mut expr_fields = vec!();
  let node_attr = node.attributes.borrow();
  let mut ty_params = HashSet::new();

  // this is a bit slower than for (k, v) in node.attributes.iter(), but we need
  // to preserve sort order to make reasonably simple test code
  let mut all_keys = Vec::new();
  for k in node_attr.keys() { all_keys.push(k.clone()) };
  all_keys.sort();

  for k in all_keys.iter() {
    let v = node_attr.get(k);

    let (ty, val) = match v.value {
      node::IntValue(i) =>
        (cx.ty_ident(DUMMY_SP, cx.ident_of("u32")),
            quote_expr!(&*cx, $i)),
      node::StrValue(ref string)  => {
        let static_lifetime = cx.lifetime(DUMMY_SP, intern("'static"));
        let val_slice = string.as_slice();
        (cx.ty_rptr(
          DUMMY_SP,
          cx.ty_ident(DUMMY_SP, cx.ident_of("str")),
          Some(static_lifetime),
          ast::MutImmutable), quote_expr!(&*cx, $val_slice))
      },
      node::RefValue(ref rname)  => {
        let refnode = builder.pt.get_by_name(rname.as_slice()).unwrap();
        let reftype = refnode.type_name().unwrap();
        let refparams = refnode.type_params();
        for param in refparams.iter() {
          if !param.as_slice().starts_with("'") {
            ty_params.insert(param.clone());
          }
        }
        let val_slice = TokenString(rname.clone());
        let a_lifetime = cx.lifetime(DUMMY_SP, intern("'a"));
        (cx.ty_rptr(
          DUMMY_SP,
          cx.ty_path(type_name_as_path(cx, reftype.as_slice(), refparams), None),
          Some(a_lifetime),
          ast::MutImmutable), quote_expr!(&*cx, &$val_slice))
      },
    };
    let name_ident = cx.ident_of(k.as_slice());
    let sf = ast::StructField_ {
      kind: ast::NamedField(name_ident, ast::Public),
      id: ast::DUMMY_NODE_ID,
      ty: ty,
      attrs: vec!(),
    };

    fields.push(respan(DUMMY_SP, sf));
    expr_fields.push(cx.field_imm(DUMMY_SP, name_ident, val));
  }

  let name_ident = cx.ident_of(format!("{}_args", struct_name).as_slice());
  let a_lifetime = cx.lifetime(DUMMY_SP, intern("'a"));
  let mut collected_params = vec!();
  let mut ty_params_vec = vec!();
  for ty in ty_params.iter() {
    let typaram = cx.typaram(
        DUMMY_SP,
        cx.ident_of(ty.to_tyhash().as_slice()),
        OwnedSlice::empty(),
        None,
        None);
    collected_params.push(typaram);
    ty_params_vec.push(ty.clone());
  }

  set_ty_params_for_task(cx, struct_name.as_slice(), ty_params_vec);
  let struct_item = box(GC) ast::Item {
    ident: name_ident,
    attrs: vec!(),
    id: ast::DUMMY_NODE_ID,
    node: ast::ItemStruct(box(GC) ast::StructDef {
      fields: fields,
      ctor_id: None,
      super_struct: None,
      is_virtual: false,
    }, ast::Generics {
      lifetimes: vec!(a_lifetime),
      ty_params: OwnedSlice::from_vec(collected_params),
    }),
    vis: ast::Public,
    span: DUMMY_SP,
  };
  builder.add_type_item(struct_item);

  cx.expr_addr_of(DUMMY_SP,
      cx.expr_struct(
          DUMMY_SP,
          cx.path(DUMMY_SP, vec!(cx.ident_of("pt"), name_ident)),
          expr_fields))
}

fn type_name_as_path(cx: &ExtCtxt, ty: &str, params: Vec<String>) -> ast::Path {
  let mut lifetimes = vec!();
  let mut types = vec!();
  for p in params.iter() {
    let slice = p.as_slice();
    if slice.starts_with("'") {
      let lifetime = cx.lifetime(DUMMY_SP, intern(slice));
      lifetimes.push(lifetime);
    } else {
      let path = cx.ty_path(type_name_as_path(cx, p.to_tyhash().as_slice(), vec!()), None);
      types.push(path);
    }
  }
  cx.path_all(DUMMY_SP, false,
      ty.split_str("::").map(|t| cx.ident_of(t)).collect(),
      lifetimes,
      types)
}

#[cfg(test)]
mod test {
  use syntax::codemap::DUMMY_SP;
  use syntax::ext::build::AstBuilder;

  use builder::Builder;
  use super::build_single_task;
  use test_helpers::{assert_equal_source, with_parsed};

  #[test]
  fn builds_single_task_os_loop() {
    with_parsed("
      single_task {
        loop = \"run\";
      }", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      build_single_task(&mut builder, cx, pt.get_by_path("single_task").unwrap().clone());
      assert!(unsafe{*failed} == false);
      assert!(builder.main_stmts.len() == 1);

      assert_equal_source(builder.main_stmts[0],
          "loop {
            run();
          }");
    });
  }

  #[test]
  fn builds_single_task_with_args() {
    with_parsed("
      single_task {
        loop = \"run\";
        args {
          a = 1;
          b = \"a\";
          c = &named;
        }
      }

      named@ref;
      ", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      pt.get_by_path("ref").unwrap().set_type_name("hello::world::Struct".to_string());

      build_single_task(&mut builder, cx, pt.get_by_path("single_task").unwrap().clone());
      assert!(unsafe{*failed} == false);
      assert!(builder.main_stmts.len() == 1);
      assert!(builder.type_items.len() == 1);

      assert_equal_source(cx.stmt_item(DUMMY_SP, builder.type_items[0]),
          "pub struct run_args<'a> {
            pub a: u32,
            pub b: &'static str,
            pub c: &'a hello::world::Struct,
          }");

      assert_equal_source(builder.main_stmts[0],
          "loop {
            run(&pt::run_args {
              a: 1u,
              b: \"a\",
              c: &named,
            });
          }");
    });
  }
}
<commit_msg>Using new lifetime_def (fixes #132)<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::hashmap::HashSet;
use std::gc::{Gc, GC};
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::{respan, DUMMY_SP};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::{ToTokens, ExtParseUtils};
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::intern;

use builder::meta_args::{ToTyHash, set_ty_params_for_task};
use node;
use super::{Builder, TokenString, add_node_dependency};

pub fn attach(builder: &mut Builder, _: &mut ExtCtxt, node: Rc<node::Node>) {
  node.materializer.set(Some(verify));
  let mcu_node = builder.pt.get_by_path("mcu").unwrap();

  let maybe_task_node = node.get_by_path("single_task");
  if maybe_task_node.is_some() {
    let task_node = maybe_task_node.unwrap();
    task_node.materializer.set(Some(build_single_task));
    add_node_dependency(&node, &task_node);
    add_node_dependency(&task_node, &mcu_node);

    let maybe_args_node = task_node.get_by_path("args");
    if maybe_args_node.is_some() {
      let args_node = maybe_args_node.unwrap();
      for (_, ref attr) in args_node.attributes.borrow().iter() {
        match attr.value {
          node::RefValue(ref refname) => {
            let refnode = builder.pt.get_by_name(refname.as_slice()).unwrap();
            add_node_dependency(&task_node, &refnode);
          },
          _ => (),
        }
      }
    }
  }
}

pub fn verify(_: &mut Builder, cx: &mut ExtCtxt, node: Rc<node::Node>) {
  node.expect_no_attributes(cx);
  node.expect_subnodes(cx, ["single_task"]);
  if node.get_by_path("single_task").is_none() {
    cx.parse_sess().span_diagnostic.span_err(node.name_span,
        "subnode `single_task` must be present");
  }
}

fn build_single_task(builder: &mut Builder, cx: &mut ExtCtxt,
    node: Rc<node::Node>) {
  let some_loop_fn = node.get_required_string_attr(cx, "loop");
  match some_loop_fn {
    Some(loop_fn) => {
      let args_node = node.get_by_path("args");
      let args = match args_node.and_then(|args| {
        Some(build_args(builder, cx, &loop_fn, args))
      }) {
        None => vec!(),
        Some(arg) => vec!(arg),
      };

      let call_expr = cx.expr_call_ident(
          node.get_attr("loop").value_span,
          cx.ident_of(loop_fn.as_slice()),
          args);
      let loop_stmt = quote_stmt!(&*cx, loop { $call_expr; } );
      builder.add_main_statement(loop_stmt);
    },
    None => (),
  }
}

fn build_args(builder: &mut Builder, cx: &mut ExtCtxt,
    struct_name: &String, node: Rc<node::Node>) -> Gc<ast::Expr> {
  let mut fields = vec!();
  let mut expr_fields = vec!();
  let node_attr = node.attributes.borrow();
  let mut ty_params = HashSet::new();

  // this is a bit slower than for (k, v) in node.attributes.iter(), but we need
  // to preserve sort order to make reasonably simple test code
  let mut all_keys = Vec::new();
  for k in node_attr.keys() { all_keys.push(k.clone()) };
  all_keys.sort();

  for k in all_keys.iter() {
    let v = node_attr.get(k);

    let (ty, val) = match v.value {
      node::IntValue(i) =>
        (cx.ty_ident(DUMMY_SP, cx.ident_of("u32")),
            quote_expr!(&*cx, $i)),
      node::StrValue(ref string)  => {
        let static_lifetime = cx.lifetime(DUMMY_SP, intern("'static"));
        let val_slice = string.as_slice();
        (cx.ty_rptr(
          DUMMY_SP,
          cx.ty_ident(DUMMY_SP, cx.ident_of("str")),
          Some(static_lifetime),
          ast::MutImmutable), quote_expr!(&*cx, $val_slice))
      },
      node::RefValue(ref rname)  => {
        let refnode = builder.pt.get_by_name(rname.as_slice()).unwrap();
        let reftype = refnode.type_name().unwrap();
        let refparams = refnode.type_params();
        for param in refparams.iter() {
          if !param.as_slice().starts_with("'") {
            ty_params.insert(param.clone());
          }
        }
        let val_slice = TokenString(rname.clone());
        let a_lifetime = cx.lifetime(DUMMY_SP, intern("'a"));
        (cx.ty_rptr(
          DUMMY_SP,
          cx.ty_path(type_name_as_path(cx, reftype.as_slice(), refparams), None),
          Some(a_lifetime),
          ast::MutImmutable), quote_expr!(&*cx, &$val_slice))
      },
    };
    let name_ident = cx.ident_of(k.as_slice());
    let sf = ast::StructField_ {
      kind: ast::NamedField(name_ident, ast::Public),
      id: ast::DUMMY_NODE_ID,
      ty: ty,
      attrs: vec!(),
    };

    fields.push(respan(DUMMY_SP, sf));
    expr_fields.push(cx.field_imm(DUMMY_SP, name_ident, val));
  }

  let name_ident = cx.ident_of(format!("{}_args", struct_name).as_slice());
  let mut collected_params = vec!();
  let mut ty_params_vec = vec!();
  for ty in ty_params.iter() {
    let typaram = cx.typaram(
        DUMMY_SP,
        cx.ident_of(ty.to_tyhash().as_slice()),
        OwnedSlice::empty(),
        None,
        None);
    collected_params.push(typaram);
    ty_params_vec.push(ty.clone());
  }

  set_ty_params_for_task(cx, struct_name.as_slice(), ty_params_vec);
  let struct_item = box(GC) ast::Item {
    ident: name_ident,
    attrs: vec!(),
    id: ast::DUMMY_NODE_ID,
    node: ast::ItemStruct(box(GC) ast::StructDef {
      fields: fields,
      ctor_id: None,
      super_struct: None,
      is_virtual: false,
    }, ast::Generics {
      lifetimes: vec!(cx.lifetime_def(DUMMY_SP, intern("'a"), vec!())),
      ty_params: OwnedSlice::from_vec(collected_params),
    }),
    vis: ast::Public,
    span: DUMMY_SP,
  };
  builder.add_type_item(struct_item);

  cx.expr_addr_of(DUMMY_SP,
      cx.expr_struct(
          DUMMY_SP,
          cx.path(DUMMY_SP, vec!(cx.ident_of("pt"), name_ident)),
          expr_fields))
}

fn type_name_as_path(cx: &ExtCtxt, ty: &str, params: Vec<String>) -> ast::Path {
  let mut lifetimes = vec!();
  let mut types = vec!();
  for p in params.iter() {
    let slice = p.as_slice();
    if slice.starts_with("'") {
      let lifetime = cx.lifetime(DUMMY_SP, intern(slice));
      lifetimes.push(lifetime);
    } else {
      let path = cx.ty_path(type_name_as_path(cx, p.to_tyhash().as_slice(), vec!()), None);
      types.push(path);
    }
  }
  cx.path_all(DUMMY_SP, false,
      ty.split_str("::").map(|t| cx.ident_of(t)).collect(),
      lifetimes,
      types)
}

#[cfg(test)]
mod test {
  use syntax::codemap::DUMMY_SP;
  use syntax::ext::build::AstBuilder;

  use builder::Builder;
  use super::build_single_task;
  use test_helpers::{assert_equal_source, with_parsed};

  #[test]
  fn builds_single_task_os_loop() {
    with_parsed("
      single_task {
        loop = \"run\";
      }", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      build_single_task(&mut builder, cx, pt.get_by_path("single_task").unwrap().clone());
      assert!(unsafe{*failed} == false);
      assert!(builder.main_stmts.len() == 1);

      assert_equal_source(builder.main_stmts[0],
          "loop {
            run();
          }");
    });
  }

  #[test]
  fn builds_single_task_with_args() {
    with_parsed("
      single_task {
        loop = \"run\";
        args {
          a = 1;
          b = \"a\";
          c = &named;
        }
      }

      named@ref;
      ", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      pt.get_by_path("ref").unwrap().set_type_name("hello::world::Struct".to_string());

      build_single_task(&mut builder, cx, pt.get_by_path("single_task").unwrap().clone());
      assert!(unsafe{*failed} == false);
      assert!(builder.main_stmts.len() == 1);
      assert!(builder.type_items.len() == 1);

      assert_equal_source(cx.stmt_item(DUMMY_SP, builder.type_items[0]),
          "pub struct run_args<'a> {
            pub a: u32,
            pub b: &'static str,
            pub c: &'a hello::world::Struct,
          }");

      assert_equal_source(builder.main_stmts[0],
          "loop {
            run(&pt::run_args {
              a: 1u,
              b: \"a\",
              c: &named,
            });
          }");
    });
  }
}
<|endoftext|>


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

use std::collections::hashmap::HashSet;
use std::gc::{Gc, GC};
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::{respan, DUMMY_SP};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::{ToTokens, ExtParseUtils};
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::intern;

use builder::meta_args::{ToTyHash, set_ty_params_for_task};
use node;
use super::{Builder, TokenString, add_node_dependency};

pub fn attach(builder: &mut Builder, _: &mut ExtCtxt, node: Rc<node::Node>) {
  node.materializer.set(Some(verify));
  let mcu_node = builder.pt.get_by_path("mcu").unwrap();

  let maybe_task_node = node.get_by_path("single_task");
  if maybe_task_node.is_some() {
    let task_node = maybe_task_node.unwrap();
    task_node.materializer.set(Some(build_single_task));
    add_node_dependency(&node, &task_node);
    add_node_dependency(&task_node, &mcu_node);

    let maybe_args_node = task_node.get_by_path("args");
    if maybe_args_node.is_some() {
      let args_node = maybe_args_node.unwrap();
      for (_, ref attr) in args_node.attributes.borrow().iter() {
        match attr.value {
          node::RefValue(ref refname) => {
            let refnode = builder.pt.get_by_name(refname.as_slice()).unwrap();
            add_node_dependency(&task_node, &refnode);
          },
          _ => (),
        }
      }
    }
  }
}

pub fn verify(_: &mut Builder, cx: &mut ExtCtxt, node: Rc<node::Node>) {
  node.expect_no_attributes(cx);
  node.expect_subnodes(cx, ["single_task"]);
  if node.get_by_path("single_task").is_none() {
    cx.parse_sess().span_diagnostic.span_err(node.name_span,
        "subnode `single_task` must be present");
  }
}

fn build_single_task(builder: &mut Builder, cx: &mut ExtCtxt,
    node: Rc<node::Node>) {
  let some_loop_fn = node.get_required_string_attr(cx, "loop");
  match some_loop_fn {
    Some(loop_fn) => {
      let args_node = node.get_by_path("args");
      let args = match args_node.and_then(|args| {
        Some(build_args(builder, cx, &loop_fn, args))
      }) {
        None => vec!(),
        Some(arg) => vec!(arg),
      };

      let call_expr = cx.expr_call_ident(
          node.get_attr("loop").value_span,
          cx.ident_of(loop_fn.as_slice()),
          args);
      let loop_stmt = quote_stmt!(&*cx, loop { $call_expr; } );
      builder.add_main_statement(loop_stmt);
    },
    None => (),
  }
}

fn build_args(builder: &mut Builder, cx: &mut ExtCtxt,
    struct_name: &String, node: Rc<node::Node>) -> Gc<ast::Expr> {
  let mut fields = vec!();
  let mut expr_fields = vec!();
  let node_attr = node.attributes.borrow();
  let mut ty_params = HashSet::new();

  // this is a bit slower than for (k, v) in node.attributes.iter(), but we need
  // to preserve sort order to make reasonably simple test code
  let mut all_keys = Vec::new();
  for k in node_attr.keys() { all_keys.push(k.clone()) };
  all_keys.sort();

  for k in all_keys.iter() {
    let v = &(*node_attr)[*k];

    let (ty, val) = match v.value {
      node::IntValue(i) =>
        (cx.ty_ident(DUMMY_SP, cx.ident_of("u32")),
            quote_expr!(&*cx, $i)),
      node::StrValue(ref string)  => {
        let static_lifetime = cx.lifetime(DUMMY_SP, intern("'static"));
        let val_slice = string.as_slice();
        (cx.ty_rptr(
          DUMMY_SP,
          cx.ty_ident(DUMMY_SP, cx.ident_of("str")),
          Some(static_lifetime),
          ast::MutImmutable), quote_expr!(&*cx, $val_slice))
      },
      node::RefValue(ref rname)  => {
        let refnode = builder.pt.get_by_name(rname.as_slice()).unwrap();
        let reftype = refnode.type_name().unwrap();
        let refparams = refnode.type_params();
        for param in refparams.iter() {
          if !param.as_slice().starts_with("'") {
            ty_params.insert(param.clone());
          }
        }
        let val_slice = TokenString(rname.clone());
        let a_lifetime = cx.lifetime(DUMMY_SP, intern("'a"));
        (cx.ty_rptr(
          DUMMY_SP,
          cx.ty_path(type_name_as_path(cx, reftype.as_slice(), refparams), None),
          Some(a_lifetime),
          ast::MutImmutable), quote_expr!(&*cx, &$val_slice))
      },
    };
    let name_ident = cx.ident_of(k.as_slice());
    let sf = ast::StructField_ {
      kind: ast::NamedField(name_ident, ast::Public),
      id: ast::DUMMY_NODE_ID,
      ty: ty,
      attrs: vec!(),
    };

    fields.push(respan(DUMMY_SP, sf));
    expr_fields.push(cx.field_imm(DUMMY_SP, name_ident, val));
  }

  let name_ident = cx.ident_of(format!("{}_args", struct_name).as_slice());
  let mut collected_params = vec!();
  let mut ty_params_vec = vec!();
  for ty in ty_params.iter() {
    let typaram = cx.typaram(
        DUMMY_SP,
        cx.ident_of(ty.to_tyhash().as_slice()),
        OwnedSlice::empty(),
        None,
        None);
    collected_params.push(typaram);
    ty_params_vec.push(ty.clone());
  }

  set_ty_params_for_task(cx, struct_name.as_slice(), ty_params_vec);
  let struct_item = box(GC) ast::Item {
    ident: name_ident,
    attrs: vec!(),
    id: ast::DUMMY_NODE_ID,
    node: ast::ItemStruct(box(GC) ast::StructDef {
      fields: fields,
      ctor_id: None,
      super_struct: None,
      is_virtual: false,
    }, ast::Generics {
      lifetimes: vec!(cx.lifetime_def(DUMMY_SP, intern("'a"), vec!())),
      ty_params: OwnedSlice::from_vec(collected_params),
      where_clause: ast::WhereClause {
        id: ast::DUMMY_NODE_ID,
        predicates: vec!(),
      }
    }),
    vis: ast::Public,
    span: DUMMY_SP,
  };
  builder.add_type_item(struct_item);

  cx.expr_addr_of(DUMMY_SP,
      cx.expr_struct(
          DUMMY_SP,
          cx.path(DUMMY_SP, vec!(cx.ident_of("pt"), name_ident)),
          expr_fields))
}

fn type_name_as_path(cx: &ExtCtxt, ty: &str, params: Vec<String>) -> ast::Path {
  let mut lifetimes = vec!();
  let mut types = vec!();
  for p in params.iter() {
    let slice = p.as_slice();
    if slice.starts_with("'") {
      let lifetime = cx.lifetime(DUMMY_SP, intern(slice));
      lifetimes.push(lifetime);
    } else {
      let path = cx.ty_path(type_name_as_path(cx, p.to_tyhash().as_slice(), vec!()), None);
      types.push(path);
    }
  }
  cx.path_all(DUMMY_SP, false,
      ty.split_str("::").map(|t| cx.ident_of(t)).collect(),
      lifetimes,
      types)
}

#[cfg(test)]
mod test {
  use syntax::codemap::DUMMY_SP;
  use syntax::ext::build::AstBuilder;

  use builder::Builder;
  use super::build_single_task;
  use test_helpers::{assert_equal_source, with_parsed};

  #[test]
  fn builds_single_task_os_loop() {
    with_parsed("
      single_task {
        loop = \"run\";
      }", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      build_single_task(&mut builder, cx, pt.get_by_path("single_task").unwrap().clone());
      assert!(unsafe{*failed} == false);
      assert!(builder.main_stmts.len() == 1);

      assert_equal_source(builder.main_stmts[0],
          "loop {
            run();
          }");
    });
  }

  #[test]
  fn builds_single_task_with_args() {
    with_parsed("
      single_task {
        loop = \"run\";
        args {
          a = 1;
          b = \"a\";
          c = &named;
        }
      }

      named@ref;
      ", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      pt.get_by_path("ref").unwrap().set_type_name("hello::world::Struct".to_string());

      build_single_task(&mut builder, cx, pt.get_by_path("single_task").unwrap().clone());
      assert!(unsafe{*failed} == false);
      assert!(builder.main_stmts.len() == 1);
      assert!(builder.type_items.len() == 1);

      assert_equal_source(cx.stmt_item(DUMMY_SP, builder.type_items[0]),
          "pub struct run_args<'a> {
            pub a: u32,
            pub b: &'static str,
            pub c: &'a hello::world::Struct,
          }");

      assert_equal_source(builder.main_stmts[0],
          "loop {
            run(&pt::run_args {
              a: 1u,
              b: \"a\",
              c: &named,
            });
          }");
    });
  }
}
<commit_msg>Fixed param bound for os PT<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::hashmap::HashSet;
use std::gc::{Gc, GC};
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::{respan, DUMMY_SP};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::{ToTokens, ExtParseUtils};
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::intern;

use builder::meta_args::{ToTyHash, set_ty_params_for_task};
use node;
use super::{Builder, TokenString, add_node_dependency};

pub fn attach(builder: &mut Builder, _: &mut ExtCtxt, node: Rc<node::Node>) {
  node.materializer.set(Some(verify));
  let mcu_node = builder.pt.get_by_path("mcu").unwrap();

  let maybe_task_node = node.get_by_path("single_task");
  if maybe_task_node.is_some() {
    let task_node = maybe_task_node.unwrap();
    task_node.materializer.set(Some(build_single_task));
    add_node_dependency(&node, &task_node);
    add_node_dependency(&task_node, &mcu_node);

    let maybe_args_node = task_node.get_by_path("args");
    if maybe_args_node.is_some() {
      let args_node = maybe_args_node.unwrap();
      for (_, ref attr) in args_node.attributes.borrow().iter() {
        match attr.value {
          node::RefValue(ref refname) => {
            let refnode = builder.pt.get_by_name(refname.as_slice()).unwrap();
            add_node_dependency(&task_node, &refnode);
          },
          _ => (),
        }
      }
    }
  }
}

pub fn verify(_: &mut Builder, cx: &mut ExtCtxt, node: Rc<node::Node>) {
  node.expect_no_attributes(cx);
  node.expect_subnodes(cx, ["single_task"]);
  if node.get_by_path("single_task").is_none() {
    cx.parse_sess().span_diagnostic.span_err(node.name_span,
        "subnode `single_task` must be present");
  }
}

fn build_single_task(builder: &mut Builder, cx: &mut ExtCtxt,
    node: Rc<node::Node>) {
  let some_loop_fn = node.get_required_string_attr(cx, "loop");
  match some_loop_fn {
    Some(loop_fn) => {
      let args_node = node.get_by_path("args");
      let args = match args_node.and_then(|args| {
        Some(build_args(builder, cx, &loop_fn, args))
      }) {
        None => vec!(),
        Some(arg) => vec!(arg),
      };

      let call_expr = cx.expr_call_ident(
          node.get_attr("loop").value_span,
          cx.ident_of(loop_fn.as_slice()),
          args);
      let loop_stmt = quote_stmt!(&*cx, loop { $call_expr; } );
      builder.add_main_statement(loop_stmt);
    },
    None => (),
  }
}

fn build_args(builder: &mut Builder, cx: &mut ExtCtxt,
    struct_name: &String, node: Rc<node::Node>) -> Gc<ast::Expr> {
  let mut fields = vec!();
  let mut expr_fields = vec!();
  let node_attr = node.attributes.borrow();
  let mut ty_params = HashSet::new();

  // this is a bit slower than for (k, v) in node.attributes.iter(), but we need
  // to preserve sort order to make reasonably simple test code
  let mut all_keys = Vec::new();
  for k in node_attr.keys() { all_keys.push(k.clone()) };
  all_keys.sort();

  for k in all_keys.iter() {
    let v = &(*node_attr)[*k];

    let (ty, val) = match v.value {
      node::IntValue(i) =>
        (cx.ty_ident(DUMMY_SP, cx.ident_of("u32")),
            quote_expr!(&*cx, $i)),
      node::StrValue(ref string)  => {
        let static_lifetime = cx.lifetime(DUMMY_SP, intern("'static"));
        let val_slice = string.as_slice();
        (cx.ty_rptr(
          DUMMY_SP,
          cx.ty_ident(DUMMY_SP, cx.ident_of("str")),
          Some(static_lifetime),
          ast::MutImmutable), quote_expr!(&*cx, $val_slice))
      },
      node::RefValue(ref rname)  => {
        let refnode = builder.pt.get_by_name(rname.as_slice()).unwrap();
        let reftype = refnode.type_name().unwrap();
        let refparams = refnode.type_params();
        for param in refparams.iter() {
          if !param.as_slice().starts_with("'") {
            ty_params.insert(param.clone());
          }
        }
        let val_slice = TokenString(rname.clone());
        let a_lifetime = cx.lifetime(DUMMY_SP, intern("'a"));
        (cx.ty_rptr(
          DUMMY_SP,
          cx.ty_path(type_name_as_path(cx, reftype.as_slice(), refparams), None),
          Some(a_lifetime),
          ast::MutImmutable), quote_expr!(&*cx, &$val_slice))
      },
    };
    let name_ident = cx.ident_of(k.as_slice());
    let sf = ast::StructField_ {
      kind: ast::NamedField(name_ident, ast::Public),
      id: ast::DUMMY_NODE_ID,
      ty: ty,
      attrs: vec!(),
    };

    fields.push(respan(DUMMY_SP, sf));
    expr_fields.push(cx.field_imm(DUMMY_SP, name_ident, val));
  }

  let name_ident = cx.ident_of(format!("{}_args", struct_name).as_slice());
  let mut collected_params = vec!();
  let mut ty_params_vec = vec!();
  for ty in ty_params.iter() {
    let typaram = cx.typaram(
        DUMMY_SP,
        cx.ident_of(ty.to_tyhash().as_slice()),
        OwnedSlice::from_vec(vec!(
          ast::RegionTyParamBound(cx.lifetime(DUMMY_SP, intern("'a")))
        )),
        None,
        None);
    collected_params.push(typaram);
    ty_params_vec.push(ty.clone());
  }

  set_ty_params_for_task(cx, struct_name.as_slice(), ty_params_vec);
  let struct_item = box(GC) ast::Item {
    ident: name_ident,
    attrs: vec!(),
    id: ast::DUMMY_NODE_ID,
    node: ast::ItemStruct(box(GC) ast::StructDef {
      fields: fields,
      ctor_id: None,
      super_struct: None,
      is_virtual: false,
    }, ast::Generics {
      lifetimes: vec!(cx.lifetime_def(DUMMY_SP, intern("'a"), vec!())),
      ty_params: OwnedSlice::from_vec(collected_params),
      where_clause: ast::WhereClause {
        id: ast::DUMMY_NODE_ID,
        predicates: vec!(),
      }
    }),
    vis: ast::Public,
    span: DUMMY_SP,
  };
  builder.add_type_item(struct_item);

  cx.expr_addr_of(DUMMY_SP,
      cx.expr_struct(
          DUMMY_SP,
          cx.path(DUMMY_SP, vec!(cx.ident_of("pt"), name_ident)),
          expr_fields))
}

fn type_name_as_path(cx: &ExtCtxt, ty: &str, params: Vec<String>) -> ast::Path {
  let mut lifetimes = vec!();
  let mut types = vec!();
  for p in params.iter() {
    let slice = p.as_slice();
    if slice.starts_with("'") {
      let lifetime = cx.lifetime(DUMMY_SP, intern(slice));
      lifetimes.push(lifetime);
    } else {
      let path = cx.ty_path(type_name_as_path(cx, p.to_tyhash().as_slice(), vec!()), None);
      types.push(path);
    }
  }
  cx.path_all(DUMMY_SP, false,
      ty.split_str("::").map(|t| cx.ident_of(t)).collect(),
      lifetimes,
      types)
}

#[cfg(test)]
mod test {
  use syntax::codemap::DUMMY_SP;
  use syntax::ext::build::AstBuilder;

  use builder::Builder;
  use super::build_single_task;
  use test_helpers::{assert_equal_source, with_parsed};

  #[test]
  fn builds_single_task_os_loop() {
    with_parsed("
      single_task {
        loop = \"run\";
      }", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      build_single_task(&mut builder, cx, pt.get_by_path("single_task").unwrap().clone());
      assert!(unsafe{*failed} == false);
      assert!(builder.main_stmts.len() == 1);

      assert_equal_source(builder.main_stmts[0],
          "loop {
            run();
          }");
    });
  }

  #[test]
  fn builds_single_task_with_args() {
    with_parsed("
      single_task {
        loop = \"run\";
        args {
          a = 1;
          b = \"a\";
          c = &named;
        }
      }

      named@ref;
      ", |cx, failed, pt| {
      let mut builder = Builder::new(pt.clone());
      pt.get_by_path("ref").unwrap().set_type_name("hello::world::Struct".to_string());

      build_single_task(&mut builder, cx, pt.get_by_path("single_task").unwrap().clone());
      assert!(unsafe{*failed} == false);
      assert!(builder.main_stmts.len() == 1);
      assert!(builder.type_items.len() == 1);

      assert_equal_source(cx.stmt_item(DUMMY_SP, builder.type_items[0]),
          "pub struct run_args<'a> {
            pub a: u32,
            pub b: &'static str,
            pub c: &'a hello::world::Struct,
          }");

      assert_equal_source(builder.main_stmts[0],
          "loop {
            run(&pt::run_args {
              a: 1u,
              b: \"a\",
              c: &named,
            });
          }");
    });
  }
}
<|endoftext|>


<commit_before>extern crate rosc;
extern crate byteorder;

use byteorder::{ByteOrder, BigEndian};
use std::{mem, iter};
use std::ascii::AsciiExt;

use rosc::{types, errors, decoder, utils};

#[test]
fn test_decode_no_args() {
    // message to build: /some/valid/address/4 ,
    let raw_addr = "/some/valid/address/4";
    let addr = to_osc_string(raw_addr.as_bytes());
    let type_tags = to_osc_string(b",");
    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .collect();
    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    assert!(osc_packet.is_ok());
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            assert!(msg.args.is_none());
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

#[test]
fn test_decode_args() {
    // /another/valid/address/123 ,fdih 3.1415 3.14159265359 12345678i32
    // -1234567891011
    let raw_addr = "/another/valid/address/123";
    let addr = to_osc_string(raw_addr.as_bytes());
    // args
    let f = 3.1415f32;
    let mut f_bytes: [u8; 4] = [0u8; 4];
    BigEndian::write_f32(&mut f_bytes, f);
    assert_eq!(BigEndian::read_f32(&f_bytes), f);

    let d = 3.14159265359f64;
    let mut d_bytes: [u8; 8] = [0u8; 8];
    BigEndian::write_f64(&mut d_bytes, d);
    assert_eq!(BigEndian::read_f64(&d_bytes), d);

    let i = 12345678i32;
    let i_bytes: [u8; 4] = unsafe { mem::transmute(i.to_be()) };

    let l = -1234567891011i64;
    let h_bytes: [u8; 8] = unsafe { mem::transmute(l.to_be()) };

    let blob_size: [u8; 4] = unsafe { mem::transmute(6u32.to_be()) };
    let blob: Vec<u8> = vec![1u8, 2u8, 3u8, 4u8, 5u8, 6u8];

    let s = "I am an osc test string.";
    assert!(s.is_ascii());

    // Osc strings are null terminated like in C!
    let s_bytes: Vec<u8> = to_osc_string(s.as_bytes());

    let type_tags = to_osc_string(b",fdsTFibhNI");

    let args: Vec<u8> = f_bytes.iter()
                               .chain(d_bytes.iter())
                               .chain(s_bytes.iter())
                               .chain(i_bytes.iter())
                               .chain(blob_size.iter())
                               .chain(blob.iter())
                               .chain(vec![0u8, 0u8].iter())
                               .chain(h_bytes.iter())
                               .map(|x| *x)
                               .collect::<Vec<u8>>();

    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .chain(args)
                              .collect::<Vec<u8>>();

    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            for arg in msg.args.unwrap() {
                match arg {
                    types::OscType::Int(x) => assert_eq!(i, x),
                    types::OscType::Long(x) => assert_eq!(l, x),
                    types::OscType::Float(x) => assert_eq!(f, x),
                    types::OscType::Double(x) => assert_eq!(d, x),
                    types::OscType::String(x) => assert_eq!(s, x),
                    types::OscType::Blob(x) => assert_eq!(blob, x),
                    // cant assign bool args to type_tag, so there is no real test
                    types::OscType::Bool(x) => assert_eq!(x, x),
                    types::OscType::Inf => (),
                    types::OscType::Nil => (),
                    _ => panic!(),
                }
            }
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

/// Nul terminates the data and pads with zero bytes to a length that is a multiple of 4.
fn to_osc_string(data: &[u8]) -> Vec<u8> {
    let mut v: Vec<u8> = data.iter()
                             .cloned()
                             .chain(iter::once(0u8))
                             .collect();
    // v;
    let pad_len: usize = utils::pad(v.len() as u64) as usize;
    while v.len() < pad_len {
        v.push(0u8);
    }
    v
}<commit_msg>Simplify test structure<commit_after>extern crate rosc;
extern crate byteorder;

use byteorder::{ByteOrder, BigEndian};
use std::{mem, iter};
use std::ascii::AsciiExt;

use rosc::{types, errors, decoder, utils};

#[test]
fn test_decode_no_args() {
    // message to build: /some/valid/address/4 ,
    let raw_addr = "/some/valid/address/4";
    let addr = to_osc_string(raw_addr.as_bytes());
    let type_tags = to_osc_string(b",");
    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .collect();
    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    assert!(osc_packet.is_ok());
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            assert!(msg.args.is_none());
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

#[test]
fn test_decode_args() {
    // /another/valid/address/123 ,fdih 3.1415 3.14159265359 12345678i32
    // -1234567891011
    let raw_addr = "/another/valid/address/123";
    let addr = to_osc_string(raw_addr.as_bytes());
    // args
    let f = 3.1415f32;
    let mut f_bytes: [u8; 4] = [0u8; 4];
    BigEndian::write_f32(&mut f_bytes, f);
    assert_eq!(BigEndian::read_f32(&f_bytes), f);

    let d = 3.14159265359f64;
    let mut d_bytes: [u8; 8] = [0u8; 8];
    BigEndian::write_f64(&mut d_bytes, d);
    assert_eq!(BigEndian::read_f64(&d_bytes), d);

    let i = 12345678i32;
    let i_bytes: [u8; 4] = unsafe { mem::transmute(i.to_be()) };

    let l = -1234567891011i64;
    let h_bytes: [u8; 8] = unsafe { mem::transmute(l.to_be()) };

    let blob_size: [u8; 4] = unsafe { mem::transmute(6u32.to_be()) };
    let blob: Vec<u8> = vec![1u8, 2u8, 3u8, 4u8, 5u8, 6u8];

    let s = "I am an osc test string.";
    assert!(s.is_ascii());

    // Osc strings are null terminated like in C!
    let s_bytes: Vec<u8> = to_osc_string(s.as_bytes());

    let type_tags = to_osc_string(b",fdsTFibhNI");

    let args: Vec<u8> = f_bytes.iter()
                               .chain(d_bytes.iter())
                               .chain(s_bytes.iter())
                               .chain(i_bytes.iter())
                               .chain(blob_size.iter())
                               .chain(blob.iter())
                               .chain(vec![0u8, 0u8].iter())
                               .chain(h_bytes.iter())
                               .map(|x| *x)
                               .collect::<Vec<u8>>();

    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .chain(args)
                              .collect::<Vec<u8>>();

    match decoder::decode(&merged).unwrap() {
        types::OscPacket::Message(msg) => {
            for arg in msg.args.unwrap() {
                match arg {
                    types::OscType::Int(x) => assert_eq!(i, x),
                    types::OscType::Long(x) => assert_eq!(l, x),
                    types::OscType::Float(x) => assert_eq!(f, x),
                    types::OscType::Double(x) => assert_eq!(d, x),
                    types::OscType::String(x) => assert_eq!(s, x),
                    types::OscType::Blob(x) => assert_eq!(blob, x),
                    // cant assign bool args to type_tag, so there is no real test
                    types::OscType::Bool(x) => assert_eq!(x, x),
                    types::OscType::Inf => (),
                    types::OscType::Nil => (),
                    _ => panic!(),
                }

            }
        }
        _ => panic!("Expected an OSC message!"),
    }
}

/// Nul terminates the data and pads with zero bytes to a length that is a multiple of 4.
fn to_osc_string(data: &[u8]) -> Vec<u8> {
    let mut v: Vec<u8> = data.iter()
                             .cloned()
                             .chain(iter::once(0u8))
                             .collect();
    // v;
    let pad_len: usize = utils::pad(v.len() as u64) as usize;
    while v.len() < pad_len {
        v.push(0u8);
    }
    v
}<|endoftext|>


<commit_before>//extern crate native;

use std::comm;
use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

fn subtx(ii: uint, interval: Duration, task_tx: Sender<uint>) {
    task_tx.send(ii);
    timer::sleep(interval);
    println!("task {} is done", ii);
}

fn main() {
    let (tx, rx): (Sender<uint>, Receiver<uint>) = comm::channel();
    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(500);
    let tictoc: Receiver<()> = timer.periodic(interval);

    for ii in range(0u, 10) {
        let interval = Duration::milliseconds(ii as i64 * 20i64);
        let task_tx = tx.clone(); // clone the Sender

        spawn(proc() {
            subtx(ii, interval, task_tx);
        });
    }

    for ii in std::iter::range_step(10i, 0, -1) {
        tictoc.recv();
        println!("{}", ii);
        println!("Recieved {}", rx.recv());
    }

    println!("go!");
}
<commit_msg>double up<commit_after>//extern crate native;

use std::comm;
use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

fn subtx(ii: uint, interval: Duration, task_tx: Sender<uint>) {
    task_tx.send(ii);
    timer::sleep(interval);
    println!("task {} is done", ii);
}

fn main() {
    let (tx, rx): (Sender<uint>, Receiver<uint>) = comm::channel();
    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(500);
    let tictoc: Receiver<()> = timer.periodic(interval);

    for ii in range(0u, 10) {
        let interval = Duration::milliseconds(ii as i64 * 20i64);
        let task_tx = tx.clone(); // clone the Sender
        spawn(proc() {
            subtx(ii, interval, task_tx.clone());
            subtx(ii, interval, task_tx.clone());
        });
    }

    for ii in std::iter::range_step(10i, 0, -1) {
        tictoc.recv();
        println!("{}", ii);
        println!("Recieved {}", rx.recv());
    }

    println!("go!");
}
<|endoftext|>


<commit_before>use na::Real;
use pipeline::broad_phase::BroadPhasePairFilter;
use pipeline::world::CollisionObject;

const SELF_COLLISION: u32 = 1 << 31;
const ALL_GROUPS: u32 = (1 << 30) - 1;
const NO_GROUP: u32 = 0;

/// Groups of collision used to filter which object interact with which other one.
///
/// There are at most 30 groups indexed from 0 to 29 (included). This identifies collidable
/// entities by combining three attributes:
///    * A set of group this structure is member of.
///    * A collision group whitelist.
///    * A collision group blacklist.
///
/// For two entities to interact, they must be member of at least one group part of each-other's
/// whitelists, and must not be part of any blacklisted group. The blacklist always has priority on
/// the whitelist.
///
/// ### Example
/// For example if the object A is such that:
///    * It is part of the groups 1, 3, and 6.
///    * It whitelists the groups 6 and 7.
///    * It blacklists the group 1.
/// Let the object B be such that:
///    * It is part of the groups 1, 3, and 7.
///    * It whitelists the groups 3 and 7.
///    * It does not blacklist anything.
/// For example if the object C is such that:
///    * It is part of the groups 6 and 9.
///    * It whitelists the groups 3 and 7.
///    * It does not blacklist anything.
///
/// Then we have:
///    * A and C can interact because A whitelists the group 6 (which C is part of), and,
///    reciprocally, C whitelists the group 3 (which A is part of).
///    * A and B will **not** interact because B is part of the group 1 which is blacklisted by A.
///    * Finally, B and C will **not** interact either because, even if C whitelists the group 3
///    (which B is part of), B does not whitelists the groups 6 nor 9 (which B is part of).
#[derive(Clone, Debug, Copy)]
pub struct CollisionGroups {
    membership: u32,
    whitelist: u32,
    blacklist: u32,
}

impl CollisionGroups {
    /// Creates a new `CollisionGroups` that enables interactions with everything except
    /// self-interaction.
    #[inline]
    pub fn new() -> CollisionGroups {
        CollisionGroups {
            membership: ALL_GROUPS,
            whitelist: ALL_GROUPS,
            blacklist: NO_GROUP,
        }
    }

    /// The maximum allowed group identifier.
    #[inline]
    pub fn max_group_id() -> usize {
        29
    }

    #[inline]
    fn modify_mask(mask: &mut u32, group_id: usize, add: bool) {
        assert!(
            group_id < 30,
            "There are at most 30 groups indexed from 0 to 29 (included)."
        );

        if add {
            *mask = *mask | (1 << group_id)
        } else {
            *mask = *mask & !(1 << group_id)
        }
    }

    #[inline]
    fn set_mask(mask: &mut u32, groups: &[usize]) {
        *mask = 0;
        for g in groups.iter() {
            CollisionGroups::modify_mask(mask, *g, true);
        }
    }

    /// Adds or removes this entity from the given group.
    #[inline]
    pub fn modify_membership(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.membership, group_id, add);
    }

    /// Adds or removes the given group from this entity whitelist.
    #[inline]
    pub fn modify_whitelist(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.whitelist, group_id, add);
    }

    /// Adds or removes this entity from the given group.
    #[inline]
    pub fn modify_blacklist(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.blacklist, group_id, add);
    }

    /// Make this object member of the given groups only.
    #[inline]
    pub fn set_membership(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.membership, groups);
    }

    /// Whitelists the given groups only (others will be un-whitelisted).
    #[inline]
    pub fn set_whitelist(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.whitelist, groups);
    }

    /// Blacklists the given groups only (others will be un-blacklisted).
    #[inline]
    pub fn set_blacklist(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.blacklist, groups);
    }

    /// Copies the membership of another collision groups.
    #[inline]
    pub fn copy_membership(&mut self, other: &CollisionGroups) {
        self.membership = other.membership
    }

    /// Copies the whitelist of another collision groups.
    #[inline]
    pub fn copy_whitelist(&mut self, other: &CollisionGroups) {
        self.whitelist = other.whitelist
    }

    /// Copies the blacklist of another collision groups.
    #[inline]
    pub fn copy_blacklist(&mut self, other: &CollisionGroups) {
        self.blacklist = other.blacklist
    }

    /// Allows the object to interact with itself.
    #[inline]
    pub fn enable_self_interaction(&mut self) {
        self.whitelist = self.whitelist | SELF_COLLISION;
    }

    /// Prevents the object from interacting with itself.
    #[inline]
    pub fn disable_self_interaction(&mut self) {
        self.whitelist = self.whitelist & !SELF_COLLISION;
    }

    #[inline]
    fn is_inside_mask(mask: u32, group_id: usize) -> bool {
        assert!(
            group_id < 30,
            "There are at most 30 groups indexed from 0 to 29 (included)."
        );
        mask & (1 << group_id) != 0
    }

    /// Tests if this entity is part of the given group.
    #[inline]
    pub fn is_member_of(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.membership, group_id)
    }

    /// Tests if the given group is whitelisted.
    #[inline]
    pub fn is_group_whitelisted(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.whitelist, group_id)
    }

    /// Tests if the given group is blacklisted.
    #[inline]
    pub fn is_group_blacklisted(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.blacklist, group_id)
    }

    /// Tests whether interactinos with a given group is possible.
    ///
    /// Collision is possible if `group_id` is whitelisted but not blacklisted.
    #[inline]
    pub fn can_interact_with(&self, group_id: usize) -> bool {
        !CollisionGroups::is_inside_mask(self.blacklist, group_id)
            && CollisionGroups::is_inside_mask(self.whitelist, group_id)
    }

    /// Tests whether two collision groups have at least one group in common.
    #[inline]
    pub fn can_interact_with_groups(&self, other: &CollisionGroups) -> bool {
        // FIXME: is there a more bitwise-y way of doing this?
        self.membership & other.blacklist == 0 && other.membership & self.blacklist == 0
            && self.membership & other.whitelist != 0
            && other.membership & self.whitelist != 0
    }

    /// Tests whether self-interaction is enabled.
    #[inline]
    pub fn can_interact_with_self(&self) -> bool {
        self.whitelist & SELF_COLLISION != 0
    }
}

/// A collision filter based collision groups.
pub struct CollisionGroupsPairFilter;

impl CollisionGroupsPairFilter {
    /// Creates a new collision filter based collision groups.
    #[inline]
    pub fn new() -> CollisionGroupsPairFilter {
        CollisionGroupsPairFilter
    }
}

impl<N: Real, T> BroadPhasePairFilter<N, T> for CollisionGroupsPairFilter {
    fn is_pair_valid(
        &self,
        co1: &CollisionObject<N, T>,
        co2: &CollisionObject<N, T>,
    ) -> bool {
        let id1 = co1 as *const CollisionObject<N, T> as usize;
        let id2 = co2 as *const CollisionObject<N, T> as usize;

        if id1 == id2 {
            co1.collision_groups().can_interact_with_self()
        } else {
            co1.collision_groups()
                .can_interact_with_groups(co2.collision_groups())
        }
    }
}
<commit_msg>Is collision objects handle (instead of pointers) for comparing if two are equal.<commit_after>use na::Real;
use pipeline::broad_phase::BroadPhasePairFilter;
use pipeline::world::CollisionObject;

const SELF_COLLISION: u32 = 1 << 31;
const ALL_GROUPS: u32 = (1 << 30) - 1;
const NO_GROUP: u32 = 0;

/// Groups of collision used to filter which object interact with which other one.
///
/// There are at most 30 groups indexed from 0 to 29 (included). This identifies collidable
/// entities by combining three attributes:
///    * A set of group this structure is member of.
///    * A collision group whitelist.
///    * A collision group blacklist.
///
/// For two entities to interact, they must be member of at least one group part of each-other's
/// whitelists, and must not be part of any blacklisted group. The blacklist always has priority on
/// the whitelist.
///
/// ### Example
/// For example if the object A is such that:
///    * It is part of the groups 1, 3, and 6.
///    * It whitelists the groups 6 and 7.
///    * It blacklists the group 1.
/// Let the object B be such that:
///    * It is part of the groups 1, 3, and 7.
///    * It whitelists the groups 3 and 7.
///    * It does not blacklist anything.
/// For example if the object C is such that:
///    * It is part of the groups 6 and 9.
///    * It whitelists the groups 3 and 7.
///    * It does not blacklist anything.
///
/// Then we have:
///    * A and C can interact because A whitelists the group 6 (which C is part of), and,
///    reciprocally, C whitelists the group 3 (which A is part of).
///    * A and B will **not** interact because B is part of the group 1 which is blacklisted by A.
///    * Finally, B and C will **not** interact either because, even if C whitelists the group 3
///    (which B is part of), B does not whitelists the groups 6 nor 9 (which B is part of).
#[derive(Clone, Debug, Copy)]
pub struct CollisionGroups {
    membership: u32,
    whitelist: u32,
    blacklist: u32,
}

impl CollisionGroups {
    /// Creates a new `CollisionGroups` that enables interactions with everything except
    /// self-interaction.
    #[inline]
    pub fn new() -> CollisionGroups {
        CollisionGroups {
            membership: ALL_GROUPS,
            whitelist: ALL_GROUPS,
            blacklist: NO_GROUP,
        }
    }

    /// The maximum allowed group identifier.
    #[inline]
    pub fn max_group_id() -> usize {
        29
    }

    #[inline]
    fn modify_mask(mask: &mut u32, group_id: usize, add: bool) {
        assert!(
            group_id < 30,
            "There are at most 30 groups indexed from 0 to 29 (included)."
        );

        if add {
            *mask = *mask | (1 << group_id)
        } else {
            *mask = *mask & !(1 << group_id)
        }
    }

    #[inline]
    fn set_mask(mask: &mut u32, groups: &[usize]) {
        *mask = 0;
        for g in groups.iter() {
            CollisionGroups::modify_mask(mask, *g, true);
        }
    }

    /// Adds or removes this entity from the given group.
    #[inline]
    pub fn modify_membership(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.membership, group_id, add);
    }

    /// Adds or removes the given group from this entity whitelist.
    #[inline]
    pub fn modify_whitelist(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.whitelist, group_id, add);
    }

    /// Adds or removes this entity from the given group.
    #[inline]
    pub fn modify_blacklist(&mut self, group_id: usize, add: bool) {
        CollisionGroups::modify_mask(&mut self.blacklist, group_id, add);
    }

    /// Make this object member of the given groups only.
    #[inline]
    pub fn set_membership(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.membership, groups);
    }

    /// Whitelists the given groups only (others will be un-whitelisted).
    #[inline]
    pub fn set_whitelist(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.whitelist, groups);
    }

    /// Blacklists the given groups only (others will be un-blacklisted).
    #[inline]
    pub fn set_blacklist(&mut self, groups: &[usize]) {
        CollisionGroups::set_mask(&mut self.blacklist, groups);
    }

    /// Copies the membership of another collision groups.
    #[inline]
    pub fn copy_membership(&mut self, other: &CollisionGroups) {
        self.membership = other.membership
    }

    /// Copies the whitelist of another collision groups.
    #[inline]
    pub fn copy_whitelist(&mut self, other: &CollisionGroups) {
        self.whitelist = other.whitelist
    }

    /// Copies the blacklist of another collision groups.
    #[inline]
    pub fn copy_blacklist(&mut self, other: &CollisionGroups) {
        self.blacklist = other.blacklist
    }

    /// Allows the object to interact with itself.
    #[inline]
    pub fn enable_self_interaction(&mut self) {
        self.whitelist = self.whitelist | SELF_COLLISION;
    }

    /// Prevents the object from interacting with itself.
    #[inline]
    pub fn disable_self_interaction(&mut self) {
        self.whitelist = self.whitelist & !SELF_COLLISION;
    }

    #[inline]
    fn is_inside_mask(mask: u32, group_id: usize) -> bool {
        assert!(
            group_id < 30,
            "There are at most 30 groups indexed from 0 to 29 (included)."
        );
        mask & (1 << group_id) != 0
    }

    /// Tests if this entity is part of the given group.
    #[inline]
    pub fn is_member_of(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.membership, group_id)
    }

    /// Tests if the given group is whitelisted.
    #[inline]
    pub fn is_group_whitelisted(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.whitelist, group_id)
    }

    /// Tests if the given group is blacklisted.
    #[inline]
    pub fn is_group_blacklisted(&self, group_id: usize) -> bool {
        CollisionGroups::is_inside_mask(self.blacklist, group_id)
    }

    /// Tests whether interactinos with a given group is possible.
    ///
    /// Collision is possible if `group_id` is whitelisted but not blacklisted.
    #[inline]
    pub fn can_interact_with(&self, group_id: usize) -> bool {
        !CollisionGroups::is_inside_mask(self.blacklist, group_id)
            && CollisionGroups::is_inside_mask(self.whitelist, group_id)
    }

    /// Tests whether two collision groups have at least one group in common.
    #[inline]
    pub fn can_interact_with_groups(&self, other: &CollisionGroups) -> bool {
        // FIXME: is there a more bitwise-y way of doing this?
        self.membership & other.blacklist == 0 && other.membership & self.blacklist == 0
            && self.membership & other.whitelist != 0
            && other.membership & self.whitelist != 0
    }

    /// Tests whether self-interaction is enabled.
    #[inline]
    pub fn can_interact_with_self(&self) -> bool {
        self.whitelist & SELF_COLLISION != 0
    }
}

/// A collision filter based collision groups.
pub struct CollisionGroupsPairFilter;

impl CollisionGroupsPairFilter {
    /// Creates a new collision filter based collision groups.
    #[inline]
    pub fn new() -> CollisionGroupsPairFilter {
        CollisionGroupsPairFilter
    }
}

impl<N: Real, T> BroadPhasePairFilter<N, T> for CollisionGroupsPairFilter {
    fn is_pair_valid(
        &self,
        co1: &CollisionObject<N, T>,
        co2: &CollisionObject<N, T>,
    ) -> bool {
        if co1.handle() == co2.handle() {
            co1.collision_groups().can_interact_with_self()
        } else {
            co1.collision_groups()
                .can_interact_with_groups(co2.collision_groups())
        }
    }
}
<|endoftext|>


<commit_before>extern crate proc_macro;

use quote::{quote, ToTokens};
use std::borrow::Cow;
use synstructure::{decl_derive, Structure, VariantInfo};

fn discriminant_attr(v: &VariantInfo) -> Option<syn::Expr> {
    v.ast().attrs.iter().find_map(|attr| match attr {
        syn::Attribute {
            style: syn::AttrStyle::Outer,
            path,
            ..
        } if path.is_ident("wasmbin") => {
            syn::custom_keyword!(discriminant);

            Some(
                attr.parse_args_with(|parser: syn::parse::ParseStream| {
                    parser.parse::<discriminant>()?;
                    parser.parse::<syn::Token![=]>()?;
                    parser.parse()
                })
                .unwrap(),
            )
        }
        _ => None,
    })
}

fn gen_encode_discriminant(discriminant: &syn::Expr) -> proc_macro2::TokenStream {
    quote!(<u8 as WasmbinEncode>::encode(&#discriminant, w)?)
}

fn gen_decode(v: &VariantInfo) -> proc_macro2::TokenStream {
    v.construct(|_, _| quote!(WasmbinDecode::decode(r)?))
}

fn wasmbin_derive(s: Structure) -> proc_macro2::TokenStream {
    let (encode_discriminant, decode) = match s.ast().data {
        syn::Data::Enum(_) => {
            if !s.ast().attrs.iter().any(|attr| {
                attr.path.is_ident("repr")
                    && attr
                        .parse_args::<syn::Ident>()
                        .map_or(false, |ident| ident == "u8")
            }) {
                panic!("Wasmbin enums must use #[repr(u8)].");
            }

            let mut encode_discriminant = quote!();

            let mut decoders = quote!();
            let mut decode_other = quote!({ return Ok(None) });

            for v in s.variants() {
                let discriminant = v
                    .ast()
                    .discriminant
                    .as_ref()
                    .map(|(_, discriminant)| Cow::Borrowed(discriminant))
                    .or_else(|| discriminant_attr(v).map(Cow::Owned));

                match discriminant {
                    Some(discriminant) => {
                        let pat = v.pat();

                        let encode = gen_encode_discriminant(&discriminant);
                        (quote!(#pat => #encode,)).to_tokens(&mut encode_discriminant);

                        let construct = gen_decode(v);
                        (quote!(#discriminant => #construct,)).to_tokens(&mut decoders);
                    }
                    None => {
                        let fields = v.ast().fields;
                        assert_eq!(
                            fields.len(),
                            1,
                            "Single field is required for catch-all discriminants."
                        );
                        let field = fields.iter().next().unwrap();
                        let construct = match &field.ident {
                            Some(ident) => quote!({ #ident: res }),
                            None => quote!((res)),
                        };
                        let variant_name = v.ast().ident;
                        decode_other = quote! {
                            if let Some(res) = WasmbinDecodeWithDiscriminant::maybe_decode_with_discriminant(discriminant, r)? {
                                Self::#variant_name #construct
                            } else #decode_other
                        };
                    }
                }
            }

            (
                quote! {
                    match *self {
                        #encode_discriminant
                        _ => {}
                    }
                },
                quote! {
                    gen impl WasmbinDecodeWithDiscriminant for @Self {
                        fn maybe_decode_with_discriminant(discriminant: u8, r: &mut impl std::io::Read) -> Result<Option<Self>, DecodeError> {
                            Ok(Some(match discriminant {
                                #decoders
                                _ => #decode_other
                            }))
                        }
                    }

                    gen impl WasmbinDecode for @Self {
                        fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
                            WasmbinDecodeWithDiscriminant::decode(r)
                        }
                    }
                },
            )
        }
        _ => {
            let variants = s.variants();
            assert_eq!(variants.len(), 1);
            let v = &variants[0];
            let decode = gen_decode(v);
            match discriminant_attr(v) {
                Some(discriminant) => (
                    gen_encode_discriminant(&discriminant),
                    quote! {
                        gen impl WasmbinDecodeWithDiscriminant for @Self {
                            fn maybe_decode_with_discriminant(discriminant: u8, r: &mut impl std::io::Read) -> Result<Option<Self>, DecodeError> {
                                Ok(match discriminant {
                                    #discriminant => Some(#decode),
                                    _ => None
                                })
                            }
                        }

                        gen impl WasmbinDecode for @Self {
                            fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
                                WasmbinDecodeWithDiscriminant::decode(r)
                            }
                        }
                    },
                ),
                None => (
                    quote! {},
                    quote! {
                        gen impl WasmbinDecode for @Self {
                            fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
                                Ok(#decode)
                            }
                        }
                    },
                ),
            }
        }
    };

    let encode_body = s.each(|bi| {
        quote! {
            WasmbinEncode::encode(#bi, w)?
        }
    });

    s.gen_impl(quote! {
        use crate::{WasmbinEncode, WasmbinDecode, WasmbinDecodeWithDiscriminant, DecodeError};

        gen impl WasmbinEncode for @Self {
            fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
                #encode_discriminant;
                match *self { #encode_body }
                Ok(())
            }
        }

        #decode
    })
}

fn wasmbin_countable_derive(s: Structure) -> proc_macro2::TokenStream {
    s.gen_impl(quote! {
        gen impl crate::WasmbinCountable for @Self {}
    })
}

#[proc_macro_attribute]
pub fn wasmbin_discriminants(
    _attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let mut input: syn::DeriveInput = syn::parse(input).unwrap();
    let e = match &mut input.data {
        syn::Data::Enum(e) => e,
        _ => panic!("This attribute can only be used on enums"),
    };
    let mut seen_non_units = false;
    for v in &mut e.variants {
        match v.fields {
            syn::Fields::Unit => {}
            _ => seen_non_units = true,
        }
        #[cfg(not(feature = "nightly"))]
        {
            if let Some((_, discriminant)) = v.discriminant.take() {
                v.attrs
                    .push(syn::parse_quote!(#[wasmbin(discriminant = #discriminant)]));
            }
        }
    }
    assert!(
        seen_non_units,
        "Attribute shouldn't be used on C-like enums"
    );
    input.into_token_stream().into()
}

decl_derive!([Wasmbin, attributes(wasmbin)] => wasmbin_derive);
decl_derive!([WasmbinCountable] => wasmbin_countable_derive);
<commit_msg>Add error handling to derive<commit_after>extern crate proc_macro;

use quote::{quote, ToTokens};
use std::borrow::Cow;
use synstructure::{decl_derive, Structure, VariantInfo};

macro_rules! syn_throw {
    ($err:expr) => {
        return syn::Error::to_compile_error(&$err)
    };
}

macro_rules! syn_try {
    ($expr:expr) => {
        match $expr {
            Ok(expr) => expr,
            Err(err) => syn_throw!(err),
        }
    };
}

fn discriminant<'v>(v: &VariantInfo<'v>) -> syn::Result<Option<Cow<'v, syn::Expr>>> {
    v.ast()
        .discriminant
        .iter()
        .map(|(_, discriminant)| Ok(Cow::Borrowed(discriminant)))
        .chain(v.ast().attrs.iter().filter_map(|attr| match attr {
            syn::Attribute {
                style: syn::AttrStyle::Outer,
                path,
                ..
            } if path.is_ident("wasmbin") => {
                syn::custom_keyword!(discriminant);

                Some(
                    attr.parse_args_with(|parser: syn::parse::ParseStream| {
                        parser.parse::<discriminant>()?;
                        parser.parse::<syn::Token![=]>()?;
                        parser.parse()
                    })
                    .map(Cow::Owned),
                )
            }
            _ => None,
        }))
        .try_fold(None, |prev, discriminant| {
            let discriminant = discriminant?;
            if let Some(prev) = prev {
                let mut err = syn::Error::new_spanned(discriminant, "#[derive(Wasmbin)]: duplicate discriminant");
                err.combine(syn::Error::new_spanned(prev, "#[derive(Wasmbin)]: previous discriminant here"));
                return Err(err);
            }
            Ok(Some(discriminant))
        })
}

fn gen_encode_discriminant(discriminant: &syn::Expr) -> proc_macro2::TokenStream {
    quote!(<u8 as WasmbinEncode>::encode(&#discriminant, w)?)
}

fn gen_decode(v: &VariantInfo) -> proc_macro2::TokenStream {
    v.construct(|_, _| quote!(WasmbinDecode::decode(r)?))
}

fn wasmbin_derive(s: Structure) -> proc_macro2::TokenStream {
    let (encode_discriminant, decode) = match s.ast().data {
        syn::Data::Enum(_) => {
            if !s.ast().attrs.iter().any(|attr| {
                attr.path.is_ident("repr")
                    && attr
                        .parse_args::<syn::Ident>()
                        .map_or(false, |ident| ident == "u8")
            }) {
                panic!("Wasmbin enums must use #[repr(u8)].");
            }

            let mut encode_discriminant = quote!();

            let mut decoders = quote!();
            let mut decode_other = quote!({ return Ok(None) });

            for v in s.variants() {
                let discriminant = syn_try!(discriminant(v));

                match discriminant {
                    Some(discriminant) => {
                        let pat = v.pat();

                        let encode = gen_encode_discriminant(&discriminant);
                        (quote!(#pat => #encode,)).to_tokens(&mut encode_discriminant);

                        let construct = gen_decode(v);
                        (quote!(#discriminant => #construct,)).to_tokens(&mut decoders);
                    }
                    None => {
                        let fields = v.ast().fields;
                        if fields.len() != 1 {
                            syn_throw!(syn::Error::new_spanned(fields, "Catch-all variants without discriminant must have a single field."));
                        }
                        let field = fields.iter().next().unwrap();
                        let construct = match &field.ident {
                            Some(ident) => quote!({ #ident: res }),
                            None => quote!((res)),
                        };
                        let variant_name = v.ast().ident;
                        decode_other = quote! {
                            if let Some(res) = WasmbinDecodeWithDiscriminant::maybe_decode_with_discriminant(discriminant, r)? {
                                Self::#variant_name #construct
                            } else #decode_other
                        };
                    }
                }
            }

            (
                quote! {
                    match *self {
                        #encode_discriminant
                        _ => {}
                    }
                },
                quote! {
                    gen impl WasmbinDecodeWithDiscriminant for @Self {
                        fn maybe_decode_with_discriminant(discriminant: u8, r: &mut impl std::io::Read) -> Result<Option<Self>, DecodeError> {
                            Ok(Some(match discriminant {
                                #decoders
                                _ => #decode_other
                            }))
                        }
                    }

                    gen impl WasmbinDecode for @Self {
                        fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
                            WasmbinDecodeWithDiscriminant::decode(r)
                        }
                    }
                },
            )
        }
        _ => {
            let variants = s.variants();
            assert_eq!(variants.len(), 1);
            let v = &variants[0];
            let decode = gen_decode(v);
            match syn_try!(discriminant(v)) {
                Some(discriminant) => (
                    gen_encode_discriminant(&discriminant),
                    quote! {
                        gen impl WasmbinDecodeWithDiscriminant for @Self {
                            fn maybe_decode_with_discriminant(discriminant: u8, r: &mut impl std::io::Read) -> Result<Option<Self>, DecodeError> {
                                Ok(match discriminant {
                                    #discriminant => Some(#decode),
                                    _ => None
                                })
                            }
                        }

                        gen impl WasmbinDecode for @Self {
                            fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
                                WasmbinDecodeWithDiscriminant::decode(r)
                            }
                        }
                    },
                ),
                None => (
                    quote! {},
                    quote! {
                        gen impl WasmbinDecode for @Self {
                            fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
                                Ok(#decode)
                            }
                        }
                    },
                ),
            }
        }
    };

    let encode_body = s.each(|bi| {
        quote! {
            WasmbinEncode::encode(#bi, w)?
        }
    });

    s.gen_impl(quote! {
        use crate::{WasmbinEncode, WasmbinDecode, WasmbinDecodeWithDiscriminant, DecodeError};

        gen impl WasmbinEncode for @Self {
            fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
                #encode_discriminant;
                match *self { #encode_body }
                Ok(())
            }
        }

        #decode
    })
}

fn wasmbin_countable_derive(s: Structure) -> proc_macro2::TokenStream {
    s.gen_impl(quote! {
        gen impl crate::WasmbinCountable for @Self {}
    })
}

#[proc_macro_attribute]
pub fn wasmbin_discriminants(
    _attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let mut input: syn::DeriveInput = syn::parse(input).unwrap();
    let e = match &mut input.data {
        syn::Data::Enum(e) => e,
        _ => panic!("This attribute can only be used on enums"),
    };
    let mut seen_non_units = false;
    for v in &mut e.variants {
        match v.fields {
            syn::Fields::Unit => {}
            _ => seen_non_units = true,
        }
        #[cfg(not(feature = "nightly"))]
        {
            if let Some((_, discriminant)) = v.discriminant.take() {
                v.attrs
                    .push(syn::parse_quote!(#[wasmbin(discriminant = #discriminant)]));
            }
        }
    }
    assert!(
        seen_non_units,
        "Attribute shouldn't be used on C-like enums"
    );
    input.into_token_stream().into()
}

decl_derive!([Wasmbin, attributes(wasmbin)] => wasmbin_derive);
decl_derive!([WasmbinCountable] => wasmbin_countable_derive);
<|endoftext|>


<commit_before><commit_msg>Don't bypass cleanup logic in clear_namespace().<commit_after><|endoftext|>


<commit_before>#[cfg(windows)]
pub mod windows_child;

#[allow(unused_variables)]
#[cfg(windows)]
mod windows;

#[cfg(unix)]
mod unix;

#[cfg(unix)]
pub(crate) use self::unix::SignalCode;
#[cfg(unix)]
pub use self::unix::{become_command,
                     current_pid,
                     is_alive,
                     signal,
                     Pid};
#[cfg(windows)]
pub use self::windows::{become_command,
                        current_pid,
                        handle_from_pid,
                        is_alive,
                        terminate,
                        Pid};
use crate::{error::Error,
            util};
use serde_derive::{Deserialize,
                   Serialize};
use std::{fmt,
          result,
          str::FromStr,
          time::Duration};

/// This type encapsulates the number of seconds we should wait after
/// send a shutdown signal to a process before we kill it.
#[derive(Deserialize, Serialize, Eq, PartialEq, Debug, Clone, Copy, Hash)]
#[serde(from = "u32", into = "u32")]
pub struct ShutdownTimeout(u32);

impl Default for ShutdownTimeout {
    /// Unless otherwise specified, the Supervisor will wait 8 seconds
    /// for a service to finish shutting down before killing it.
    fn default() -> Self { 8.into() }
}

impl FromStr for ShutdownTimeout {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(ShutdownTimeout(s.parse()?)) }
}

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

impl From<u32> for ShutdownTimeout {
    fn from(seconds: u32) -> Self { ShutdownTimeout(seconds) }
}

impl From<ShutdownTimeout> for u32 {
    fn from(timeout: ShutdownTimeout) -> Self { timeout.0 }
}

impl From<ShutdownTimeout> for Duration {
    fn from(timeout: ShutdownTimeout) -> Self { Duration::from_secs(timeout.0.into()) }
}

// This defines a handful of Unix signals that we want to deal with,
// but we are making it available on Windows as well for situations
// where a Windows CLI is communicating with a Linux Supervisor.
#[allow(non_snake_case)]
#[derive(Deserialize, Serialize, PartialEq, Debug, Clone, Copy)]
pub enum Signal {
    INT,
    ILL,
    ABRT,
    FPE,
    KILL,
    SEGV,
    TERM,
    HUP,
    QUIT,
    ALRM,
    USR1,
    USR2,
    CHLD,
}

impl FromStr for Signal {
    type Err = Error;

    fn from_str(s: &str) -> result::Result<Self, Self::Err> {
        let signal = match s {
            "HUP" => Signal::HUP,
            "INT" => Signal::INT,
            "QUIT" => Signal::QUIT,
            "ILL" => Signal::ILL,
            "ABRT" => Signal::ABRT,
            "FPE" => Signal::FPE,
            "KILL" => Signal::KILL,
            "USR1" => Signal::USR1,
            "SEGV" => Signal::SEGV,
            "USR2" => Signal::USR2,
            "ALRM" => Signal::ALRM,
            "TERM" => Signal::TERM,
            "CHLD" => Signal::CHLD,
            _ => return Err(Error::ParseSignalError(s.to_string())),
        };
        Ok(signal)
    }
}

impl fmt::Display for Signal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            Signal::HUP => "HUP",
            Signal::INT => "INT",
            Signal::QUIT => "QUIT",
            Signal::ILL => "ILL",
            Signal::ABRT => "ABRT",
            Signal::FPE => "FPE",
            Signal::KILL => "KILL",
            Signal::USR1 => "USR1",
            Signal::SEGV => "SEGV",
            Signal::USR2 => "USR2",
            Signal::ALRM => "ALRM",
            Signal::TERM => "TERM",
            Signal::CHLD => "CHLD",
        };
        write!(f, "{}", s)
    }
}

/// Encapsulates logic for defining the default shutdown signal we
/// send services, and handles translation from external types at the
/// edges of our system.
#[derive(Deserialize, Serialize, Debug, Clone, Copy)]
pub struct ShutdownSignal(#[serde(with = "util::serde::string")] Signal);

impl Default for ShutdownSignal {
    /// Unless otherwise specified, the Supervisor will shut down
    /// services by sending the `TERM` signal.
    fn default() -> Self { Signal::TERM.into() }
}

impl FromStr for ShutdownSignal {
    type Err = Error;

    fn from_str(s: &str) -> result::Result<Self, Self::Err> { Ok(ShutdownSignal(s.parse()?)) }
}

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

impl From<Signal> for ShutdownSignal {
    fn from(signal: Signal) -> Self { ShutdownSignal(signal) }
}

impl From<ShutdownSignal> for Signal {
    fn from(shutdown_signal: ShutdownSignal) -> Self { shutdown_signal.0 }
}

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

    #[test]
    fn signal_names_are_only_accepted_as_uppercase() {
        assert_eq!(Signal::HUP, "HUP".parse().unwrap());
        assert!("hup".parse::<Signal>().is_err());
    }

    #[test]
    fn signals_can_render_as_strings() {
        assert_eq!("HUP", Signal::HUP.to_string());
    }

    #[test]
    fn signals_can_round_trip_through_parsing() {
        for signal in &[Signal::HUP,
                        Signal::INT,
                        Signal::QUIT,
                        Signal::ABRT,
                        Signal::FPE,
                        Signal::KILL,
                        Signal::USR1,
                        Signal::SEGV,
                        Signal::USR2,
                        Signal::ALRM,
                        Signal::TERM,
                        Signal::CHLD]
        {
            assert_eq!(*signal,
                       signal.to_string()
                             .parse::<Signal>()
                             .expect("Couldn't parse back into a Signal!"));
        }
    }
}
<commit_msg>[REFACTOR] Clarify process module interface<commit_after>#[cfg(windows)]
pub mod windows_child;

#[allow(unused_variables)]
#[cfg(windows)]
mod windows;
#[cfg(windows)]
use windows as implementation;

#[cfg(unix)]
mod unix;
#[cfg(unix)]
use unix as implementation;

// Common platform-independent interface
pub use implementation::{become_command,
                         current_pid,
                         is_alive,
                         Pid};

#[cfg(unix)]
pub use unix::signal;
#[cfg(unix)]
pub(crate) use unix::SignalCode;

#[cfg(windows)]
pub use windows::{handle_from_pid,
                  terminate};

use crate::{error::Error,
            util};
use serde_derive::{Deserialize,
                   Serialize};
use std::{fmt,
          result,
          str::FromStr,
          time::Duration};

/// This type encapsulates the number of seconds we should wait after
/// send a shutdown signal to a process before we kill it.
#[derive(Deserialize, Serialize, Eq, PartialEq, Debug, Clone, Copy, Hash)]
#[serde(from = "u32", into = "u32")]
pub struct ShutdownTimeout(u32);

impl Default for ShutdownTimeout {
    /// Unless otherwise specified, the Supervisor will wait 8 seconds
    /// for a service to finish shutting down before killing it.
    fn default() -> Self { 8.into() }
}

impl FromStr for ShutdownTimeout {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(ShutdownTimeout(s.parse()?)) }
}

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

impl From<u32> for ShutdownTimeout {
    fn from(seconds: u32) -> Self { ShutdownTimeout(seconds) }
}

impl From<ShutdownTimeout> for u32 {
    fn from(timeout: ShutdownTimeout) -> Self { timeout.0 }
}

impl From<ShutdownTimeout> for Duration {
    fn from(timeout: ShutdownTimeout) -> Self { Duration::from_secs(timeout.0.into()) }
}

// This defines a handful of Unix signals that we want to deal with,
// but we are making it available on Windows as well for situations
// where a Windows CLI is communicating with a Linux Supervisor.
#[allow(non_snake_case)]
#[derive(Deserialize, Serialize, PartialEq, Debug, Clone, Copy)]
pub enum Signal {
    INT,
    ILL,
    ABRT,
    FPE,
    KILL,
    SEGV,
    TERM,
    HUP,
    QUIT,
    ALRM,
    USR1,
    USR2,
    CHLD,
}

impl FromStr for Signal {
    type Err = Error;

    fn from_str(s: &str) -> result::Result<Self, Self::Err> {
        let signal = match s {
            "HUP" => Signal::HUP,
            "INT" => Signal::INT,
            "QUIT" => Signal::QUIT,
            "ILL" => Signal::ILL,
            "ABRT" => Signal::ABRT,
            "FPE" => Signal::FPE,
            "KILL" => Signal::KILL,
            "USR1" => Signal::USR1,
            "SEGV" => Signal::SEGV,
            "USR2" => Signal::USR2,
            "ALRM" => Signal::ALRM,
            "TERM" => Signal::TERM,
            "CHLD" => Signal::CHLD,
            _ => return Err(Error::ParseSignalError(s.to_string())),
        };
        Ok(signal)
    }
}

impl fmt::Display for Signal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            Signal::HUP => "HUP",
            Signal::INT => "INT",
            Signal::QUIT => "QUIT",
            Signal::ILL => "ILL",
            Signal::ABRT => "ABRT",
            Signal::FPE => "FPE",
            Signal::KILL => "KILL",
            Signal::USR1 => "USR1",
            Signal::SEGV => "SEGV",
            Signal::USR2 => "USR2",
            Signal::ALRM => "ALRM",
            Signal::TERM => "TERM",
            Signal::CHLD => "CHLD",
        };
        write!(f, "{}", s)
    }
}

/// Encapsulates logic for defining the default shutdown signal we
/// send services, and handles translation from external types at the
/// edges of our system.
#[derive(Deserialize, Serialize, Debug, Clone, Copy)]
pub struct ShutdownSignal(#[serde(with = "util::serde::string")] Signal);

impl Default for ShutdownSignal {
    /// Unless otherwise specified, the Supervisor will shut down
    /// services by sending the `TERM` signal.
    fn default() -> Self { Signal::TERM.into() }
}

impl FromStr for ShutdownSignal {
    type Err = Error;

    fn from_str(s: &str) -> result::Result<Self, Self::Err> { Ok(ShutdownSignal(s.parse()?)) }
}

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

impl From<Signal> for ShutdownSignal {
    fn from(signal: Signal) -> Self { ShutdownSignal(signal) }
}

impl From<ShutdownSignal> for Signal {
    fn from(shutdown_signal: ShutdownSignal) -> Self { shutdown_signal.0 }
}

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

    #[test]
    fn signal_names_are_only_accepted_as_uppercase() {
        assert_eq!(Signal::HUP, "HUP".parse().unwrap());
        assert!("hup".parse::<Signal>().is_err());
    }

    #[test]
    fn signals_can_render_as_strings() {
        assert_eq!("HUP", Signal::HUP.to_string());
    }

    #[test]
    fn signals_can_round_trip_through_parsing() {
        for signal in &[Signal::HUP,
                        Signal::INT,
                        Signal::QUIT,
                        Signal::ABRT,
                        Signal::FPE,
                        Signal::KILL,
                        Signal::USR1,
                        Signal::SEGV,
                        Signal::USR2,
                        Signal::ALRM,
                        Signal::TERM,
                        Signal::CHLD]
        {
            assert_eq!(*signal,
                       signal.to_string()
                             .parse::<Signal>()
                             .expect("Couldn't parse back into a Signal!"));
        }
    }
}
<|endoftext|>