<commit_before>use std::collections::VecDeque;
use std::fmt::Debug;
use std::iter::FromIterator;
use std::ops::Deref;
use std::sync::Arc;
use std::thread::sleep;
use std::time::Duration;
use std::time::Instant;

use bazel_protos;
use futures::{Future, Sink};
use grpcio;
use parking_lot::Mutex;
use protobuf;

///
/// A MockOperation to be used with MockExecution.
///
/// If the op is None, the MockExecution will drop the channel, triggering cancelation on the
/// client. If the duration is not None, it represents a delay before either responding or
/// canceling for the operation.
///
#[derive(Clone, Debug)]
pub struct MockOperation {
  pub op:
    Result<Option<bazel_protos::google::longrunning::Operation>, bazel_protos::google::rpc::Status>,
  pub duration: Option<Duration>,
}

impl MockOperation {
  pub fn new(op: bazel_protos::google::longrunning::Operation) -> MockOperation {
    MockOperation {
      op: Ok(Some(op)),
      duration: None,
    }
  }
}

#[derive(Clone, Debug)]
pub struct MockExecution {
  name: String,
  execute_request: bazel_protos::remote_execution::ExecuteRequest,
  operation_responses: Arc<Mutex<VecDeque<MockOperation>>>,
}

impl MockExecution {
  ///
  /// # Arguments:
  ///  * `name` - The name of the operation. It is assumed that all operation_responses use this
  ///             name.
  ///  * `execute_request` - The expected ExecuteRequest.
  ///  * `operation_responses` - Vec of Operation response for Execution or GetOperation requests.
  ///                            Will be returned in order.
  ///
  pub fn new(
    name: String,
    execute_request: bazel_protos::build::bazel::remote::execution::v2::ExecuteRequest,
    operation_responses: Vec<MockOperation>,
  ) -> MockExecution {
    MockExecution {
      name: name,
      execute_request: execute_request.into(),
      operation_responses: Arc::new(Mutex::new(VecDeque::from(operation_responses))),
    }
  }
}

///
/// A server which will answer ExecuteRequest and GetOperation gRPC requests with pre-canned
/// responses.
///
pub struct TestServer {
  pub mock_responder: MockResponder,
  server_transport: grpcio::Server,
}

impl TestServer {
  ///
  /// # Arguments
  /// * `mock_execution` - The canned responses to issue. Returns the MockExecution's
  ///                      operation_responses in order to any ExecuteRequest or GetOperation
  ///                      requests.
  ///                      If an ExecuteRequest request is received which is not equal to this
  ///                      MockExecution's execute_request, an error will be returned.
  ///                      If a GetOperation request is received whose name is not equal to this
  ///                      MockExecution's name, or more requests are received than stub responses
  ///                      are available for, an error will be returned.
  pub fn new(mock_execution: MockExecution) -> TestServer {
    let mock_responder = MockResponder::new(mock_execution);

    let env = Arc::new(grpcio::Environment::new(1));
    let mut server_transport = grpcio::ServerBuilder::new(env)
      .register_service(bazel_protos::remote_execution_grpc::create_execution(
        mock_responder.clone(),
      ))
      .register_service(bazel_protos::operations_grpc::create_operations(
        mock_responder.clone(),
      ))
      .bind("localhost", 0)
      .build()
      .unwrap();
    server_transport.start();

    TestServer {
      mock_responder: mock_responder,
      server_transport,
    }
  }

  ///
  /// The address on which this server is listening over insecure HTTP transport.
  ///
  pub fn address(&self) -> String {
    let bind_addr = self.server_transport.bind_addrs().first().unwrap();
    format!("{}:{}", bind_addr.0, bind_addr.1)
  }
}

impl Drop for TestServer {
  fn drop(&mut self) {
    let remaining_expected_responses = self
      .mock_responder
      .mock_execution
      .operation_responses
      .lock()
      .len();
    assert_eq!(
      remaining_expected_responses,
      0,
      "Expected {} more requests. Remaining expected responses:\n{}\nReceived requests:\n{}",
      remaining_expected_responses,
      MockResponder::display_all(&Vec::from_iter(
        self
          .mock_responder
          .mock_execution
          .operation_responses
          .lock()
          .clone(),
      )),
      MockResponder::display_all(&self.mock_responder.received_messages.deref().lock())
    )
  }
}

#[derive(Debug)]
pub struct ReceivedMessage {
  pub message_type: String,
  pub message: Box<dyn protobuf::Message>,
  pub received_at: Instant,
}

#[derive(Clone, Debug)]
pub struct MockResponder {
  mock_execution: MockExecution,
  pub received_messages: Arc<Mutex<Vec<ReceivedMessage>>>,
}

impl MockResponder {
  fn new(mock_execution: MockExecution) -> MockResponder {
    MockResponder {
      mock_execution: mock_execution,
      received_messages: Arc::new(Mutex::new(vec![])),
    }
  }

  fn log<T: protobuf::Message + Sized>(&self, message: T) {
    self.received_messages.lock().push(ReceivedMessage {
      message_type: message.descriptor().name().to_string(),
      message: Box::new(message),
      received_at: Instant::now(),
    });
  }

  fn display_all<D: Debug>(items: &[D]) -> String {
    items
      .iter()
      .map(|i| format!("{:?}\n", i))
      .collect::<Vec<_>>()
      .concat()
  }

  fn send_next_operation_unary(
    &self,
    sink: grpcio::UnarySink<bazel_protos::operations::Operation>,
  ) {
    if let Some(MockOperation { op, duration }) =
      self.mock_execution.operation_responses.lock().pop_front()
    {
      if let Some(d) = duration {
        sleep(d);
      }
      if let Ok(Some(op)) = op {
        // Complete the channel with the op.
        sink.success(op.clone().into());
      } else if let Err(status) = op {
        sink.fail(status.into());
      } else {
        // Cancel the request by dropping the sink.
        drop(sink);
      }
    } else {
      sink.fail(grpcio::RpcStatus::new(
        grpcio::RpcStatusCode::InvalidArgument,
        Some("Did not expect further requests from client.".to_string()),
      ));
    }
  }

  fn send_next_operation_stream(
    &self,
    ctx: &grpcio::RpcContext<'_>,
    sink: grpcio::ServerStreamingSink<bazel_protos::operations::Operation>,
  ) {
    match self.mock_execution.operation_responses.lock().pop_front() {
      Some(MockOperation { op, duration }) => {
        if let Some(d) = duration {
          sleep(d);
        }
        if let Ok(Some(op)) = op {
          ctx.spawn(
            sink
              .send((op.clone().into(), grpcio::WriteFlags::default()))
              .map(|mut stream| stream.close())
              .map(|_| ())
              .map_err(|_| ()),
          )
        } else if let Err(status) = op {
          sink.fail(status.into());
        } else {
          // Cancel the request by dropping the sink.
          drop(sink)
        }
      }
      None => ctx.spawn(
        sink
          .fail(grpcio::RpcStatus::new(
            grpcio::RpcStatusCode::InvalidArgument,
            Some("Did not expect further requests from client.".to_string()),
          ))
          .map(|_| ())
          .map_err(|_| ()),
      ),
    }
  }
}

impl bazel_protos::remote_execution_grpc::Execution for MockResponder {
  // We currently only support the one-shot "stream and disconnect" client behavior.
  // If we start supporting the "stream updates" variant, we will need to do so here.
  fn execute(
    &self,
    ctx: grpcio::RpcContext<'_>,
    req: bazel_protos::remote_execution::ExecuteRequest,
    sink: grpcio::ServerStreamingSink<bazel_protos::operations::Operation>,
  ) {
    self.log(req.clone());

    if self.mock_execution.execute_request != req {
      ctx.spawn(
        sink
          .fail(grpcio::RpcStatus::new(
            grpcio::RpcStatusCode::InvalidArgument,
            Some("Did not expect this request".to_string()),
          ))
          .map_err(|_| ()),
      );
      return;
    }

    self.send_next_operation_stream(&ctx, sink);
  }

  fn wait_execution(
    &self,
    _ctx: grpcio::RpcContext<'_>,
    _req: bazel_protos::remote_execution::WaitExecutionRequest,
    _sink: grpcio::ServerStreamingSink<bazel_protos::operations::Operation>,
  ) {
    unimplemented!()
  }
}

impl bazel_protos::operations_grpc::Operations for MockResponder {
  fn get_operation(
    &self,
    _: grpcio::RpcContext<'_>,
    req: bazel_protos::operations::GetOperationRequest,
    sink: grpcio::UnarySink<bazel_protos::operations::Operation>,
  ) {
    self.log(req.clone());

    self.send_next_operation_unary(sink)
  }

  fn list_operations(
    &self,
    _: grpcio::RpcContext<'_>,
    _: bazel_protos::operations::ListOperationsRequest,
    sink: grpcio::UnarySink<bazel_protos::operations::ListOperationsResponse>,
  ) {
    sink.fail(grpcio::RpcStatus::new(
      grpcio::RpcStatusCode::Unimplemented,
      None,
    ));
  }

  fn delete_operation(
    &self,
    _: grpcio::RpcContext<'_>,
    _: bazel_protos::operations::DeleteOperationRequest,
    sink: grpcio::UnarySink<bazel_protos::empty::Empty>,
  ) {
    sink.fail(grpcio::RpcStatus::new(
      grpcio::RpcStatusCode::Unimplemented,
      None,
    ));
  }

  fn cancel_operation(
    &self,
    _: grpcio::RpcContext<'_>,
    _: bazel_protos::operations::CancelOperationRequest,
    sink: grpcio::UnarySink<bazel_protos::empty::Empty>,
  ) {
    sink.fail(grpcio::RpcStatus::new(
      grpcio::RpcStatusCode::Unimplemented,
      None,
    ));
  }
}
<commit_msg>Don't re-panic in mock execution server (#7167)<commit_after>use std::collections::VecDeque;
use std::fmt::Debug;
use std::iter::FromIterator;
use std::ops::Deref;
use std::sync::Arc;
use std::thread::sleep;
use std::time::Duration;
use std::time::Instant;

use bazel_protos;
use futures::{Future, Sink};
use grpcio;
use parking_lot::Mutex;
use protobuf;

///
/// A MockOperation to be used with MockExecution.
///
/// If the op is None, the MockExecution will drop the channel, triggering cancelation on the
/// client. If the duration is not None, it represents a delay before either responding or
/// canceling for the operation.
///
#[derive(Clone, Debug)]
pub struct MockOperation {
  pub op:
    Result<Option<bazel_protos::google::longrunning::Operation>, bazel_protos::google::rpc::Status>,
  pub duration: Option<Duration>,
}

impl MockOperation {
  pub fn new(op: bazel_protos::google::longrunning::Operation) -> MockOperation {
    MockOperation {
      op: Ok(Some(op)),
      duration: None,
    }
  }
}

#[derive(Clone, Debug)]
pub struct MockExecution {
  name: String,
  execute_request: bazel_protos::remote_execution::ExecuteRequest,
  operation_responses: Arc<Mutex<VecDeque<MockOperation>>>,
}

impl MockExecution {
  ///
  /// # Arguments:
  ///  * `name` - The name of the operation. It is assumed that all operation_responses use this
  ///             name.
  ///  * `execute_request` - The expected ExecuteRequest.
  ///  * `operation_responses` - Vec of Operation response for Execution or GetOperation requests.
  ///                            Will be returned in order.
  ///
  pub fn new(
    name: String,
    execute_request: bazel_protos::build::bazel::remote::execution::v2::ExecuteRequest,
    operation_responses: Vec<MockOperation>,
  ) -> MockExecution {
    MockExecution {
      name: name,
      execute_request: execute_request.into(),
      operation_responses: Arc::new(Mutex::new(VecDeque::from(operation_responses))),
    }
  }
}

///
/// A server which will answer ExecuteRequest and GetOperation gRPC requests with pre-canned
/// responses.
///
pub struct TestServer {
  pub mock_responder: MockResponder,
  server_transport: grpcio::Server,
}

impl TestServer {
  ///
  /// # Arguments
  /// * `mock_execution` - The canned responses to issue. Returns the MockExecution's
  ///                      operation_responses in order to any ExecuteRequest or GetOperation
  ///                      requests.
  ///                      If an ExecuteRequest request is received which is not equal to this
  ///                      MockExecution's execute_request, an error will be returned.
  ///                      If a GetOperation request is received whose name is not equal to this
  ///                      MockExecution's name, or more requests are received than stub responses
  ///                      are available for, an error will be returned.
  pub fn new(mock_execution: MockExecution) -> TestServer {
    let mock_responder = MockResponder::new(mock_execution);

    let env = Arc::new(grpcio::Environment::new(1));
    let mut server_transport = grpcio::ServerBuilder::new(env)
      .register_service(bazel_protos::remote_execution_grpc::create_execution(
        mock_responder.clone(),
      ))
      .register_service(bazel_protos::operations_grpc::create_operations(
        mock_responder.clone(),
      ))
      .bind("localhost", 0)
      .build()
      .unwrap();
    server_transport.start();

    TestServer {
      mock_responder: mock_responder,
      server_transport,
    }
  }

  ///
  /// The address on which this server is listening over insecure HTTP transport.
  ///
  pub fn address(&self) -> String {
    let bind_addr = self.server_transport.bind_addrs().first().unwrap();
    format!("{}:{}", bind_addr.0, bind_addr.1)
  }
}

impl Drop for TestServer {
  fn drop(&mut self) {
    let remaining_expected_responses = self
      .mock_responder
      .mock_execution
      .operation_responses
      .lock()
      .len();
    if remaining_expected_responses != 0 {
      let message = format!(
        "Expected {} more requests. Remaining expected responses:\n{}\nReceived requests:\n{}",
        remaining_expected_responses,
        MockResponder::display_all(&Vec::from_iter(
          self
            .mock_responder
            .mock_execution
            .operation_responses
            .lock()
            .clone(),
        )),
        MockResponder::display_all(&self.mock_responder.received_messages.deref().lock())
      );
      if std::thread::panicking() {
        eprintln!(
          "TestServer missing requests, but not panicking because caller is already panicking: {}",
          message
        );
      } else {
        assert_eq!(remaining_expected_responses, 0, "{}", message,);
      }
    }
  }
}

#[derive(Debug)]
pub struct ReceivedMessage {
  pub message_type: String,
  pub message: Box<dyn protobuf::Message>,
  pub received_at: Instant,
}

#[derive(Clone, Debug)]
pub struct MockResponder {
  mock_execution: MockExecution,
  pub received_messages: Arc<Mutex<Vec<ReceivedMessage>>>,
}

impl MockResponder {
  fn new(mock_execution: MockExecution) -> MockResponder {
    MockResponder {
      mock_execution: mock_execution,
      received_messages: Arc::new(Mutex::new(vec![])),
    }
  }

  fn log<T: protobuf::Message + Sized>(&self, message: T) {
    self.received_messages.lock().push(ReceivedMessage {
      message_type: message.descriptor().name().to_string(),
      message: Box::new(message),
      received_at: Instant::now(),
    });
  }

  fn display_all<D: Debug>(items: &[D]) -> String {
    items
      .iter()
      .map(|i| format!("{:?}\n", i))
      .collect::<Vec<_>>()
      .concat()
  }

  fn send_next_operation_unary(
    &self,
    sink: grpcio::UnarySink<bazel_protos::operations::Operation>,
  ) {
    if let Some(MockOperation { op, duration }) =
      self.mock_execution.operation_responses.lock().pop_front()
    {
      if let Some(d) = duration {
        sleep(d);
      }
      if let Ok(Some(op)) = op {
        // Complete the channel with the op.
        sink.success(op.clone().into());
      } else if let Err(status) = op {
        sink.fail(status.into());
      } else {
        // Cancel the request by dropping the sink.
        drop(sink);
      }
    } else {
      sink.fail(grpcio::RpcStatus::new(
        grpcio::RpcStatusCode::InvalidArgument,
        Some("Did not expect further requests from client.".to_string()),
      ));
    }
  }

  fn send_next_operation_stream(
    &self,
    ctx: &grpcio::RpcContext<'_>,
    sink: grpcio::ServerStreamingSink<bazel_protos::operations::Operation>,
  ) {
    match self.mock_execution.operation_responses.lock().pop_front() {
      Some(MockOperation { op, duration }) => {
        if let Some(d) = duration {
          sleep(d);
        }
        if let Ok(Some(op)) = op {
          ctx.spawn(
            sink
              .send((op.clone().into(), grpcio::WriteFlags::default()))
              .map(|mut stream| stream.close())
              .map(|_| ())
              .map_err(|_| ()),
          )
        } else if let Err(status) = op {
          sink.fail(status.into());
        } else {
          // Cancel the request by dropping the sink.
          drop(sink)
        }
      }
      None => ctx.spawn(
        sink
          .fail(grpcio::RpcStatus::new(
            grpcio::RpcStatusCode::InvalidArgument,
            Some("Did not expect further requests from client.".to_string()),
          ))
          .map(|_| ())
          .map_err(|_| ()),
      ),
    }
  }
}

impl bazel_protos::remote_execution_grpc::Execution for MockResponder {
  // We currently only support the one-shot "stream and disconnect" client behavior.
  // If we start supporting the "stream updates" variant, we will need to do so here.
  fn execute(
    &self,
    ctx: grpcio::RpcContext<'_>,
    req: bazel_protos::remote_execution::ExecuteRequest,
    sink: grpcio::ServerStreamingSink<bazel_protos::operations::Operation>,
  ) {
    self.log(req.clone());

    if self.mock_execution.execute_request != req {
      ctx.spawn(
        sink
          .fail(grpcio::RpcStatus::new(
            grpcio::RpcStatusCode::InvalidArgument,
            Some("Did not expect this request".to_string()),
          ))
          .map_err(|_| ()),
      );
      return;
    }

    self.send_next_operation_stream(&ctx, sink);
  }

  fn wait_execution(
    &self,
    _ctx: grpcio::RpcContext<'_>,
    _req: bazel_protos::remote_execution::WaitExecutionRequest,
    _sink: grpcio::ServerStreamingSink<bazel_protos::operations::Operation>,
  ) {
    unimplemented!()
  }
}

impl bazel_protos::operations_grpc::Operations for MockResponder {
  fn get_operation(
    &self,
    _: grpcio::RpcContext<'_>,
    req: bazel_protos::operations::GetOperationRequest,
    sink: grpcio::UnarySink<bazel_protos::operations::Operation>,
  ) {
    self.log(req.clone());

    self.send_next_operation_unary(sink)
  }

  fn list_operations(
    &self,
    _: grpcio::RpcContext<'_>,
    _: bazel_protos::operations::ListOperationsRequest,
    sink: grpcio::UnarySink<bazel_protos::operations::ListOperationsResponse>,
  ) {
    sink.fail(grpcio::RpcStatus::new(
      grpcio::RpcStatusCode::Unimplemented,
      None,
    ));
  }

  fn delete_operation(
    &self,
    _: grpcio::RpcContext<'_>,
    _: bazel_protos::operations::DeleteOperationRequest,
    sink: grpcio::UnarySink<bazel_protos::empty::Empty>,
  ) {
    sink.fail(grpcio::RpcStatus::new(
      grpcio::RpcStatusCode::Unimplemented,
      None,
    ));
  }

  fn cancel_operation(
    &self,
    _: grpcio::RpcContext<'_>,
    _: bazel_protos::operations::CancelOperationRequest,
    sink: grpcio::UnarySink<bazel_protos::empty::Empty>,
  ) {
    sink.fail(grpcio::RpcStatus::new(
      grpcio::RpcStatusCode::Unimplemented,
      None,
    ));
  }
}
<|endoftext|>


<commit_before>// Copyright 2017 Rich Lane <lanerl@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate rbpf;
mod common;

use rbpf::assembler::assemble;
use rbpf::disassembler::to_insn_vec;

// Using a macro to keep actual line numbers in failure output
macro_rules! disasm {
    ($src:expr) => {
        {
            let src = $src;
            let asm = assemble(src).expect("Can't assemble from string");
            let insn = to_insn_vec(&asm);
            let reasm = insn.into_iter().map(|ins| ins.desc).collect::<Vec<_>>().join("\n");

            assert_eq!(src, reasm);
        }
    }
}

#[test]
fn test_empty() {
    disasm!("");
}

// Example for InstructionType::NoOperand.
#[test]
fn test_exit() {
    disasm!("exit");
}

// Example for InstructionType::AluBinary.
#[test]
fn test_add64() {
    disasm!("add64 r1, r3");
    disasm!("add64 r1, 0x5");
}

// Example for InstructionType::AluUnary.
#[test]
fn test_neg64() {
    disasm!("neg64 r1");
}

// Example for InstructionType::LoadReg.
#[test]
fn test_ldxw() {
    disasm!("ldxw r1, [r2+0x5]");
}

// Example for InstructionType::StoreImm.
#[test]
fn test_stw() {
    disasm!("stw [r2+0x5], 0x7");
}

// Example for InstructionType::StoreReg.
#[test]
fn test_stxw() {
    disasm!("stxw [r2+0x5], r8");
}

// Example for InstructionType::JumpUnconditional.
#[test]
fn test_ja() {
    disasm!("ja +0x8");
}

// Example for InstructionType::JumpConditional.
#[test]
fn test_jeq() {
    disasm!("jeq r1, 0x4, +0x8");
    disasm!("jeq r1, r3, +0x8");
}

// Example for InstructionType::Call.
#[test]
fn test_call() {
    disasm!("call 0x3");
}

// Example for InstructionType::Endian.
#[test]
fn test_be32() {
    disasm!("be32 r1");
}

// Example for InstructionType::LoadImm.
#[test]
fn test_lddw() {
    disasm!("lddw r1, 0x1234abcd5678eeff");
    disasm!("lddw r1, 0xff11ee22dd33cc44");
}

// Example for InstructionType::LoadAbs.
#[test]
fn test_ldabsw() {
    disasm!("ldabsw 0x1");
}

// Example for InstructionType::LoadInd.
#[test]
fn test_ldindw() {
    disasm!("ldindw r1, 0x2");
}

// Example for InstructionType::LoadReg.
#[test]
fn test_ldxdw() {
    disasm!("ldxdw r1, [r2+0x3]");
}

// Example for InstructionType::StoreImm.
#[test]
fn test_sth() {
    disasm!("sth [r1+0x2], 0x3");
}

// Example for InstructionType::StoreReg.
#[test]
fn test_stxh() {
    disasm!("stxh [r1+0x2], r3");
}

// Test all supported AluBinary mnemonics.
#[test]
fn test_alu_binary() {
    disasm!("add64 r1, r2
sub64 r1, r2
mul64 r1, r2
div64 r1, r2
or64 r1, r2
and64 r1, r2
lsh64 r1, r2
rsh64 r1, r2
mod64 r1, r2
xor64 r1, r2
mov64 r1, r2
arsh64 r1, r2");

    disasm!("add64 r1, 0x2
sub64 r1, 0x2
mul64 r1, 0x2
div64 r1, 0x2
or64 r1, 0x2
and64 r1, 0x2
lsh64 r1, 0x2
rsh64 r1, 0x2
mod64 r1, 0x2
xor64 r1, 0x2
mov64 r1, 0x2
arsh64 r1, 0x2");

    disasm!("add32 r1, r2
sub32 r1, r2
mul32 r1, r2
div32 r1, r2
or32 r1, r2
and32 r1, r2
lsh32 r1, r2
rsh32 r1, r2
mod32 r1, r2
xor32 r1, r2
mov32 r1, r2
arsh32 r1, r2");

    disasm!("add32 r1, 0x2
sub32 r1, 0x2
mul32 r1, 0x2
div32 r1, 0x2
or32 r1, 0x2
and32 r1, 0x2
lsh32 r1, 0x2
rsh32 r1, 0x2
mod32 r1, 0x2
xor32 r1, 0x2
mov32 r1, 0x2
arsh32 r1, 0x2");
}

// Test all supported AluUnary mnemonics.
#[test]
fn test_alu_unary() {
    disasm!("neg64 r1
neg32 r1");
}

// Test all supported LoadAbs mnemonics.
#[test]
fn test_load_abs() {
    disasm!("ldabsw 0x1
ldabsh 0x1
ldabsb 0x1
ldabsdw 0x1");
}

// Test all supported LoadInd mnemonics.
#[test]
fn test_load_ind() {
    disasm!("ldindw r1, 0x2
ldindh r1, 0x2
ldindb r1, 0x2
ldinddw r1, 0x2");
}

// Test all supported LoadReg mnemonics.
#[test]
fn test_load_reg() {
    disasm!(r"ldxw r1, [r2+0x3]
ldxh r1, [r2+0x3]
ldxb r1, [r2+0x3]
ldxdw r1, [r2+0x3]");
}

// Test all supported StoreImm mnemonics.
#[test]
fn test_store_imm() {
    disasm!("stw [r1+0x2], 0x3
sth [r1+0x2], 0x3
stb [r1+0x2], 0x3
stdw [r1+0x2], 0x3");
}

// Test all supported StoreReg mnemonics.
#[test]
fn test_store_reg() {
    disasm!("stxw [r1+0x2], r3
stxh [r1+0x2], r3
stxb [r1+0x2], r3
stxdw [r1+0x2], r3");
}

// Test all supported JumpConditional mnemonics.
#[test]
fn test_jump_conditional() {
    disasm!("jeq r1, r2, +0x3
jgt r1, r2, +0x3
jge r1, r2, +0x3
jset r1, r2, +0x3
jne r1, r2, +0x3
jsgt r1, r2, +0x3
jsge r1, r2, +0x3");

    disasm!("jeq r1, 0x2, +0x3
jgt r1, 0x2, +0x3
jge r1, 0x2, +0x3
jset r1, 0x2, +0x3
jne r1, 0x2, +0x3
jsgt r1, 0x2, +0x3
jsge r1, 0x2, +0x3");
}

// Test all supported Endian mnemonics.
#[test]
fn test_endian() {
    disasm!("be16 r1
be32 r1
be64 r1
le16 r1
le32 r1
le64 r1");
}

#[test]
fn test_large_immediate() {
    disasm!("add64 r1, 0x7fffffff");
    disasm!("add64 r1, 0x7fffffff");
}
<commit_msg>Add my own copyright<commit_after>// Copyright 2017 Jan-Erik Rediger <badboy@archlinux.us>
//
// Adopted from tests in `tests/assembler.rs`
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate rbpf;
mod common;

use rbpf::assembler::assemble;
use rbpf::disassembler::to_insn_vec;

// Using a macro to keep actual line numbers in failure output
macro_rules! disasm {
    ($src:expr) => {
        {
            let src = $src;
            let asm = assemble(src).expect("Can't assemble from string");
            let insn = to_insn_vec(&asm);
            let reasm = insn.into_iter().map(|ins| ins.desc).collect::<Vec<_>>().join("\n");

            assert_eq!(src, reasm);
        }
    }
}

#[test]
fn test_empty() {
    disasm!("");
}

// Example for InstructionType::NoOperand.
#[test]
fn test_exit() {
    disasm!("exit");
}

// Example for InstructionType::AluBinary.
#[test]
fn test_add64() {
    disasm!("add64 r1, r3");
    disasm!("add64 r1, 0x5");
}

// Example for InstructionType::AluUnary.
#[test]
fn test_neg64() {
    disasm!("neg64 r1");
}

// Example for InstructionType::LoadReg.
#[test]
fn test_ldxw() {
    disasm!("ldxw r1, [r2+0x5]");
}

// Example for InstructionType::StoreImm.
#[test]
fn test_stw() {
    disasm!("stw [r2+0x5], 0x7");
}

// Example for InstructionType::StoreReg.
#[test]
fn test_stxw() {
    disasm!("stxw [r2+0x5], r8");
}

// Example for InstructionType::JumpUnconditional.
#[test]
fn test_ja() {
    disasm!("ja +0x8");
}

// Example for InstructionType::JumpConditional.
#[test]
fn test_jeq() {
    disasm!("jeq r1, 0x4, +0x8");
    disasm!("jeq r1, r3, +0x8");
}

// Example for InstructionType::Call.
#[test]
fn test_call() {
    disasm!("call 0x3");
}

// Example for InstructionType::Endian.
#[test]
fn test_be32() {
    disasm!("be32 r1");
}

// Example for InstructionType::LoadImm.
#[test]
fn test_lddw() {
    disasm!("lddw r1, 0x1234abcd5678eeff");
    disasm!("lddw r1, 0xff11ee22dd33cc44");
}

// Example for InstructionType::LoadAbs.
#[test]
fn test_ldabsw() {
    disasm!("ldabsw 0x1");
}

// Example for InstructionType::LoadInd.
#[test]
fn test_ldindw() {
    disasm!("ldindw r1, 0x2");
}

// Example for InstructionType::LoadReg.
#[test]
fn test_ldxdw() {
    disasm!("ldxdw r1, [r2+0x3]");
}

// Example for InstructionType::StoreImm.
#[test]
fn test_sth() {
    disasm!("sth [r1+0x2], 0x3");
}

// Example for InstructionType::StoreReg.
#[test]
fn test_stxh() {
    disasm!("stxh [r1+0x2], r3");
}

// Test all supported AluBinary mnemonics.
#[test]
fn test_alu_binary() {
    disasm!("add64 r1, r2
sub64 r1, r2
mul64 r1, r2
div64 r1, r2
or64 r1, r2
and64 r1, r2
lsh64 r1, r2
rsh64 r1, r2
mod64 r1, r2
xor64 r1, r2
mov64 r1, r2
arsh64 r1, r2");

    disasm!("add64 r1, 0x2
sub64 r1, 0x2
mul64 r1, 0x2
div64 r1, 0x2
or64 r1, 0x2
and64 r1, 0x2
lsh64 r1, 0x2
rsh64 r1, 0x2
mod64 r1, 0x2
xor64 r1, 0x2
mov64 r1, 0x2
arsh64 r1, 0x2");

    disasm!("add32 r1, r2
sub32 r1, r2
mul32 r1, r2
div32 r1, r2
or32 r1, r2
and32 r1, r2
lsh32 r1, r2
rsh32 r1, r2
mod32 r1, r2
xor32 r1, r2
mov32 r1, r2
arsh32 r1, r2");

    disasm!("add32 r1, 0x2
sub32 r1, 0x2
mul32 r1, 0x2
div32 r1, 0x2
or32 r1, 0x2
and32 r1, 0x2
lsh32 r1, 0x2
rsh32 r1, 0x2
mod32 r1, 0x2
xor32 r1, 0x2
mov32 r1, 0x2
arsh32 r1, 0x2");
}

// Test all supported AluUnary mnemonics.
#[test]
fn test_alu_unary() {
    disasm!("neg64 r1
neg32 r1");
}

// Test all supported LoadAbs mnemonics.
#[test]
fn test_load_abs() {
    disasm!("ldabsw 0x1
ldabsh 0x1
ldabsb 0x1
ldabsdw 0x1");
}

// Test all supported LoadInd mnemonics.
#[test]
fn test_load_ind() {
    disasm!("ldindw r1, 0x2
ldindh r1, 0x2
ldindb r1, 0x2
ldinddw r1, 0x2");
}

// Test all supported LoadReg mnemonics.
#[test]
fn test_load_reg() {
    disasm!(r"ldxw r1, [r2+0x3]
ldxh r1, [r2+0x3]
ldxb r1, [r2+0x3]
ldxdw r1, [r2+0x3]");
}

// Test all supported StoreImm mnemonics.
#[test]
fn test_store_imm() {
    disasm!("stw [r1+0x2], 0x3
sth [r1+0x2], 0x3
stb [r1+0x2], 0x3
stdw [r1+0x2], 0x3");
}

// Test all supported StoreReg mnemonics.
#[test]
fn test_store_reg() {
    disasm!("stxw [r1+0x2], r3
stxh [r1+0x2], r3
stxb [r1+0x2], r3
stxdw [r1+0x2], r3");
}

// Test all supported JumpConditional mnemonics.
#[test]
fn test_jump_conditional() {
    disasm!("jeq r1, r2, +0x3
jgt r1, r2, +0x3
jge r1, r2, +0x3
jset r1, r2, +0x3
jne r1, r2, +0x3
jsgt r1, r2, +0x3
jsge r1, r2, +0x3");

    disasm!("jeq r1, 0x2, +0x3
jgt r1, 0x2, +0x3
jge r1, 0x2, +0x3
jset r1, 0x2, +0x3
jne r1, 0x2, +0x3
jsgt r1, 0x2, +0x3
jsge r1, 0x2, +0x3");
}

// Test all supported Endian mnemonics.
#[test]
fn test_endian() {
    disasm!("be16 r1
be32 r1
be64 r1
le16 r1
le32 r1
le64 r1");
}

#[test]
fn test_large_immediate() {
    disasm!("add64 r1, 0x7fffffff");
    disasm!("add64 r1, 0x7fffffff");
}
<|endoftext|>


<commit_before>//! Module for kernels
//!
//! Currently used within Gaussian Processes.

use linalg::vector::Vector;

/// The Kernel trait
///
/// Requires a function mapping two vectors to a scalar.
pub trait Kernel {
    /// The kernel function.
    ///
    /// Takes two equal length slices and returns a scalar.
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64;
}

/// Squared exponential kernel
///
/// Equivalently a gaussian function.
///
/// The kernel function is given by:
///
/// f(x1,x2) = A _exp_(-||x1-x2||^2 / 2(l^2))
///
/// Where A is the amplitude and l the length scale.
pub struct SquaredExp {
    ls: f64,
    ampl: f64,
}

impl SquaredExp {
    /// Construct a new squared exponential kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel::SquaredExp;
    ///
    /// let ker = SquaredExp::new(2f64, 1f64);
    /// ```
    pub fn new(ls: f64, ampl: f64) -> SquaredExp {
        SquaredExp {
            ls: ls,
            ampl: ampl,
        }
    }
}

impl Default for SquaredExp {
    /// Constructs the default Squared Exp kernel.
    ///
    /// The default settings are:
    /// - length scale = 1
    /// - amplitude = 1
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel::SquaredExp;
    ///
    /// let ker = SquaredExp::default();
    /// ```
    fn default() -> SquaredExp {
        SquaredExp {
            ls: 1f64,
            ampl: 1f64,
        }
    }
}

impl Kernel for SquaredExp {
    /// The squared exponential kernel function.
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        assert_eq!(x1.len(), x2.len());

        let v1 = Vector::new(x1.to_vec());
        let v2 = Vector::new(x2.to_vec());

        let x = -(&v1 - &v2).dot(&(v1 - v2)) / (2f64 * self.ls * self.ls);
        (self.ampl * x.exp())
    }
}
<commit_msg>Adding more kernels and documentation.<commit_after>//! Module for kernels
//!
//! Currently used within Gaussian Processes and SVMs.

use linalg::vector::Vector;
use linalg::utils;
use linalg::Metric;

use libnum::Float;

/// The Kernel trait
///
/// Requires a function mapping two vectors to a scalar.
pub trait Kernel {
    /// The kernel function.
    ///
    /// Takes two equal length slices and returns a scalar.
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64;
}

/// The Linear Kernel
///
/// k(x,y) = xTy + c
pub struct Linear {
    /// Constant term added to inner product.
    pub c: f64,
}

impl Linear {
    /// Constructs a new Linear Kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel;
    /// use rusty_machine::learning::toolkit::kernel::Kernel;
    ///
    /// let ker = kernel::Linear::new(5.0);
    ///
    /// println!("{0}", ker.kernel(&[1.,2.,3.], &[3.,4.,5.]));
    /// ```
    pub fn new(c: f64) -> Linear {
        Linear {
            c : c,
        }
    }
}

/// Constructs the default Linear Kernel
///
/// The defaults are:
///
/// - c = 0
impl Default for Linear {
    fn default() -> Linear {
        Linear {
            c: 0f64,
        }
    }
}

impl Kernel for Linear {
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        utils::dot(x1, x2) + self.c
    }
}

/// The Polynomial Kernel
///
/// k(x,y) = (αxTy + c)d
pub struct Polynomial {
    /// Scaling of the inner product.
    pub alpha: f64,
    /// Constant added to inner product.
    pub c: f64,
    /// The power to raise the sum to.
    pub d: f64,
}

impl Polynomial {

    /// Constructs a new Polynomial Kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel;
    /// use rusty_machine::learning::toolkit::kernel::Kernel;
    ///
    /// // Constructs a new polynomial with alpha = 1, c = 0, d = 2.
    /// let ker = kernel::Polynomial::new(1.0, 0.0, 2.0);
    ///
    /// println!("{0}", ker.kernel(&[1.,2.,3.], &[3.,4.,5.]));
    /// ```
    pub fn new(alpha: f64, c: f64, d: f64) -> Polynomial {
        Polynomial {
            alpha: alpha,
            c : c,
            d: d,
        }
    }
}

/// Construct a new polynomial kernel.
///
/// The defaults are:
///
/// - alpha = 1
/// - c = 0
/// - d = 1
impl Default for Polynomial {
    fn default() -> Polynomial {
        Polynomial {
            alpha: 1f64,
            c: 0f64,
            d: 1f64,
        }
    }
}

impl Kernel for Polynomial {
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        (self.alpha * utils::dot(x1, x2) + self.c).powf(self.d)
    }
}

/// Squared exponential kernel
///
/// Equivalently a gaussian function.
///
/// k(x,y) = A _exp_(-||x-y||2 / 2l2)
///
/// Where A is the amplitude and l the length scale.
pub struct SquaredExp {
    /// The length scale of the kernel.
    pub ls: f64,
    /// The amplitude of the kernel.
    pub ampl: f64,
}

impl SquaredExp {
    /// Construct a new squared exponential kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel;
    /// use rusty_machine::learning::toolkit::kernel::Kernel;
    ///
    /// // Construct a kernel with lengthscale 2 and amplitude 1.
    /// let ker = kernel::SquaredExp::new(2f64, 1f64);
    ///
    /// println!("{0}", ker.kernel(&[1.,2.,3.], &[3.,4.,5.]));
    /// ```
    pub fn new(ls: f64, ampl: f64) -> SquaredExp {
        SquaredExp {
            ls: ls,
            ampl: ampl,
        }
    }
}

/// Constructs the default Squared Exp kernel.
///
/// The defaults are:
///
/// - ls = 1
/// - ampl = 1
impl Default for SquaredExp {
    fn default() -> SquaredExp {
        SquaredExp {
            ls: 1f64,
            ampl: 1f64,
        }
    }
}

impl Kernel for SquaredExp {
    /// The squared exponential kernel function.
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        assert_eq!(x1.len(), x2.len());

        let diff = Vector::new(x1.to_vec()) - Vector::new(x2.to_vec());

        let x = -diff.dot(&diff) / (2f64 * self.ls * self.ls);
        (self.ampl * x.exp())
    }
}

/// The Exponential Kernel
///
/// k(x,y) = A _exp_(-||x-y|| / 2l2)
///
/// Where A is the amplitude and l is the length scale.
pub struct Exponential {
    /// The length scale of the kernel.
    pub ls: f64,
    /// The amplitude of the kernel.
    pub ampl: f64,
}

impl Exponential {
    /// Construct a new squared exponential kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel;
    /// use rusty_machine::learning::toolkit::kernel::Kernel;
    ///
    /// // Construct a kernel with lengthscale 2 and amplitude 1.
    /// let ker = kernel::Exponential::new(2f64, 1f64);
    ///
    /// println!("{0}", ker.kernel(&[1.,2.,3.], &[3.,4.,5.]));
    /// ```
    pub fn new(ls: f64, ampl: f64) -> Exponential {
        Exponential {
            ls: ls,
            ampl: ampl,
        }
    }
}

/// Constructs the default Exponential kernel.
///
/// The defaults are:
///
/// - ls = 1
/// - amplitude = 1
impl Default for Exponential {

    fn default() -> Exponential {
        Exponential {
            ls: 1f64,
            ampl: 1f64,
        }
    }
}

impl Kernel for Exponential {
    /// The squared exponential kernel function.
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        assert_eq!(x1.len(), x2.len());

        let diff = Vector::new(x1.to_vec()) - Vector::new(x2.to_vec());

        let x = -diff.norm() / (2f64 * self.ls * self.ls);
        (self.ampl * x.exp())
    }
}

/// The Hyperbolic Tangent Kernel.
///
/// ker(x,y) = _tanh_(αxTy + c)
pub struct HyperTan {
    /// The scaling of the inner product.
    pub alpha: f64,
    /// The constant to add to the inner product.
    pub c: f64,
}

impl HyperTan {

    /// Constructs a new Hyperbolic Tangent Kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel;
    /// use rusty_machine::learning::toolkit::kernel::Kernel;
    ///
    /// // Construct a kernel with alpha = 1, c = 2.
    /// let ker = kernel::HyperTan::new(1.0, 2.0);
    ///
    /// println!("{0}", ker.kernel(&[1.,2.,3.], &[3.,4.,5.]));
    /// ```
    pub fn new(alpha: f64, c: f64) -> HyperTan {
        HyperTan {
            alpha: alpha,
            c : c,
        }
    }
}

/// Constructs a default Hyperbolic Tangent Kernel.
///
/// The defaults are:
///
/// - alpha = 1
/// - c = 0
impl Default for HyperTan {
    fn default() -> HyperTan {
        HyperTan {
            alpha: 1f64,
            c: 0f64,
        }
    }
}

impl Kernel for HyperTan {
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        (self.alpha * utils::dot(x1, x2) + self.c).tanh()
    }
}

/// The Multiquadric Kernel.
///
/// k(x,y) = _sqrt_(||x-y||2 + c2)
pub struct Multiquadric {
    /// Constant added to square of difference.
    pub c: f64,
}

impl Multiquadric {

    /// Constructs a new Multiquadric Kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel;
    /// use rusty_machine::learning::toolkit::kernel::Kernel;
    ///
    /// // Construct a kernel with c = 2.
    /// let ker = kernel::Multiquadric::new(2.0);
    ///
    /// println!("{0}", ker.kernel(&[1.,2.,3.], &[3.,4.,5.]));
    /// ```
    pub fn new(c: f64) -> Multiquadric {
        Multiquadric {
            c : c,
        }
    }
}

/// Constructs a default Multiquadric Kernel.
///
/// The defaults are:
///
/// - c = 0
impl Default for Multiquadric {
    fn default() -> Multiquadric {
        Multiquadric {
            c: 0f64,
        }
    }
}

impl Kernel for Multiquadric {
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        assert_eq!(x1.len(), x2.len());

        let diff = Vector::new(x1.to_vec()) - Vector::new(x2.to_vec());

        diff.norm().hypot(self.c)
    }
}

/// The Rational Quadratic Kernel.
///
/// k(x,y) = (1 + ||x-y||2 / (2αl2))-α
pub struct RationalQuadratic {
    /// Controls inverse power and difference scale.
    pub alpha: f64,
    /// Length scale controls scale of difference.
    pub ls: f64,
}

impl RationalQuadratic {

    /// Constructs a new Rational Quadratic Kernel.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::toolkit::kernel;
    /// use rusty_machine::learning::toolkit::kernel::Kernel;
    ///
    /// // Construct a kernel with alpha = 2, ls = 2.
    /// let ker = kernel::RationalQuadratic::new(2.0, 2.0);
    ///
    /// println!("{0}", ker.kernel(&[1.,2.,3.], &[3.,4.,5.]));
    /// ```
    pub fn new(alpha: f64, ls: f64) -> RationalQuadratic {
        RationalQuadratic {
            alpha: alpha,
            ls: ls,
        }
    }
}

/// The default Rational Qaudratic Kernel.
///
/// The defaults are:
///
/// - alpha = 1
/// - ls = 1
impl Default for RationalQuadratic {
    fn default() -> RationalQuadratic {
        RationalQuadratic {
            alpha: 1f64,
            ls: 1f64,
        }
    }
}

impl Kernel for RationalQuadratic {
    fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
        let diff = Vector::new(x1.to_vec()) - Vector::new(x2.to_vec());

        (1f64 + diff.dot(&diff) / (2f64 * self.alpha * self.ls * self.ls)).powf(-self.alpha)
    }
}<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};
use std::ops::Range;
use ucd_parse::Codepoints;

mod case_mapping;
mod raw_emitter;
mod unicode_download;

use raw_emitter::{emit_codepoints, RawEmitter};

static PROPERTIES: &[&str] = &[
    "Alphabetic",
    "Lowercase",
    "Uppercase",
    "Cased",
    "Case_Ignorable",
    "Grapheme_Extend",
    "White_Space",
    "Cc",
    "N",
];

struct UnicodeData {
    ranges: Vec<(&'static str, Vec<Range<u32>>)>,
    to_upper: BTreeMap<u32, (u32, u32, u32)>,
    to_lower: BTreeMap<u32, (u32, u32, u32)>,
}

fn to_mapping(origin: u32, codepoints: Vec<ucd_parse::Codepoint>) -> Option<(u32, u32, u32)> {
    let mut a = None;
    let mut b = None;
    let mut c = None;

    for codepoint in codepoints {
        if origin == codepoint.value() {
            return None;
        }

        if a.is_none() {
            a = Some(codepoint.value());
        } else if b.is_none() {
            b = Some(codepoint.value());
        } else if c.is_none() {
            c = Some(codepoint.value());
        } else {
            panic!("more than 3 mapped codepoints")
        }
    }

    Some((a.unwrap(), b.unwrap_or(0), c.unwrap_or(0)))
}

static UNICODE_DIRECTORY: &str = "unicode-downloads";

fn load_data() -> UnicodeData {
    unicode_download::fetch_latest();

    let mut properties = HashMap::new();
    for row in ucd_parse::parse::<_, ucd_parse::CoreProperty>(&UNICODE_DIRECTORY).unwrap() {
        if let Some(name) = PROPERTIES.iter().find(|prop| **prop == row.property.as_str()) {
            properties.entry(*name).or_insert_with(Vec::new).push(row.codepoints);
        }
    }
    for row in ucd_parse::parse::<_, ucd_parse::Property>(&UNICODE_DIRECTORY).unwrap() {
        if let Some(name) = PROPERTIES.iter().find(|prop| **prop == row.property.as_str()) {
            properties.entry(*name).or_insert_with(Vec::new).push(row.codepoints);
        }
    }

    let mut to_lower = BTreeMap::new();
    let mut to_upper = BTreeMap::new();
    for row in ucd_parse::UnicodeDataExpander::new(
        ucd_parse::parse::<_, ucd_parse::UnicodeData>(&UNICODE_DIRECTORY).unwrap(),
    ) {
        let general_category = if ["Nd", "Nl", "No"].contains(&row.general_category.as_str()) {
            "N"
        } else {
            row.general_category.as_str()
        };
        if let Some(name) = PROPERTIES.iter().find(|prop| **prop == general_category) {
            properties
                .entry(*name)
                .or_insert_with(Vec::new)
                .push(Codepoints::Single(row.codepoint));
        }

        if let Some(mapped) = row.simple_lowercase_mapping {
            if mapped != row.codepoint {
                to_lower.insert(row.codepoint.value(), (mapped.value(), 0, 0));
            }
        }
        if let Some(mapped) = row.simple_uppercase_mapping {
            if mapped != row.codepoint {
                to_upper.insert(row.codepoint.value(), (mapped.value(), 0, 0));
            }
        }
    }

    for row in ucd_parse::parse::<_, ucd_parse::SpecialCaseMapping>(&UNICODE_DIRECTORY).unwrap() {
        if !row.conditions.is_empty() {
            // Skip conditional case mappings
            continue;
        }

        let key = row.codepoint.value();
        if let Some(lower) = to_mapping(key, row.lowercase) {
            to_lower.insert(key, lower);
        }
        if let Some(upper) = to_mapping(key, row.uppercase) {
            to_upper.insert(key, upper);
        }
    }

    let mut properties: HashMap<&'static str, Vec<Range<u32>>> = properties
        .into_iter()
        .map(|(k, v)| {
            (
                k,
                v.into_iter()
                    .flat_map(|codepoints| match codepoints {
                        Codepoints::Single(c) => c
                            .scalar()
                            .map(|ch| (ch as u32..ch as u32 + 1))
                            .into_iter()
                            .collect::<Vec<_>>(),
                        Codepoints::Range(c) => c
                            .into_iter()
                            .flat_map(|c| c.scalar().map(|ch| (ch as u32..ch as u32 + 1)))
                            .collect::<Vec<_>>(),
                    })
                    .collect::<Vec<Range<u32>>>(),
            )
        })
        .collect();

    for ranges in properties.values_mut() {
        merge_ranges(ranges);
    }

    let mut properties = properties.into_iter().collect::<Vec<_>>();
    properties.sort_by_key(|p| p.0);
    UnicodeData { ranges: properties, to_lower, to_upper }
}

fn main() {
    let write_location = std::env::args().nth(1).unwrap_or_else(|| {
        eprintln!("Must provide path to write unicode tables to");
        eprintln!(
            "e.g. {} src/libcore/unicode/unicode_data.rs",
            std::env::args().next().unwrap_or_default()
        );
        std::process::exit(1);
    });

    // Optional test path, which is a Rust source file testing that the unicode
    // property lookups are correct.
    let test_path = std::env::args().nth(2);

    let unicode_data = load_data();
    let ranges_by_property = &unicode_data.ranges;

    if let Some(path) = test_path {
        std::fs::write(&path, generate_tests(&write_location, &ranges_by_property)).unwrap();
    }

    let mut total_bytes = 0;
    let mut modules = Vec::new();
    for (property, ranges) in ranges_by_property {
        let datapoints = ranges.iter().map(|r| r.end - r.start).sum::<u32>();
        let mut emitter = RawEmitter::new();
        emit_codepoints(&mut emitter, &ranges);

        modules.push((property.to_lowercase().to_string(), emitter.file));
        println!("{:15}: {} bytes, {} codepoints", property, emitter.bytes_used, datapoints,);
        total_bytes += emitter.bytes_used;
    }

    let mut table_file = String::new();

    table_file.push_str(
        "///! This file is generated by src/tools/unicode-table-generator; do not edit manually!\n",
    );

    // Include the range search function
    table_file.push('\n');
    table_file.push_str(include_str!("range_search.rs"));
    table_file.push('\n');

    table_file.push_str(&version());

    table_file.push('\n');

    modules.push((String::from("conversions"), case_mapping::generate_case_mapping(&unicode_data)));

    for (name, contents) in modules {
        table_file.push_str("#[rustfmt::skip]\n");
        table_file.push_str(&format!("pub mod {} {{\n", name));
        for line in contents.lines() {
            if !line.trim().is_empty() {
                table_file.push_str("    ");
                table_file.push_str(&line);
            }
            table_file.push('\n');
        }
        table_file.push_str("}\n\n");
    }

    std::fs::write(&write_location, format!("{}\n", table_file.trim_end())).unwrap();

    println!("Total table sizes: {} bytes", total_bytes);
}

fn version() -> String {
    let mut out = String::new();
    out.push_str("pub const UNICODE_VERSION: (u32, u32, u32) = ");

    let readme =
        std::fs::read_to_string(std::path::Path::new(UNICODE_DIRECTORY).join("ReadMe.txt"))
            .unwrap();

    let prefix = "for Version ";
    let start = readme.find(prefix).unwrap() + prefix.len();
    let end = readme.find(" of the Unicode Standard.").unwrap();
    let version =
        readme[start..end].split('.').map(|v| v.parse::<u32>().expect(&v)).collect::<Vec<_>>();
    let [major, minor, micro] = [version[0], version[1], version[2]];

    out.push_str(&format!("({}, {}, {});\n", major, minor, micro));
    out
}

fn fmt_list<V: std::fmt::Debug>(values: impl IntoIterator<Item = V>) -> String {
    let pieces = values.into_iter().map(|b| format!("{:?}, ", b)).collect::<Vec<_>>();
    let mut out = String::new();
    let mut line = format!("\n    ");
    for piece in pieces {
        if line.len() + piece.len() < 98 {
            line.push_str(&piece);
        } else {
            out.push_str(line.trim_end());
            out.push('\n');
            line = format!("    {}", piece);
        }
    }
    out.push_str(line.trim_end());
    out.push('\n');
    out
}

fn generate_tests(data_path: &str, ranges: &[(&str, Vec<Range<u32>>)]) -> String {
    let mut s = String::new();
    s.push_str("#![allow(incomplete_features, unused)]\n");
    s.push_str("#![feature(const_generics)]\n\n");
    s.push_str(&format!("#[path = \"{}\"]\n", data_path));
    s.push_str("mod unicode_data;\n\n");

    s.push_str("\nfn main() {\n");

    for (property, ranges) in ranges {
        s.push_str(&format!(r#"    println!("Testing {}");"#, property));
        s.push('\n');
        s.push_str(&format!("    {}();\n", property.to_lowercase()));
        let mut is_true = Vec::new();
        let mut is_false = Vec::new();
        for ch_num in 0..(std::char::MAX as u32) {
            if std::char::from_u32(ch_num).is_none() {
                continue;
            }
            if ranges.iter().any(|r| r.contains(&ch_num)) {
                is_true.push(ch_num);
            } else {
                is_false.push(ch_num);
            }
        }

        s.push_str(&format!("    fn {}() {{\n", property.to_lowercase()));
        generate_asserts(&mut s, property, &is_true, true);
        generate_asserts(&mut s, property, &is_false, false);
        s.push_str("    }\n\n");
    }

    s.push_str("}");
    s
}

fn generate_asserts(s: &mut String, property: &str, points: &[u32], truthy: bool) {
    for range in ranges_from_set(points) {
        if range.end == range.start + 1 {
            s.push_str(&format!(
                "        assert!({}unicode_data::{}::lookup(std::char::from_u32({}).unwrap()), \"{}\");\n",
                if truthy { "" } else { "!" },
                property.to_lowercase(),
                range.start,
                std::char::from_u32(range.start).unwrap(),
        ));
        } else {
            s.push_str(&format!("        for chn in {:?}u32 {{\n", range));
            s.push_str(&format!(
                "            assert!({}unicode_data::{}::lookup(std::char::from_u32(chn).unwrap()), \"{{:?}}\", chn);\n",
                if truthy { "" } else { "!" },
                property.to_lowercase(),
        ));
            s.push_str("        }\n");
        }
    }
}

fn ranges_from_set(set: &[u32]) -> Vec<Range<u32>> {
    let mut ranges = set.iter().map(|e| (*e)..(*e + 1)).collect::<Vec<Range<u32>>>();
    merge_ranges(&mut ranges);
    ranges
}

fn merge_ranges(ranges: &mut Vec<Range<u32>>) {
    loop {
        let mut new_ranges = Vec::new();
        let mut idx_iter = 0..(ranges.len() - 1);
        while let Some(idx) = idx_iter.next() {
            let cur = ranges[idx].clone();
            let next = ranges[idx + 1].clone();
            if cur.end == next.start {
                let _ = idx_iter.next(); // skip next as we're merging it in
                new_ranges.push(cur.start..next.end);
            } else {
                new_ranges.push(cur);
            }
        }
        new_ranges.push(ranges.last().unwrap().clone());
        if new_ranges.len() == ranges.len() {
            *ranges = new_ranges;
            break;
        } else {
            *ranges = new_ranges;
        }
    }
}
<commit_msg>Add richer printing<commit_after>use std::collections::{BTreeMap, HashMap};
use std::ops::Range;
use ucd_parse::Codepoints;

mod case_mapping;
mod raw_emitter;
mod unicode_download;

use raw_emitter::{emit_codepoints, RawEmitter};

static PROPERTIES: &[&str] = &[
    "Alphabetic",
    "Lowercase",
    "Uppercase",
    "Cased",
    "Case_Ignorable",
    "Grapheme_Extend",
    "White_Space",
    "Cc",
    "N",
];

struct UnicodeData {
    ranges: Vec<(&'static str, Vec<Range<u32>>)>,
    to_upper: BTreeMap<u32, (u32, u32, u32)>,
    to_lower: BTreeMap<u32, (u32, u32, u32)>,
}

fn to_mapping(origin: u32, codepoints: Vec<ucd_parse::Codepoint>) -> Option<(u32, u32, u32)> {
    let mut a = None;
    let mut b = None;
    let mut c = None;

    for codepoint in codepoints {
        if origin == codepoint.value() {
            return None;
        }

        if a.is_none() {
            a = Some(codepoint.value());
        } else if b.is_none() {
            b = Some(codepoint.value());
        } else if c.is_none() {
            c = Some(codepoint.value());
        } else {
            panic!("more than 3 mapped codepoints")
        }
    }

    Some((a.unwrap(), b.unwrap_or(0), c.unwrap_or(0)))
}

static UNICODE_DIRECTORY: &str = "unicode-downloads";

fn load_data() -> UnicodeData {
    unicode_download::fetch_latest();

    let mut properties = HashMap::new();
    for row in ucd_parse::parse::<_, ucd_parse::CoreProperty>(&UNICODE_DIRECTORY).unwrap() {
        if let Some(name) = PROPERTIES.iter().find(|prop| **prop == row.property.as_str()) {
            properties.entry(*name).or_insert_with(Vec::new).push(row.codepoints);
        }
    }
    for row in ucd_parse::parse::<_, ucd_parse::Property>(&UNICODE_DIRECTORY).unwrap() {
        if let Some(name) = PROPERTIES.iter().find(|prop| **prop == row.property.as_str()) {
            properties.entry(*name).or_insert_with(Vec::new).push(row.codepoints);
        }
    }

    let mut to_lower = BTreeMap::new();
    let mut to_upper = BTreeMap::new();
    for row in ucd_parse::UnicodeDataExpander::new(
        ucd_parse::parse::<_, ucd_parse::UnicodeData>(&UNICODE_DIRECTORY).unwrap(),
    ) {
        let general_category = if ["Nd", "Nl", "No"].contains(&row.general_category.as_str()) {
            "N"
        } else {
            row.general_category.as_str()
        };
        if let Some(name) = PROPERTIES.iter().find(|prop| **prop == general_category) {
            properties
                .entry(*name)
                .or_insert_with(Vec::new)
                .push(Codepoints::Single(row.codepoint));
        }

        if let Some(mapped) = row.simple_lowercase_mapping {
            if mapped != row.codepoint {
                to_lower.insert(row.codepoint.value(), (mapped.value(), 0, 0));
            }
        }
        if let Some(mapped) = row.simple_uppercase_mapping {
            if mapped != row.codepoint {
                to_upper.insert(row.codepoint.value(), (mapped.value(), 0, 0));
            }
        }
    }

    for row in ucd_parse::parse::<_, ucd_parse::SpecialCaseMapping>(&UNICODE_DIRECTORY).unwrap() {
        if !row.conditions.is_empty() {
            // Skip conditional case mappings
            continue;
        }

        let key = row.codepoint.value();
        if let Some(lower) = to_mapping(key, row.lowercase) {
            to_lower.insert(key, lower);
        }
        if let Some(upper) = to_mapping(key, row.uppercase) {
            to_upper.insert(key, upper);
        }
    }

    let mut properties: HashMap<&'static str, Vec<Range<u32>>> = properties
        .into_iter()
        .map(|(k, v)| {
            (
                k,
                v.into_iter()
                    .flat_map(|codepoints| match codepoints {
                        Codepoints::Single(c) => c
                            .scalar()
                            .map(|ch| (ch as u32..ch as u32 + 1))
                            .into_iter()
                            .collect::<Vec<_>>(),
                        Codepoints::Range(c) => c
                            .into_iter()
                            .flat_map(|c| c.scalar().map(|ch| (ch as u32..ch as u32 + 1)))
                            .collect::<Vec<_>>(),
                    })
                    .collect::<Vec<Range<u32>>>(),
            )
        })
        .collect();

    for ranges in properties.values_mut() {
        merge_ranges(ranges);
    }

    let mut properties = properties.into_iter().collect::<Vec<_>>();
    properties.sort_by_key(|p| p.0);
    UnicodeData { ranges: properties, to_lower, to_upper }
}

fn main() {
    let write_location = std::env::args().nth(1).unwrap_or_else(|| {
        eprintln!("Must provide path to write unicode tables to");
        eprintln!(
            "e.g. {} src/libcore/unicode/unicode_data.rs",
            std::env::args().next().unwrap_or_default()
        );
        std::process::exit(1);
    });

    // Optional test path, which is a Rust source file testing that the unicode
    // property lookups are correct.
    let test_path = std::env::args().nth(2);

    let unicode_data = load_data();
    let ranges_by_property = &unicode_data.ranges;

    if let Some(path) = test_path {
        std::fs::write(&path, generate_tests(&write_location, &ranges_by_property)).unwrap();
    }

    let mut total_bytes = 0;
    let mut modules = Vec::new();
    for (property, ranges) in ranges_by_property {
        let datapoints = ranges.iter().map(|r| r.end - r.start).sum::<u32>();
        let mut emitter = RawEmitter::new();
        emit_codepoints(&mut emitter, &ranges);

        modules.push((property.to_lowercase().to_string(), emitter.file));
        println!(
            "{:15}: {} bytes, {} codepoints in {} ranges ({} - {})",
            property,
            emitter.bytes_used,
            datapoints,
            ranges.len(),
            ranges.first().unwrap().start,
            ranges.last().unwrap().end
        );
        total_bytes += emitter.bytes_used;
    }

    let mut table_file = String::new();

    table_file.push_str(
        "///! This file is generated by src/tools/unicode-table-generator; do not edit manually!\n",
    );

    // Include the range search function
    table_file.push('\n');
    table_file.push_str(include_str!("range_search.rs"));
    table_file.push('\n');

    table_file.push_str(&version());

    table_file.push('\n');

    modules.push((String::from("conversions"), case_mapping::generate_case_mapping(&unicode_data)));

    for (name, contents) in modules {
        table_file.push_str("#[rustfmt::skip]\n");
        table_file.push_str(&format!("pub mod {} {{\n", name));
        for line in contents.lines() {
            if !line.trim().is_empty() {
                table_file.push_str("    ");
                table_file.push_str(&line);
            }
            table_file.push('\n');
        }
        table_file.push_str("}\n\n");
    }

    std::fs::write(&write_location, format!("{}\n", table_file.trim_end())).unwrap();

    println!("Total table sizes: {} bytes", total_bytes);
}

fn version() -> String {
    let mut out = String::new();
    out.push_str("pub const UNICODE_VERSION: (u32, u32, u32) = ");

    let readme =
        std::fs::read_to_string(std::path::Path::new(UNICODE_DIRECTORY).join("ReadMe.txt"))
            .unwrap();

    let prefix = "for Version ";
    let start = readme.find(prefix).unwrap() + prefix.len();
    let end = readme.find(" of the Unicode Standard.").unwrap();
    let version =
        readme[start..end].split('.').map(|v| v.parse::<u32>().expect(&v)).collect::<Vec<_>>();
    let [major, minor, micro] = [version[0], version[1], version[2]];

    out.push_str(&format!("({}, {}, {});\n", major, minor, micro));
    out
}

fn fmt_list<V: std::fmt::Debug>(values: impl IntoIterator<Item = V>) -> String {
    let pieces = values.into_iter().map(|b| format!("{:?}, ", b)).collect::<Vec<_>>();
    let mut out = String::new();
    let mut line = format!("\n    ");
    for piece in pieces {
        if line.len() + piece.len() < 98 {
            line.push_str(&piece);
        } else {
            out.push_str(line.trim_end());
            out.push('\n');
            line = format!("    {}", piece);
        }
    }
    out.push_str(line.trim_end());
    out.push('\n');
    out
}

fn generate_tests(data_path: &str, ranges: &[(&str, Vec<Range<u32>>)]) -> String {
    let mut s = String::new();
    s.push_str("#![allow(incomplete_features, unused)]\n");
    s.push_str("#![feature(const_generics)]\n\n");
    s.push_str(&format!("#[path = \"{}\"]\n", data_path));
    s.push_str("mod unicode_data;\n\n");

    s.push_str("\nfn main() {\n");

    for (property, ranges) in ranges {
        s.push_str(&format!(r#"    println!("Testing {}");"#, property));
        s.push('\n');
        s.push_str(&format!("    {}();\n", property.to_lowercase()));
        let mut is_true = Vec::new();
        let mut is_false = Vec::new();
        for ch_num in 0..(std::char::MAX as u32) {
            if std::char::from_u32(ch_num).is_none() {
                continue;
            }
            if ranges.iter().any(|r| r.contains(&ch_num)) {
                is_true.push(ch_num);
            } else {
                is_false.push(ch_num);
            }
        }

        s.push_str(&format!("    fn {}() {{\n", property.to_lowercase()));
        generate_asserts(&mut s, property, &is_true, true);
        generate_asserts(&mut s, property, &is_false, false);
        s.push_str("    }\n\n");
    }

    s.push_str("}");
    s
}

fn generate_asserts(s: &mut String, property: &str, points: &[u32], truthy: bool) {
    for range in ranges_from_set(points) {
        if range.end == range.start + 1 {
            s.push_str(&format!(
                "        assert!({}unicode_data::{}::lookup(std::char::from_u32({}).unwrap()), \"{}\");\n",
                if truthy { "" } else { "!" },
                property.to_lowercase(),
                range.start,
                std::char::from_u32(range.start).unwrap(),
        ));
        } else {
            s.push_str(&format!("        for chn in {:?}u32 {{\n", range));
            s.push_str(&format!(
                "            assert!({}unicode_data::{}::lookup(std::char::from_u32(chn).unwrap()), \"{{:?}}\", chn);\n",
                if truthy { "" } else { "!" },
                property.to_lowercase(),
        ));
            s.push_str("        }\n");
        }
    }
}

fn ranges_from_set(set: &[u32]) -> Vec<Range<u32>> {
    let mut ranges = set.iter().map(|e| (*e)..(*e + 1)).collect::<Vec<Range<u32>>>();
    merge_ranges(&mut ranges);
    ranges
}

fn merge_ranges(ranges: &mut Vec<Range<u32>>) {
    loop {
        let mut new_ranges = Vec::new();
        let mut idx_iter = 0..(ranges.len() - 1);
        while let Some(idx) = idx_iter.next() {
            let cur = ranges[idx].clone();
            let next = ranges[idx + 1].clone();
            if cur.end == next.start {
                let _ = idx_iter.next(); // skip next as we're merging it in
                new_ranges.push(cur.start..next.end);
            } else {
                new_ranges.push(cur);
            }
        }
        new_ranges.push(ranges.last().unwrap().clone());
        if new_ranges.len() == ranges.len() {
            *ranges = new_ranges;
            break;
        } else {
            *ranges = new_ranges;
        }
    }
}
<|endoftext|>


<commit_before>// Generic AArch64 target for bare-metal code - Floating point enabled
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.

use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};

pub fn target() -> Target {
    let opts = TargetOptions {
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        linker: Some("rust-lld".to_owned()),
        features: "+strict-align,+neon,+fp-armv8".to_string(),
        executables: true,
        relocation_model: RelocModel::Static,
        disable_redzone: true,
        max_atomic_width: Some(128),
        panic_strategy: PanicStrategy::Abort,
        ..Default::default()
    };
    Target {
        llvm_target: "aarch64-unknown-none".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        options: opts,
    }
}
<commit_msg>x86_64-unknown-none: Use position-independent code by default<commit_after>// Generic AArch64 target for bare-metal code - Floating point enabled
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.

use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};

pub fn target() -> Target {
    let opts = TargetOptions {
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        linker: Some("rust-lld".to_owned()),
        features: "+strict-align,+neon,+fp-armv8".to_string(),
        executables: true,
        relocation_model: RelocModel::Pic,
        disable_redzone: true,
        max_atomic_width: Some(128),
        panic_strategy: PanicStrategy::Abort,
        ..Default::default()
    };
    Target {
        llvm_target: "aarch64-unknown-none".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        options: opts,
    }
}
<|endoftext|>


<commit_before>//! `Tombstone` data description.
use crate::data::RoomName;

use super::creep::CreepPartType;

with_resource_fields_and_update_struct! {
    // Unfortunately, nested macros are not allowed, so we list all resource
    // types manually.
    //
    // This is copy-pasted from `resources.rs`, and any updates here should also be updated
    // there.
    //
    // see: https://github.com/rust-lang/rust/issues/35853
    {
        crate::websocket::types::room::resources::ResourceType;

        Energy => energy => "energy"
            => Some(crate::websocket::types::room::resources::ResourceType::Power);
        Power => power => "power"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydrogen);
        Hydrogen => hydrogen => "H"
            => Some(crate::websocket::types::room::resources::ResourceType::Oxygen);
        Oxygen => oxygen => "O"
            => Some(crate::websocket::types::room::resources::ResourceType::Utrium);
        Utrium => utrium => "U"
            => Some(crate::websocket::types::room::resources::ResourceType::Lemergium);
        Lemergium => lemergium => "L"
            => Some(crate::websocket::types::room::resources::ResourceType::Keanium);
        Keanium => keanium => "K"
            => Some(crate::websocket::types::room::resources::ResourceType::Zynthium);
        Zynthium => zynthium => "Z"
            => Some(crate::websocket::types::room::resources::ResourceType::Catalyst);
        Catalyst => catalyst => "X"
            => Some(crate::websocket::types::room::resources::ResourceType::Ghodium);
        Ghodium => ghodium => "G"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydroxide);
        Hydroxide => hydroxide => "OH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumKeanite);
        ZynthiumKeanite => zynthium_keanite => "ZK"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumLemergite);
        UtriumLemergite => utrium_lemergite => "UL"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumHydride);
        UtriumHydride => utrium_hydride => "UH"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumOxide);
        UtriumOxide => utrium_oxide => "UO"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumHydride);
        KeaniumHydride => keanium_hydride => "KH"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumOxide);
        KeaniumOxide => keanium_oxide => "KO"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumHydride);
        LemergiumHydride => lemergium_hydride => "LH"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumOxide);
        LemergiumOxide => lemergium_oxide => "LO"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumHydride);
        ZynthiumHydride => zynthium_hydride => "ZH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumOxide);
        ZynthiumOxide => zynthium_oxide => "ZO"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumHydride);
        GhodiumHydride => ghodium_hydride => "GH"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumOxide);
        GhodiumOxide => ghodium_oxide => "GO"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAcid);
        UtriumAcid => utrium_acid => "UH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAlkalide);
        UtriumAlkalide => utrium_alkalide => "UHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAcid);
        KeaniumAcid => keanium_acid => "KH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAlkalide);
        KeaniumAlkalide => keanium_alkalide => "KHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAcid);
        LemergiumAcid => lemergium_acid => "LH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAlkalide);
        LemergiumAlkalide => lemergium_alkalide => "LHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAcid);
        ZynthiumAcid => zynthium_acid => "ZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAlkalide);
        ZynthiumAlkalide => zynthium_alkalide => "ZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAcid);
        GhodiumAcid => ghodium_acid => "GH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAlkalide);
        GhodiumAlkalide => ghodium_alkalide => "GHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAcid);
        CatalyzedUtriumAcid => catalyzed_utrium_acid => "XUH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAlkalide);
        CatalyzedUtriumAlkalide => catalyzed_utrium_alkalide => "XUHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAcid);
        CatalyzedKeaniumAcid => catalyzed_keanium_acid => "XKH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAlkalide);
        CatalyzedKeaniumAlkalide => catalyzed_keanium_alkalide => "XKHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAcid);
        CatalyzedLemergiumAcid => catalyzed_lemergium_acid => "XLH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAlkalide);
        CatalyzedLemergiumAlkalide => catalyzed_lemergium_alkalide => "XLHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAcid);
        CatalyzedZynthiumAcid => catalyzed_zynthium_acid => "XZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAlkalide);
        CatalyzedZynthiumAlkalide => catalyzed_zynthium_alkalide => "XZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAcid);
        CatalyzedGhodiumAcid => catalyzed_ghodium_acid => "XGH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAlkalide);
        CatalyzedGhodiumAlkalide => catalyzed_ghodium_alkalide => "XGHO2"
            => None;
    }

    /// A tomstone - remnants of a dead creep
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct Tombstone {
        /// The user ID of the owner of the creep
        pub user: String,
        /// The body of the creep who died
        pub creep_body: Vec<CreepPartType>,
        /// The ID of the creep who died
        pub creep_id: String,
        /// The name of the creep who died
        pub creep_name: String,
        /// What the creep was saying when they died
        pub creep_saying: Option<String>,
        /// How many ticks-to-live did the creeps have when it died
        pub creep_ticks_to_live: i32,
        /// The time of death of the creep
        pub death_time: u32,
        /// The time at which this structure will decay
        pub decay_time: u32,
        // TODO: what does the tombstone of a power creep look like?
    }

    /// The update structure for a `Tombstone`.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct TombstoneUpdate { ... }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use super::Tombstone;

    #[test]
    fn parse_simple_tombstone() {
        let json = json!({
            "_id": "5ce0a11dcd8deb5a978cb216",
            "creepBody": [
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "move",
                "move",
                "move",
                "move",
                "move"
            ],
            "creepId": "5ce08e9f184f823e92616faf",
            "creepName": "HeavyConsolidator6921549",
            "creepSaying": null,
            "creepTicksToLive": 1,
            "deathTime": 6923092,
            "decayTime": 6923167,
            "room": "E8S29",
            "type": "tombstone",
            "user": "5ca80c8f3c33e30c8e85555d",
            "x": 30,
            "y": 31
        });

        let obj = Tombstone::deserialize(json).unwrap();

        assert_eq!(obj.creep_id, "5ce08e9f184f823e92616faf");
        assert_eq!(obj.creep_name, "HeavyConsolidator6921549");
    }

    #[test]
    fn parse_tombstone_with_energy() {
        let json = json!({
            "_id": "5ce0a4839c5bd560bebb03e9",
            "creepBody": [
                "move",
                "move",
                "carry",
                "work"
            ],
            "creepId": "5ce098c5c4e055067fbf182e",
            "creepName": "6922398-0",
            "creepSaying": null,
            "creepTicksToLive": 532,
            "deathTime": 6923377,
            "decayTime": 6923397,
            "energy": 44,
            "room": "E9S31",
            "type": "tombstone",
            "user": "57874d42d0ae911e3bd15bbc",
            "x": 33,
            "y": 23
        });

        let obj = Tombstone::deserialize(json).unwrap();

        assert_eq!(obj.creep_id, "5ce098c5c4e055067fbf182e");
        assert_eq!(obj.creep_name, "6922398-0");
        assert_eq!(obj.energy, 44);
    }
}
<commit_msg>Add tombstone resource iterator<commit_after>//! `Tombstone` data description.
use crate::data::RoomName;

use super::creep::CreepPartType;

with_resource_fields_and_update_struct! {
    // Unfortunately, nested macros are not allowed, so we list all resource
    // types manually.
    //
    // This is copy-pasted from `resources.rs`, and any updates here should also be updated
    // there.
    //
    // see: https://github.com/rust-lang/rust/issues/35853
    {
        crate::websocket::types::room::resources::ResourceType;

        Energy => energy => "energy"
            => Some(crate::websocket::types::room::resources::ResourceType::Power);
        Power => power => "power"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydrogen);
        Hydrogen => hydrogen => "H"
            => Some(crate::websocket::types::room::resources::ResourceType::Oxygen);
        Oxygen => oxygen => "O"
            => Some(crate::websocket::types::room::resources::ResourceType::Utrium);
        Utrium => utrium => "U"
            => Some(crate::websocket::types::room::resources::ResourceType::Lemergium);
        Lemergium => lemergium => "L"
            => Some(crate::websocket::types::room::resources::ResourceType::Keanium);
        Keanium => keanium => "K"
            => Some(crate::websocket::types::room::resources::ResourceType::Zynthium);
        Zynthium => zynthium => "Z"
            => Some(crate::websocket::types::room::resources::ResourceType::Catalyst);
        Catalyst => catalyst => "X"
            => Some(crate::websocket::types::room::resources::ResourceType::Ghodium);
        Ghodium => ghodium => "G"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydroxide);
        Hydroxide => hydroxide => "OH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumKeanite);
        ZynthiumKeanite => zynthium_keanite => "ZK"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumLemergite);
        UtriumLemergite => utrium_lemergite => "UL"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumHydride);
        UtriumHydride => utrium_hydride => "UH"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumOxide);
        UtriumOxide => utrium_oxide => "UO"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumHydride);
        KeaniumHydride => keanium_hydride => "KH"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumOxide);
        KeaniumOxide => keanium_oxide => "KO"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumHydride);
        LemergiumHydride => lemergium_hydride => "LH"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumOxide);
        LemergiumOxide => lemergium_oxide => "LO"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumHydride);
        ZynthiumHydride => zynthium_hydride => "ZH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumOxide);
        ZynthiumOxide => zynthium_oxide => "ZO"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumHydride);
        GhodiumHydride => ghodium_hydride => "GH"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumOxide);
        GhodiumOxide => ghodium_oxide => "GO"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAcid);
        UtriumAcid => utrium_acid => "UH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAlkalide);
        UtriumAlkalide => utrium_alkalide => "UHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAcid);
        KeaniumAcid => keanium_acid => "KH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAlkalide);
        KeaniumAlkalide => keanium_alkalide => "KHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAcid);
        LemergiumAcid => lemergium_acid => "LH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAlkalide);
        LemergiumAlkalide => lemergium_alkalide => "LHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAcid);
        ZynthiumAcid => zynthium_acid => "ZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAlkalide);
        ZynthiumAlkalide => zynthium_alkalide => "ZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAcid);
        GhodiumAcid => ghodium_acid => "GH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAlkalide);
        GhodiumAlkalide => ghodium_alkalide => "GHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAcid);
        CatalyzedUtriumAcid => catalyzed_utrium_acid => "XUH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAlkalide);
        CatalyzedUtriumAlkalide => catalyzed_utrium_alkalide => "XUHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAcid);
        CatalyzedKeaniumAcid => catalyzed_keanium_acid => "XKH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAlkalide);
        CatalyzedKeaniumAlkalide => catalyzed_keanium_alkalide => "XKHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAcid);
        CatalyzedLemergiumAcid => catalyzed_lemergium_acid => "XLH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAlkalide);
        CatalyzedLemergiumAlkalide => catalyzed_lemergium_alkalide => "XLHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAcid);
        CatalyzedZynthiumAcid => catalyzed_zynthium_acid => "XZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAlkalide);
        CatalyzedZynthiumAlkalide => catalyzed_zynthium_alkalide => "XZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAcid);
        CatalyzedGhodiumAcid => catalyzed_ghodium_acid => "XGH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAlkalide);
        CatalyzedGhodiumAlkalide => catalyzed_ghodium_alkalide => "XGHO2"
            => None;
    }

    /// A tomstone - remnants of a dead creep
    #[derive(Clone, Debug, PartialEq)]
    #[serde(rename_all = "camelCase")]
    pub struct Tombstone {
        /// The user ID of the owner of the creep
        pub user: String,
        /// The body of the creep who died
        pub creep_body: Vec<CreepPartType>,
        /// The ID of the creep who died
        pub creep_id: String,
        /// The name of the creep who died
        pub creep_name: String,
        /// What the creep was saying when they died
        pub creep_saying: Option<String>,
        /// How many ticks-to-live did the creeps have when it died
        pub creep_ticks_to_live: i32,
        /// The time of death of the creep
        pub death_time: u32,
        /// The time at which this structure will decay
        pub decay_time: u32,
        // TODO: what does the tombstone of a power creep look like?
    }

    /// The update structure for a `Tombstone`.
    #[derive(Clone, Debug)]
    #[serde(rename_all = "camelCase")]
    pub struct TombstoneUpdate { ... }
}

resource_iterator_for! {
    // Unfortunately, nested macros are not allowed, so we list all resource
    // types manually.
    //
    // This is copy-pasted from `resources.rs`, and any updates here should also be updated
    // there.
    //
    // see: https://github.com/rust-lang/rust/issues/35853
    {
        crate::websocket::types::room::resources::ResourceType;

        Energy => energy => "energy"
            => Some(crate::websocket::types::room::resources::ResourceType::Power);
        Power => power => "power"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydrogen);
        Hydrogen => hydrogen => "H"
            => Some(crate::websocket::types::room::resources::ResourceType::Oxygen);
        Oxygen => oxygen => "O"
            => Some(crate::websocket::types::room::resources::ResourceType::Utrium);
        Utrium => utrium => "U"
            => Some(crate::websocket::types::room::resources::ResourceType::Lemergium);
        Lemergium => lemergium => "L"
            => Some(crate::websocket::types::room::resources::ResourceType::Keanium);
        Keanium => keanium => "K"
            => Some(crate::websocket::types::room::resources::ResourceType::Zynthium);
        Zynthium => zynthium => "Z"
            => Some(crate::websocket::types::room::resources::ResourceType::Catalyst);
        Catalyst => catalyst => "X"
            => Some(crate::websocket::types::room::resources::ResourceType::Ghodium);
        Ghodium => ghodium => "G"
            => Some(crate::websocket::types::room::resources::ResourceType::Hydroxide);
        Hydroxide => hydroxide => "OH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumKeanite);
        ZynthiumKeanite => zynthium_keanite => "ZK"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumLemergite);
        UtriumLemergite => utrium_lemergite => "UL"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumHydride);
        UtriumHydride => utrium_hydride => "UH"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumOxide);
        UtriumOxide => utrium_oxide => "UO"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumHydride);
        KeaniumHydride => keanium_hydride => "KH"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumOxide);
        KeaniumOxide => keanium_oxide => "KO"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumHydride);
        LemergiumHydride => lemergium_hydride => "LH"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumOxide);
        LemergiumOxide => lemergium_oxide => "LO"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumHydride);
        ZynthiumHydride => zynthium_hydride => "ZH"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumOxide);
        ZynthiumOxide => zynthium_oxide => "ZO"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumHydride);
        GhodiumHydride => ghodium_hydride => "GH"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumOxide);
        GhodiumOxide => ghodium_oxide => "GO"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAcid);
        UtriumAcid => utrium_acid => "UH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::UtriumAlkalide);
        UtriumAlkalide => utrium_alkalide => "UHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAcid);
        KeaniumAcid => keanium_acid => "KH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::KeaniumAlkalide);
        KeaniumAlkalide => keanium_alkalide => "KHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAcid);
        LemergiumAcid => lemergium_acid => "LH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::LemergiumAlkalide);
        LemergiumAlkalide => lemergium_alkalide => "LHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAcid);
        ZynthiumAcid => zynthium_acid => "ZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::ZynthiumAlkalide);
        ZynthiumAlkalide => zynthium_alkalide => "ZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAcid);
        GhodiumAcid => ghodium_acid => "GH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::GhodiumAlkalide);
        GhodiumAlkalide => ghodium_alkalide => "GHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAcid);
        CatalyzedUtriumAcid => catalyzed_utrium_acid => "XUH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedUtriumAlkalide);
        CatalyzedUtriumAlkalide => catalyzed_utrium_alkalide => "XUHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAcid);
        CatalyzedKeaniumAcid => catalyzed_keanium_acid => "XKH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedKeaniumAlkalide);
        CatalyzedKeaniumAlkalide => catalyzed_keanium_alkalide => "XKHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAcid);
        CatalyzedLemergiumAcid => catalyzed_lemergium_acid => "XLH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedLemergiumAlkalide);
        CatalyzedLemergiumAlkalide => catalyzed_lemergium_alkalide => "XLHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAcid);
        CatalyzedZynthiumAcid => catalyzed_zynthium_acid => "XZH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedZynthiumAlkalide);
        CatalyzedZynthiumAlkalide => catalyzed_zynthium_alkalide => "XZHO2"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAcid);
        CatalyzedGhodiumAcid => catalyzed_ghodium_acid => "XGH2O"
            => Some(crate::websocket::types::room::resources::ResourceType::CatalyzedGhodiumAlkalide);
        CatalyzedGhodiumAlkalide => catalyzed_ghodium_alkalide => "XGHO2"
            => None;
    }

    /// Resource iterator for a `Tombstone`.
    #[derive(Debug)]
    pub struct TombstoneContents(Tombstone);
}

impl Tombstone {
    /// Iterates over this structure's resources.
    pub fn resources(&self) -> TombstoneContents {
        TombstoneContents::new(self)
    }
}

#[cfg(test)]
mod test {
    use serde::Deserialize;

    use super::Tombstone;

    #[test]
    fn parse_simple_tombstone() {
        let json = json!({
            "_id": "5ce0a11dcd8deb5a978cb216",
            "creepBody": [
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "carry",
                "move",
                "move",
                "move",
                "move",
                "move"
            ],
            "creepId": "5ce08e9f184f823e92616faf",
            "creepName": "HeavyConsolidator6921549",
            "creepSaying": null,
            "creepTicksToLive": 1,
            "deathTime": 6923092,
            "decayTime": 6923167,
            "room": "E8S29",
            "type": "tombstone",
            "user": "5ca80c8f3c33e30c8e85555d",
            "x": 30,
            "y": 31
        });

        let obj = Tombstone::deserialize(json).unwrap();

        assert_eq!(obj.creep_id, "5ce08e9f184f823e92616faf");
        assert_eq!(obj.creep_name, "HeavyConsolidator6921549");
    }

    #[test]
    fn parse_tombstone_with_energy() {
        let json = json!({
            "_id": "5ce0a4839c5bd560bebb03e9",
            "creepBody": [
                "move",
                "move",
                "carry",
                "work"
            ],
            "creepId": "5ce098c5c4e055067fbf182e",
            "creepName": "6922398-0",
            "creepSaying": null,
            "creepTicksToLive": 532,
            "deathTime": 6923377,
            "decayTime": 6923397,
            "energy": 44,
            "room": "E9S31",
            "type": "tombstone",
            "user": "57874d42d0ae911e3bd15bbc",
            "x": 33,
            "y": 23
        });

        let obj = Tombstone::deserialize(json).unwrap();

        assert_eq!(obj.creep_id, "5ce098c5c4e055067fbf182e");
        assert_eq!(obj.creep_name, "6922398-0");
        assert_eq!(obj.energy, 44);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

extern crate abstract_ns;
extern crate futures;
extern crate getopts;
extern crate ns_dns_tokio;
extern crate rand;
extern crate tokio_core;
extern crate tokio_io;

// the device under test
extern crate net_interceptor;

use futures::{Future, Stream};
use futures::sync::oneshot;
use futures::sync::oneshot::{Sender};
use tokio_core::net::{TcpListener};
use tokio_core::reactor::Core;

use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::{Arc, Barrier};
use std::thread;

use net_interceptor::logging::unittestlogger;

fn stopper(oneshot_sender_stream: Sender<i64>) -> Arc<Barrier> {
    // barrier awaits the releaser thread and the signalling one
    let barrier = Arc::new(Barrier::new(2));
    let copy_for_thread = barrier.clone();
    // the releaser thread
    thread::spawn(move || {
        debug!("waiting for end");
        copy_for_thread.wait();
        debug!("signalling end");
        // release the future blockig core.run()
        oneshot_sender_stream.send(1).unwrap();
    });
    barrier
}

#[test]
fn test_infra_connect() {
    unittestlogger();

    // this is the main event loop, powered by tokio core
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let bind_socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12000);
    let listener = TcpListener::bind(&bind_socket_addr, &handle)
        .expect(&format!("Unable to bind to {}", &bind_socket_addr));
    warn!("Listening on {}", listener.local_addr().unwrap());

    let addr = listener.local_addr().unwrap();
    assert!(addr.port() == 12000, "should accept {}");

    let connections = listener.incoming();
    let (tx, signal) = oneshot::channel::<i64>();
    let barrier = stopper(tx);

    let acceptor = connections.for_each(move |(socket, _peer_addr)| {
        warn!("connection from {}", _peer_addr);
        barrier.wait();
        Ok(())
    });

    // register the acceptor in the reactor core
    // the map_err is a hack to satisfy connections.for_each above
    handle.spawn(acceptor.map_err(|_|()));

    core.run(signal).unwrap();
}
<commit_msg>timeout and select working<commit_after>#[macro_use]
extern crate log;

extern crate abstract_ns;
extern crate futures;
extern crate getopts;
extern crate ns_dns_tokio;
extern crate rand;
extern crate tokio_core;
extern crate tokio_io;

// the device under test
extern crate net_interceptor;

use futures::{Future, Stream, IntoFuture};
use futures::sync::oneshot;
use futures::sync::oneshot::{Sender};
use tokio_core::net::{TcpListener};
use tokio_core::reactor::{Core, Timeout};

use std::time::Duration;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::{Arc, Barrier};
use std::thread;

use net_interceptor::logging::unittestlogger;

fn stopper(oneshot_sender_stream: Sender<i64>) -> Arc<Barrier> {
    // barrier awaits the releaser thread and the signalling one
    let barrier = Arc::new(Barrier::new(2));
    let copy_for_thread = barrier.clone();
    // the releaser thread
    thread::spawn(move || {
        debug!("waiting for end");
        copy_for_thread.wait();
        debug!("signalling end");
        // release the future blockig core.run()
        oneshot_sender_stream.send(1).unwrap();
    });
    barrier
}

#[test]
fn test_infra_connect() {
    unittestlogger();

    // this is the main event loop, powered by tokio core
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let bind_socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12000);
    let listener = TcpListener::bind(&bind_socket_addr, &handle)
        .expect(&format!("Unable to bind to {}", &bind_socket_addr));
    warn!("Listening on {}", listener.local_addr().unwrap());

    let addr = listener.local_addr().unwrap();
    assert!(addr.port() == 12000, "should accept {}");

    let connections = listener.incoming();
    let (tx, signal) = oneshot::channel::<i64>();
    let barrier = stopper(tx);

    let acceptor = connections.for_each(move |(socket, _peer_addr)| {
        warn!("connection from {}", _peer_addr);
        barrier.wait();
        Ok(())
    });

    // register the acceptor in the reactor core
    // the map_err is a hack to satisfy connections.for_each above
    handle.spawn(acceptor.map_err(|_|()));

    let timeout = Timeout::new(std::time::Duration::from_secs(5), &handle).into_future().flatten();

    core.run(timeout.select2(signal));//.unwrap();
}
<|endoftext|>