<commit_before>use serde::{ser};
use std::mem::transmute;
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use std::fmt::{Display,Debug};
use std::fmt;
use serialize::{
    serialize_u64
};

// Option to display references as nested
pub static mut NESTED_REFERENCE: bool = false;

#[derive(Serialize, Debug)]
pub struct MftEnumReference{
    #[serde(serialize_with = "serialize_u64")]
    reference: u64,
    entry: u64,
    sequence: u16
}

// Represents a MFT Reference struct
// https://msdn.microsoft.com/en-us/library/bb470211(v=vs.85).aspx
// https://jmharkness.wordpress.com/2011/01/27/mft-file-reference-number/
#[derive(Hash, Eq, PartialEq, Copy, Clone)]
pub struct MftReference(pub u64);
impl MftReference{
    pub fn from_entry_and_seq(&mut self, entry: u64, sequence: u16){
        let entry_buffer: [u8; 8] = unsafe {
            transmute(entry.to_le())
        };
        let seq_buffer: [u8; 2] = unsafe {
            transmute(sequence.to_le())
        };
        let mut ref_buffer = vec![];
        ref_buffer.extend_from_slice(&entry_buffer[0..6]);
        ref_buffer.extend_from_slice(&seq_buffer);

        self.0 = LittleEndian::read_u64(&ref_buffer[0..8]);
    }
    pub fn get_from_entry_and_seq(entry: u64, sequence: u16) -> MftReference{
        let entry_buffer: [u8; 8] = unsafe {
            transmute(entry.to_le())
        };
        let seq_buffer: [u8; 2] = unsafe {
            transmute(sequence.to_le())
        };
        let mut ref_buffer = vec![];
        ref_buffer.extend_from_slice(&entry_buffer[0..6]);
        ref_buffer.extend_from_slice(&seq_buffer);

        MftReference(LittleEndian::read_u64(&ref_buffer[0..8]))
    }
    pub fn get_enum_ref(&self)->MftEnumReference{
        let mut raw_buffer = vec![];
        raw_buffer.write_u64::<LittleEndian>(self.0).unwrap();
        MftEnumReference{
            reference: LittleEndian::read_u64(&raw_buffer[0..8]),
            entry: LittleEndian::read_u64(
                &[&raw_buffer[0..6], &[0,0]].concat()
            ),
            sequence: LittleEndian::read_u16(&raw_buffer[6..8])
        }
    }
    pub fn get_entry_number(&self)->u64{
        let mut raw_buffer = vec![];
        raw_buffer.write_u64::<LittleEndian>(self.0).unwrap();

        LittleEndian::read_u64(
            &[&raw_buffer[0..6], &[0,0]].concat()
        )
    }
}
impl Display for MftReference {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,"{}",self.0)
    }
}
impl Debug for MftReference {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,"{}",self.0)
    }
}
impl ser::Serialize for MftReference {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer
    {
        // If NESTED_REFERENCE we need to serialize the enumerated structure
        if unsafe{NESTED_REFERENCE} {
            serializer.serialize_newtype_struct("mft_reference",&self.get_enum_ref())
        } else {
            // Just serialize the u64 version
            serialize_u64(&self.0,serializer)
        }
    }
}

#[test]
fn test_reference() {
    use std::mem;
    let raw_reference: &[u8] = &[0x73,0x00,0x00,0x00,0x00,0x00,0x68,0x91];

    let mft_reference = MftReference(
        LittleEndian::read_u64(&raw_reference[0..8])
    );
    assert_eq!(mft_reference.0,10477624533077459059);
    assert_eq!(format!("{}", mft_reference),"10477624533077459059");
    // assert_eq!(mft_reference.sequence,37224);

    let mft_reference_01 = MftReference::get_from_entry_and_seq(
        115,
        37224
    );
    assert_eq!(mft_reference_01.0,10477624533077459059);

    let mut mft_reference_02: MftReference = unsafe {
        mem::zeroed()
    };
    assert_eq!(mft_reference_02.0,0);
    mft_reference_02.from_entry_and_seq(
        115,
        37224
    );
    assert_eq!(mft_reference_02.0,10477624533077459059);
}
<commit_msg>renamed test function<commit_after>use serde::{ser};
use std::mem::transmute;
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use std::fmt::{Display,Debug};
use std::fmt;
use serialize::{
    serialize_u64
};

// Option to display references as nested
pub static mut NESTED_REFERENCE: bool = false;

#[derive(Serialize, Debug)]
pub struct MftEnumReference{
    #[serde(serialize_with = "serialize_u64")]
    reference: u64,
    entry: u64,
    sequence: u16
}

// Represents a MFT Reference struct
// https://msdn.microsoft.com/en-us/library/bb470211(v=vs.85).aspx
// https://jmharkness.wordpress.com/2011/01/27/mft-file-reference-number/
#[derive(Hash, Eq, PartialEq, Copy, Clone)]
pub struct MftReference(pub u64);
impl MftReference{
    pub fn from_entry_and_seq(&mut self, entry: u64, sequence: u16){
        let entry_buffer: [u8; 8] = unsafe {
            transmute(entry.to_le())
        };
        let seq_buffer: [u8; 2] = unsafe {
            transmute(sequence.to_le())
        };
        let mut ref_buffer = vec![];
        ref_buffer.extend_from_slice(&entry_buffer[0..6]);
        ref_buffer.extend_from_slice(&seq_buffer);

        self.0 = LittleEndian::read_u64(&ref_buffer[0..8]);
    }
    pub fn get_from_entry_and_seq(entry: u64, sequence: u16) -> MftReference{
        let entry_buffer: [u8; 8] = unsafe {
            transmute(entry.to_le())
        };
        let seq_buffer: [u8; 2] = unsafe {
            transmute(sequence.to_le())
        };
        let mut ref_buffer = vec![];
        ref_buffer.extend_from_slice(&entry_buffer[0..6]);
        ref_buffer.extend_from_slice(&seq_buffer);

        MftReference(LittleEndian::read_u64(&ref_buffer[0..8]))
    }
    pub fn get_enum_ref(&self)->MftEnumReference{
        let mut raw_buffer = vec![];
        raw_buffer.write_u64::<LittleEndian>(self.0).unwrap();
        MftEnumReference{
            reference: LittleEndian::read_u64(&raw_buffer[0..8]),
            entry: LittleEndian::read_u64(
                &[&raw_buffer[0..6], &[0,0]].concat()
            ),
            sequence: LittleEndian::read_u16(&raw_buffer[6..8])
        }
    }
    pub fn get_entry_number(&self)->u64{
        let mut raw_buffer = vec![];
        raw_buffer.write_u64::<LittleEndian>(self.0).unwrap();

        LittleEndian::read_u64(
            &[&raw_buffer[0..6], &[0,0]].concat()
        )
    }
}
impl Display for MftReference {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,"{}",self.0)
    }
}
impl Debug for MftReference {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,"{}",self.0)
    }
}
impl ser::Serialize for MftReference {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer
    {
        // If NESTED_REFERENCE we need to serialize the enumerated structure
        if unsafe{NESTED_REFERENCE} {
            serializer.serialize_newtype_struct("mft_reference",&self.get_enum_ref())
        } else {
            // Just serialize the u64 version
            serialize_u64(&self.0,serializer)
        }
    }
}

#[test]
fn test_mft_reference() {
    use std::mem;
    let raw_reference: &[u8] = &[0x73,0x00,0x00,0x00,0x00,0x00,0x68,0x91];

    let mft_reference = MftReference(
        LittleEndian::read_u64(&raw_reference[0..8])
    );
    assert_eq!(mft_reference.0,10477624533077459059);
    assert_eq!(format!("{}", mft_reference),"10477624533077459059");
    // assert_eq!(mft_reference.sequence,37224);

    let mft_reference_01 = MftReference::get_from_entry_and_seq(
        115,
        37224
    );
    assert_eq!(mft_reference_01.0,10477624533077459059);

    let mut mft_reference_02: MftReference = unsafe {
        mem::zeroed()
    };
    assert_eq!(mft_reference_02.0,0);
    mft_reference_02.from_entry_and_seq(
        115,
        37224
    );
    assert_eq!(mft_reference_02.0,10477624533077459059);
}
<|endoftext|>


<commit_before>//! REPL (Read–eval–print loop) executable module provides interactive
//! execution of Tokamak language.

extern crate env_logger;
extern crate libc;
extern crate llvm;
extern crate llvm_sys;
#[macro_use]
extern crate log;
extern crate parser;
extern crate rl_sys; // libreadline

extern crate common;
extern crate exec;
extern crate plan;

use std::io::{self, BufWriter, Write};
use llvm::{JitCompiler, Module, ValueRef};
use rl_sys::readline;

use common::page::{Page, ROWBATCH_SIZE};
use common::page_printer::{ColumnarPagePrinter, PagePrinter};
use common::plugin::{PluginManager};
use common::types::HasType;
use common::session::Session;
use exec::NamedSchema;
use exec::processor::MapCompiler;
use parser::lexer::{self, Token};
use parser::parser as p;
use plan::expr::Expr;

// Logical Components
// Repl - Main compoenent for REPL
// SymbolTable - HashMap, keeping functions and variables in top-level module
// IncrementalCompiler - Imitate incremental execution with some tricky way
// ValuePrinter - Print the value contents.

pub struct Repl<'a> {
  // for system
  ctx: ReplContext<'a>,

  // in/out descriptors
  out: &'a mut io::Write, // can be stdout or anything else,
}

pub struct ReplContext<'a> {
  jit: &'a JitCompiler,
  module: Module,
  sess: &'a Session,
  plugin_mgr: &'a PluginManager<'a>,
}

#[derive(Eq, Hash, PartialEq)]
pub enum SymbolKind {
  // Function
  Func,
  // Immutable value
  ImmVal,
  // Mutable value
  MutVal,
}

pub struct Symbol;

fn is_complete_stmt(tokens: &Vec<Token>) -> bool {
  tokens.len() == 0
}

impl<'a> Repl<'a> {
  pub fn new(sess: &'a Session,
             plugin_mgr: &'a PluginManager<'a>,
             jit: &'a JitCompiler,
             out: &'a mut io::Write)
             -> Repl<'a> {
    Repl {
      ctx: ReplContext {
        jit: jit,
        module: Module::new(jit.context(), "root"),
        sess: sess,
        plugin_mgr: plugin_mgr,
      },
      out: out,
    }
  }

  pub fn print(&mut self, msg: &str) -> &mut Self {
    self.out.write(msg.as_bytes()).ok().unwrap();
    self
  }

  pub fn newline(&mut self) -> &mut Self {
    self.out.write("\n".as_bytes()).ok().unwrap();
    self
  }

  pub fn flush(&mut self) -> &mut Self {
    self.out.flush().ok().unwrap();
    self
  }

  /// for unit test
  pub fn eval(&mut self, line: &str) -> Result<String, String> {
    let tokens = lexer::tokenize(&line);
    let parsed = p::parse(&tokens[..], &vec![]);

    match parsed {
      Ok((exprs, remain_tokens)) => {
        if is_complete_stmt(&remain_tokens) {
          Evaluator::eval(&self.ctx, &exprs[0])
        } else {
          Err("Incomplete statement".to_string())
        }
      }
      Err(msg) => Err(format!("{}", msg)),
    }
  }

  /// Incrementally parse and eval statements
  pub fn try_eval(&mut self, tokens: &mut Vec<Token>, ast: &mut Vec<Expr>, line: &str) {
    tokens.extend(lexer::tokenize(&line));
    let parsed = p::parse(&tokens[..], &ast[..]);

    match parsed {
      Ok((exprs, remain_tokens)) => {
        if is_complete_stmt(&remain_tokens) {
          match Evaluator::eval(&self.ctx, &exprs[0]) {
            Ok(result) => {
              self.print(&result).newline().flush();
              ast.clear();
              tokens.clear();
            }
            Err(msg) => {
              panic!("{}", msg);
            }
          }
        }
      }

      Err(msg) => println!("{}", msg),
    }
  }

  /// Loop for read and eval
  pub fn eval_loop(&mut self) {

    let mut linenum = 1usize; // repl line number
    let mut tokens = Vec::new();
    let mut ast = Vec::new();

    loop {
      match readline::readline(&format!("\x1b[33mtkm [{}]> \x1b[0m", linenum)) {
        Ok(Some(line)) => self.try_eval(&mut ast, &mut tokens, &line),
        Ok(None) => break,
        Err(e) => println!("{}", e),
      };

      linenum += 1;
    }
  }
}

pub struct Evaluator;

impl Evaluator {
  pub fn eval(ctx: &ReplContext, expr: &Expr) -> Result<String, String> {
    ctx.jit.add_module(&ctx.module);

    match MapCompiler::compile(ctx.jit,
                               &ctx.module,
                               ctx.plugin_mgr.fn_registry(),
                               ctx.sess,
                               &NamedSchema::new(&[], &[]),
                               &[expr]) {

      Ok((llvm_func, eval_fn)) => {
        let result_ty = expr.ty();
        let in_page = Page::empty_page(0);
        let mut out_page = Page::new(&[result_ty], None);
        let sellist: [usize; ROWBATCH_SIZE] = unsafe { ::std::mem::uninitialized() };
        eval_fn(&in_page, &mut out_page, sellist.as_ptr(), ROWBATCH_SIZE);
        out_page.set_value_count(1); // because of a single expression

        let mut buf: Vec<u8> = Vec::new();
        ColumnarPagePrinter::write(&[result_ty], &out_page, &mut BufWriter::new(&mut buf));

        ctx.jit.remove_module(&ctx.module);
        llvm::delete_func(&llvm_func);
        Ok(String::from_utf8(buf).ok().expect("invalid UTF-8 characters"))
      }
      Err(msg) => {
        panic!("error");
      }
    }
  }
}

pub fn main() {
  env_logger::init().unwrap();

  // Output stream for repl
  let mut stdout = &mut io::stdout();

  // Initialize system context
  let plugin_mgr = &PluginManager::new();
  let jit = &JitCompiler::from_bc("../common/target/ir/common.bc").ok().unwrap();
  assert!(jit.get_ty("struct.Chunk").is_some());
  assert!(jit.get_ty("struct.Page").is_some());
  let sess = &Session;

  let mut repl = Repl::new(sess, plugin_mgr, jit, stdout);
  repl.eval_loop();
}
<commit_msg>better error handling.<commit_after>//! REPL (Read–eval–print loop) executable module provides interactive
//! execution of Tokamak language.

extern crate env_logger;
extern crate libc;
extern crate llvm;
extern crate llvm_sys;
#[macro_use]
extern crate log;
extern crate parser;
extern crate rl_sys; // libreadline

extern crate common;
extern crate exec;
extern crate plan;

use std::io::{self, BufWriter, Write};
use llvm::{JitCompiler, Module, ValueRef};
use log::LogLevel;
use rl_sys::readline;

use common::page::{Page, ROWBATCH_SIZE};
use common::page_printer::{ColumnarPagePrinter, PagePrinter};
use common::plugin::PluginManager;
use common::types::HasType;
use common::session::Session;
use exec::NamedSchema;
use exec::processor::MapCompiler;
use parser::lexer::{self, Token};
use parser::parser as p;
use plan::expr::Expr;

// Logical Components
// Repl - Main compoenent for REPL
// SymbolTable - HashMap, keeping functions and variables in top-level module
// IncrementalCompiler - Imitate incremental execution with some tricky way
// ValuePrinter - Print the value contents.

pub struct Repl<'a> {
  // for system
  ctx: ReplContext<'a>,

  // in/out descriptors
  out: &'a mut io::Write, // can be stdout or anything else,
}

pub struct ReplContext<'a> {
  jit: &'a JitCompiler,
  module: Module,
  sess: &'a Session,
  plugin_mgr: &'a PluginManager<'a>,
}

#[derive(Eq, Hash, PartialEq)]
pub enum SymbolKind {
  // Function
  Func,
  // Immutable value
  ImmVal,
  // Mutable value
  MutVal,
}

pub struct Symbol;

fn is_complete_stmt(tokens: &Vec<Token>) -> bool {
  tokens.len() == 0
}

impl<'a> Repl<'a> {
  pub fn new(sess: &'a Session,
             plugin_mgr: &'a PluginManager<'a>,
             jit: &'a JitCompiler,
             out: &'a mut io::Write)
             -> Repl<'a> {
    Repl {
      ctx: ReplContext {
        jit: jit,
        module: Module::new(jit.context(), "root"),
        sess: sess,
        plugin_mgr: plugin_mgr,
      },
      out: out,
    }
  }

  pub fn print(&mut self, msg: &str) -> &mut Self {
    self.out.write(msg.as_bytes()).ok().unwrap();
    self
  }

  pub fn newline(&mut self) -> &mut Self {
    self.out.write("\n".as_bytes()).ok().unwrap();
    self
  }

  pub fn flush(&mut self) -> &mut Self {
    self.out.flush().ok().unwrap();
    self
  }

  /// for unit test
  pub fn eval_inline(&mut self, line: &str) -> Result<Option<String>, String> {
    self.eval(&mut Vec::new(), &mut Vec::new(), line)
  }

  /// Incrementally parse and eval statements
  ///
  /// The result is set only if parsing and evaluation are completed.
  /// The result is none if statement is incomplete.
  /// The error is set if some error occurs in parsing, code generation or evaluation phase.
  pub fn eval(&mut self,
              tokens: &mut Vec<Token>,
              ast: &mut Vec<Expr>,
              line: &str)
              -> Result<Option<String>, String> {

    tokens.extend(lexer::tokenize(&line));
    let parsed = p::parse(&tokens[..], &ast[..]);

    match parsed {
      Ok((exprs, remain_tokens)) => {
        if is_complete_stmt(&remain_tokens) {
          match Evaluator::eval(&self.ctx, &exprs[0]) {
            Ok(result) => Ok(Some(result)),
            Err(errmsg) => Err(errmsg),
          }
        } else {
          Ok(None)
        }
      }
      Err(msg) => Err(msg),
    }
  }

  /// Loop for read and eval
  pub fn eval_loop(&mut self) {

    let mut linenum = 1usize; // repl line number
    let mut tokens = Vec::new();
    let mut ast = Vec::new();

    loop {
      match readline::readline(&format!("\x1b[33mtkm [{}]> \x1b[0m", linenum)) {
        Ok(Some(line)) => {
          match self.eval(&mut ast, &mut tokens, &line) {
            Ok(Some(result)) => {
              self.print(&result).newline().flush();
              ast.clear();
              tokens.clear();
            }
            Ok(None) => {
              // when statement is incomplete
            }
            Err(msg) => {
              self.print(&msg).newline().flush();
              ast.clear();
              tokens.clear();
            }
          }
        }
        Ok(None) => break, // when eof
        Err(e) => {
          // readline error
          self.print(&format!("{}", e)).newline().flush();
        }
      };

      linenum += 1;
    }
  }
}

pub struct Evaluator;

impl Evaluator {
  pub fn eval(ctx: &ReplContext, expr: &Expr) -> Result<String, String> {
    ctx.jit.add_module(&ctx.module);

    match MapCompiler::compile(ctx.jit,
                               &ctx.module,
                               ctx.plugin_mgr.fn_registry(),
                               ctx.sess,
                               &NamedSchema::new(&[], &[]),
                               &[expr]) {

      Ok((llvm_func, eval_fn)) => {
        let result_ty = expr.ty();
        let in_page = Page::empty_page(0);
        let mut out_page = Page::new(&[result_ty], None);
        let sellist: [usize; ROWBATCH_SIZE] = unsafe { ::std::mem::uninitialized() };
        eval_fn(&in_page, &mut out_page, sellist.as_ptr(), ROWBATCH_SIZE);
        out_page.set_value_count(1); // because of a single expression

        let mut buf: Vec<u8> = Vec::new();
        ColumnarPagePrinter::write(&[result_ty], &out_page, &mut BufWriter::new(&mut buf));

        ctx.jit.remove_module(&ctx.module);
        llvm::delete_func(&llvm_func);
        Ok(String::from_utf8(buf).ok().expect("invalid UTF-8 characters"))
      }
      Err(_) => {
        panic!("Compilation error");
      }
    }
  }
}

pub fn main() {
  env_logger::init().unwrap();

  // Output stream for repl
  let mut stdout = &mut io::stdout();

  // Initialize system context
  let plugin_mgr = &PluginManager::new();
  let jit = &JitCompiler::from_bc("../common/target/ir/common.bc").ok().unwrap();
  assert!(jit.get_ty("struct.Chunk").is_some());
  assert!(jit.get_ty("struct.Page").is_some());
  let sess = &Session;

  let mut repl = Repl::new(sess, plugin_mgr, jit, stdout);
  repl.eval_loop();
}
<|endoftext|>


<commit_before>use core::prelude::*;
use core::default::Default;
use boxed::Box;
use fn_box::FnBox;
use collections::RingBuf;
use global::global;
use alloc::heap::allocate;
use spinlock::{Spinlock, SpinlockGuard};

pub fn spawn<F, R>(f:F) -> Future<R> where F: FnOnce()->R, F:Send {
    global().scheduler.spawn(f)
}

pub unsafe fn reschedule(current_rsp: uint) -> ! {
    // switch stack so we can park current thread

    call_on_stack(inner, current_rsp, scheduler_stack_top());

    fn inner(current_rsp: uint) -> ! {
        // try to park current thread
        let current = Thread::from_rsp(current_rsp);
        let scheduler = &global().scheduler;

        let thread = match scheduler.try_park(current) {
            Ok(()) => scheduler.schedule(),
            Err(thread) => thread,
        };
        start_thread(thread)
    }
}

pub unsafe fn schedule() -> ! {
    call_on_stack(inner, scheduler_stack_top());

    unsafe fn call_on_stack(function: fn() -> !, stack_top: uint) -> ! {
        asm!("call $0;" :: "r"(function), "{rsp}"(stack_top) :: "intel", "volatile");
        panic!("diverging fn returned");
    }

    fn inner() -> ! {
        // TODO FIXME kill current thread and deallocate stack
        start_thread(global().scheduler.schedule())
    }
}

fn start_thread(thread: Thread) -> ! {
    #[allow(improper_ctypes)]
    extern {
        fn pop_registers_and_iret(rsp: uint) -> !;
    }

    fn new_stack() -> uint {
        const NEW_STACK_SIZE: uint = 4096*2;
        let stack_bottom = unsafe{allocate(NEW_STACK_SIZE, 4096)};
        let stack_top = stack_bottom as uint + NEW_STACK_SIZE;
        stack_top
    }

    fn invoke(function: Box<FnBox() + Send>) -> ! {
        unsafe{::enable_interrupts()};
        function.call_once(());
        unsafe{asm!("int $$66" :::: "volatile")};
        unreachable!();
    }

    match thread {
        Thread{state: ThreadState::Active{rsp}} => {
            unsafe{pop_registers_and_iret(rsp)}
        },
        Thread{state: ThreadState::New{function}} => {
            println!("new");
            let new_stack_top = new_stack();
            unsafe{call_on_stack(invoke, function, new_stack_top)}
        },
    }
}

fn scheduler_stack_top() -> uint {
    const SCHEDULER_STACK_SIZE: uint = 4096;
    static SCHEDULER_STACK: [u8; SCHEDULER_STACK_SIZE] = [0; SCHEDULER_STACK_SIZE];

    &SCHEDULER_STACK as *const [u8; 4096] as uint + SCHEDULER_STACK_SIZE
}

unsafe fn call_on_stack<Arg>(function: fn(Arg) -> !, arg: Arg, stack_top: uint) -> ! {
    asm!("call $0;" :: "r"(function), "{rdi}"(arg), "{rsp}"(stack_top) :
        : "intel", "volatile");
    panic!("diverging fn returned");
}

pub struct Future<T>;

pub struct Thread {
    state: ThreadState,
}

impl Thread {
    fn new<F>(f: F) -> Thread where F : FnOnce(), F: Send {
        Thread {
            state: ThreadState::New {
                function: box f,
            }
        }
    }

    pub fn from_rsp(rsp: uint) -> Thread {
        Thread {
            state: ThreadState::Active {
                rsp: rsp,
            }
        }
    }
}

impl Default for Thread {
    fn default() -> Thread {
        Thread::new(|| print!("."))
    }
}

enum ThreadState {
    New {
        function: Box<FnBox() + Send>,
    },
    Active {
        rsp: uint,
    }
}

pub struct GlobalScheduler {
    threads: Spinlock<RingBuf<Thread>>,
}

impl GlobalScheduler {
    pub fn new() -> GlobalScheduler {
        GlobalScheduler{
            threads: Spinlock::new(RingBuf::new()),
        }
    }

    fn spawn<F, R>(&self, f:F) -> Future<R> where F: FnOnce()->R, F: Send {

        //let (tx, rx) = channel();

        self.threads.lock().push_back(Thread::new(move |:| {
            /*tx.send_opt(*/ f();
        }));

        unsafe{::enable_interrupts()};

        Future/*::from_receiver(rx)*/
    }

    fn try_park(&self, thread: Thread) -> Result<(), Thread> {
        match self.threads.try_lock() {
            Some(mut threads) => Ok(threads.push_back(thread)),
            None => Err(thread),
        }
    }

    fn schedule(&self) -> Thread {
        self.threads.lock().pop_front().unwrap_or_default()
    }
}<commit_msg>some minor improvements<commit_after>use core::prelude::*;
use core::default::Default;
use boxed::Box;
use fn_box::FnBox;
use collections::RingBuf;
use global::global;
use alloc::heap::allocate;
use spinlock::{Spinlock, SpinlockGuard};

pub fn spawn<F, R>(f:F) -> Future<R> where F: FnOnce()->R, F:Send {
    global().scheduler.spawn(f)
}

pub unsafe fn reschedule(current_rsp: uint) -> ! {
    // we must not be interrupted while using the scheduler stack
    ::disable_interrupts();
    // switch stack so we can park current thread
    call_on_stack(inner, current_rsp, scheduler_stack_top());

    fn inner(current_rsp: uint) -> ! {
        // try to park current thread
        let current = Thread::from_rsp(current_rsp);
        let scheduler = &global().scheduler;

        let thread = match scheduler.try_park(current) {
            Ok(()) => scheduler.schedule(),
            Err(thread) => {
                println!("thread list is locked. Maybe a thread was interrupted while holding
                    the lock in spawn()?");
                thread
            },
        };
        start_thread(thread)
    }
}

pub unsafe fn schedule() -> ! {
    // we must not be interrupted while using the scheduler stack
    ::disable_interrupts();
    // switch to scheduler stack (the stack of current thread could be to full/small)
    call_on_stack(inner, scheduler_stack_top());

    unsafe fn call_on_stack(function: fn() -> !, stack_top: uint) -> ! {
        asm!("call $0;" :: "r"(function), "{rsp}"(stack_top) :: "intel", "volatile");
        panic!("diverging fn returned");
    }

    fn inner() -> ! {
        // TODO FIXME kill current thread and deallocate stack
        start_thread(global().scheduler.schedule())
    }
}

fn start_thread(thread: Thread) -> ! {
    #[allow(improper_ctypes)]
    extern {
        fn pop_registers_and_iret(rsp: uint) -> !;
    }

    fn new_stack() -> uint {
        const NEW_STACK_SIZE: uint = 4096*2;
        let stack_bottom = unsafe{allocate(NEW_STACK_SIZE, 4096)};
        let stack_top = stack_bottom as uint + NEW_STACK_SIZE;
        stack_top
    }

    fn invoke(function: Box<FnBox() + Send>) -> ! {
        unsafe{::enable_interrupts()};
        function.call_once(());
        unsafe{asm!("int $$66" :::: "volatile")};
        unreachable!();
    }

    match thread {
        Thread{state: ThreadState::Active{rsp}} => {
            unsafe{pop_registers_and_iret(rsp)}
        },
        Thread{state: ThreadState::New{function}} => {
            println!("new");
            let new_stack_top = new_stack();
            unsafe{call_on_stack(invoke, function, new_stack_top)}
        },
    }
}

fn scheduler_stack_top() -> uint {
    const SCHEDULER_STACK_SIZE: uint = 4096;
    static SCHEDULER_STACK: [u8; SCHEDULER_STACK_SIZE] = [0; SCHEDULER_STACK_SIZE];

    &SCHEDULER_STACK as *const [u8; 4096] as uint + SCHEDULER_STACK_SIZE
}

unsafe fn call_on_stack<Arg>(function: fn(Arg) -> !, arg: Arg, stack_top: uint) -> ! {
    asm!("call $0;" :: "r"(function), "{rdi}"(arg), "{rsp}"(stack_top) :
        : "intel", "volatile");
    panic!("diverging fn returned");
}

pub struct Future<T>;

pub struct Thread {
    state: ThreadState,
}

impl Thread {
    fn new<F>(f: F) -> Thread where F : FnOnce(), F: Send {
        Thread {
            state: ThreadState::New {
                function: box f,
            }
        }
    }

    pub fn from_rsp(rsp: uint) -> Thread {
        Thread {
            state: ThreadState::Active {
                rsp: rsp,
            }
        }
    }
}

impl Default for Thread {
    fn default() -> Thread {
        Thread::new(|| print!("."))
    }
}

enum ThreadState {
    New {
        function: Box<FnBox() + Send>,
    },
    Active {
        rsp: uint,
    }
}

pub struct GlobalScheduler {
    threads: Spinlock<RingBuf<Thread>>,
}

impl GlobalScheduler {
    pub fn new() -> GlobalScheduler {
        GlobalScheduler{
            threads: Spinlock::new(RingBuf::new()),
        }
    }

    fn spawn<F, R>(&self, f:F) -> Future<R> where F: FnOnce()->R, F: Send {

        //let (tx, rx) = channel();

        self.threads.lock().push_back(Thread::new(move |:| {
            /*tx.send_opt(*/ f();
        }));

        Future/*::from_receiver(rx)*/
    }

    fn try_park(&self, thread: Thread) -> Result<(), Thread> {
        match self.threads.try_lock() {
            Some(mut threads) => Ok(threads.push_back(thread)),
            None => Err(thread),
        }
    }

    fn schedule(&self) -> Thread {
        self.threads.lock().pop_front().unwrap_or_default()
    }
}<|endoftext|>


<commit_before>use std::io;

use byteorder::{ByteOrder, BigEndian, WriteBytesExt};

use error::NbtError;

pub trait NbtFmt {
    fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
       where W: io::Write;

    #[inline]
    fn write_nbt_fmt_with_name<W, S>(&self, dst: &mut W, name: S) -> Result<(), NbtError>
       where W: io::Write,
             S: AsRef<str> {

        try!(dst.write_u8(Self::tag()));
        try!(write_bare_string(dst, name.as_ref()));
        self.write_nbt_fmt(dst)
    }

    #[inline] fn tag() -> u8 { 0x0a }
    #[inline] fn is_bare() -> bool { false }
}

macro_rules! nbtfmt_value {
  ($T:ty, $method:ident, $tag:expr, $bare:expr) => (
    impl NbtFmt for $T {
      fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
           where W: io::Write {
            $method(dst, *self)
      }
        #[inline] fn tag() -> u8 { $tag }
        #[inline] fn is_bare() -> bool { $bare }
    }
  )
}

macro_rules! nbtfmt_ptr {
  ($T:ty, $method:ident, $tag:expr, $bare:expr) => (
    impl NbtFmt for $T {
      fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
           where W: io::Write {
            $method(dst, self)
      }
        #[inline] fn tag() -> u8 { $tag }
        #[inline] fn is_bare() -> bool { $bare }
    }
  )
}

macro_rules! nbtfmt_slice {
  ($T:ty, $method:ident, $tag:expr, $bare:expr) => (
    impl NbtFmt for $T {
      fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
           where W: io::Write {
            $method(dst, &self[..])
      }
        #[inline] fn tag() -> u8 { $tag }
        #[inline] fn is_bare() -> bool { $bare }
    }
  )
}

nbtfmt_value!(i8, write_bare_byte, 0x01, true);
nbtfmt_value!(i16, write_bare_short, 0x02, true);
nbtfmt_value!(i32, write_bare_int, 0x03, true);
nbtfmt_value!(i64, write_bare_long, 0x04, true);
nbtfmt_value!(f32, write_bare_float, 0x05, true);
nbtfmt_value!(f64, write_bare_double, 0x06, true);
nbtfmt_ptr!([i8], write_bare_byte_array, 0x07, true);
nbtfmt_slice!(Vec<i8>, write_bare_byte_array, 0x07, true);
nbtfmt_ptr!(str, write_bare_string, 0x08, true);
nbtfmt_slice!(String, write_bare_string, 0x08, true);
nbtfmt_ptr!([i32], write_bare_int_array, 0x0b, true);
nbtfmt_slice!(Vec<i32>, write_bare_int_array, 0x0b, true);

// impl<T> NbtFmt for [T] where T: NbtFmt {
//  fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
//        where W: io::Write {

//          write_bare_list(dst, self.iter())
//  }
//     #[inline] fn tag() -> u8 { 0x09 }
//     #[inline] fn is_bare() -> bool { true }
// }

// impl<T> NbtFmt for Vec<T> where T: NbtFmt {
//  fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
//        where W: io::Write {

//          write_bare_list(dst, self.iter())
//  }
//     #[inline] fn tag() -> u8 { 0x09 }
//     #[inline] fn is_bare() -> bool { true }
// }

#[inline]
fn write_bare_byte<W>(dst: &mut W, value: i8) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_i8(value).map_err(From::from)
}

#[inline]
fn write_bare_short<W>(dst: &mut W, value: i16) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_i16::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_int<W>(dst: &mut W, value: i32) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_i32::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_long<W>(dst: &mut W, value: i64) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_i64::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_float<W>(dst: &mut W, value: f32) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_f32::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_double<W>(dst: &mut W, value: f64) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_f64::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_byte_array<W>(dst: &mut W, value: &[i8]) -> Result<(), NbtError>
   where W: io::Write {

    try!(dst.write_i32::<BigEndian>(value.len() as i32));
    for &v in value {
        try!(dst.write_i8(v));
    }
    Ok(())
}

#[inline]
fn write_bare_int_array<W>(dst: &mut W, value: &[i32]) -> Result<(), NbtError>
   where W: io::Write {

    try!(dst.write_i32::<BigEndian>(value.len() as i32));
    for &v in value {
        try!(dst.write_i32::<BigEndian>(v));
    }
    Ok(())
}

#[inline]
fn write_bare_string<W>(dst: &mut W, value: &str) -> Result<(), NbtError>
   where W: io::Write {

    try!(dst.write_u16::<BigEndian>(value.len() as u16));
    dst.write_all(value.as_bytes()).map_err(From::from)
}

#[inline]
fn write_bare_list<'a, W, I, T>(dst: &mut W, values: I) -> Result<(), NbtError>
   where W: io::Write,
         I: Iterator<Item=&'a T> + ExactSizeIterator,
         T: 'a + NbtFmt {

    // The list contents are prefixed by a byte tag for the type and the
    // length of the list (a big-endian i32).
    try!(dst.write_u8(T::tag()));
    try!(dst.write_i32::<BigEndian>(values.len() as i32));

    for ref value in values {
       try!(value.write_nbt_fmt(dst));
    }

    Ok(())
}

#[inline]
fn write_bare_compound<'a, W, I, T, S>(dst: &mut W, values: I) -> Result<(), NbtError>
   where W: io::Write,
         I: Iterator<Item=(&'a S, &'a T)>,
         S: 'a + AsRef<str>,
         T: 'a + NbtFmt {

    for (key, ref value) in values {
        try!(value.write_nbt_fmt_with_name(dst, key.as_ref()));
    }

    // Write the marker for the end of the Compound.
    dst.write_u8(0x00).map_err(From::from)
}

#[test]
fn nbt_test_struct_serialize() {
  struct TestStruct {
    name: String,
    health: i8,
    food: f32,
    emeralds: i16,
    timestamp: i32
  }

  impl NbtFmt for TestStruct {
    fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
           where W: io::Write {

            self.name.write_nbt_fmt_with_name(dst, "name");
            self.health.write_nbt_fmt_with_name(dst, "health");
            self.food.write_nbt_fmt_with_name(dst, "food");
            self.emeralds.write_nbt_fmt_with_name(dst, "emeralds");
            self.timestamp.write_nbt_fmt_with_name(dst, "timestamp");

            dst.write_u8(0x00).map_err(From::from)
        }
  }

  let test = TestStruct {
    name: "Herobrine".to_string(),
    health: 100, food: 20.0, emeralds: 12345, timestamp: 1424778774
  };

  let mut test_encoded = Vec::new();
  test.write_nbt_fmt_with_name(&mut test_encoded, "");

  let bytes = [
        0x0a,
            0x00, 0x00,
            0x08,
                0x00, 0x04,
                0x6e, 0x61, 0x6d, 0x65,
                0x00, 0x09,
                0x48, 0x65, 0x72, 0x6f, 0x62, 0x72, 0x69, 0x6e, 0x65,
            0x01,
                0x00, 0x06,
                0x68, 0x65, 0x61, 0x6c, 0x74, 0x68,
                0x64,
            0x05,
                0x00, 0x04,
                0x66, 0x6f, 0x6f, 0x64,
                0x41, 0xa0, 0x00, 0x00,
            0x02,
                0x00, 0x08,
                0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x64, 0x73,
                0x30, 0x39,
            0x03,
                0x00, 0x09,
                0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
                0x54, 0xec, 0x66, 0x16,
        0x00
    ];

    assert_eq!(&bytes[..], &test_encoded[..]);
}
<commit_msg>Adds some utility methods to the serialization submodule.<commit_after>use std::io;

use byteorder::{ByteOrder, BigEndian, WriteBytesExt};

use error::NbtError;

pub trait NbtFmt {
    fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
       where W: io::Write;

    #[inline]
    fn write_nbt_fmt_with_name<W, S>(&self, dst: &mut W, name: S) -> Result<(), NbtError>
       where W: io::Write,
             S: AsRef<str> {

        try!(dst.write_u8(Self::tag()));
        try!(write_bare_string(dst, name.as_ref()));
        self.write_nbt_fmt(dst)
    }

    #[inline] fn tag() -> u8 { 0x0a }
    #[inline] fn is_bare() -> bool { false }
}

pub fn close_nbt<W>(dst: &mut W) -> Result<(), NbtError>
    where W: io::Write {

    dst.write_u8(0x00).map_err(From::from)
}

pub fn to_writer<W, T>(dst: &mut W, obj: T) -> Result<(), NbtError>
    where W: io::Write,
          T: NbtFmt
{
    obj.write_nbt_fmt_with_name(dst, "")
}

macro_rules! nbtfmt_value {
  ($T:ty, $method:ident, $tag:expr, $bare:expr) => (
    impl NbtFmt for $T {
      fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
           where W: io::Write {
            $method(dst, *self)
      }
        #[inline] fn tag() -> u8 { $tag }
        #[inline] fn is_bare() -> bool { $bare }
    }
  )
}

macro_rules! nbtfmt_ptr {
  ($T:ty, $method:ident, $tag:expr, $bare:expr) => (
    impl NbtFmt for $T {
      fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
           where W: io::Write {
            $method(dst, self)
      }
        #[inline] fn tag() -> u8 { $tag }
        #[inline] fn is_bare() -> bool { $bare }
    }
  )
}

macro_rules! nbtfmt_slice {
  ($T:ty, $method:ident, $tag:expr, $bare:expr) => (
    impl NbtFmt for $T {
      fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
           where W: io::Write {
            $method(dst, &self[..])
      }
        #[inline] fn tag() -> u8 { $tag }
        #[inline] fn is_bare() -> bool { $bare }
    }
  )
}

nbtfmt_value!(i8, write_bare_byte, 0x01, true);
nbtfmt_value!(i16, write_bare_short, 0x02, true);
nbtfmt_value!(i32, write_bare_int, 0x03, true);
nbtfmt_value!(i64, write_bare_long, 0x04, true);
nbtfmt_value!(f32, write_bare_float, 0x05, true);
nbtfmt_value!(f64, write_bare_double, 0x06, true);
nbtfmt_ptr!([i8], write_bare_byte_array, 0x07, true);
nbtfmt_slice!(Vec<i8>, write_bare_byte_array, 0x07, true);
nbtfmt_ptr!(str, write_bare_string, 0x08, true);
nbtfmt_slice!(String, write_bare_string, 0x08, true);
nbtfmt_ptr!([i32], write_bare_int_array, 0x0b, true);
nbtfmt_slice!(Vec<i32>, write_bare_int_array, 0x0b, true);

// impl<T> NbtFmt for [T] where T: NbtFmt {
//  fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
//        where W: io::Write {

//          write_bare_list(dst, self.iter())
//  }
//     #[inline] fn tag() -> u8 { 0x09 }
//     #[inline] fn is_bare() -> bool { true }
// }

// impl<T> NbtFmt for Vec<T> where T: NbtFmt {
//  fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
//        where W: io::Write {

//          write_bare_list(dst, self.iter())
//  }
//     #[inline] fn tag() -> u8 { 0x09 }
//     #[inline] fn is_bare() -> bool { true }
// }

#[inline]
fn write_bare_byte<W>(dst: &mut W, value: i8) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_i8(value).map_err(From::from)
}

#[inline]
fn write_bare_short<W>(dst: &mut W, value: i16) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_i16::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_int<W>(dst: &mut W, value: i32) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_i32::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_long<W>(dst: &mut W, value: i64) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_i64::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_float<W>(dst: &mut W, value: f32) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_f32::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_double<W>(dst: &mut W, value: f64) -> Result<(), NbtError>
   where W: io::Write {

    dst.write_f64::<BigEndian>(value).map_err(From::from)
}

#[inline]
fn write_bare_byte_array<W>(dst: &mut W, value: &[i8]) -> Result<(), NbtError>
   where W: io::Write {

    try!(dst.write_i32::<BigEndian>(value.len() as i32));
    for &v in value {
        try!(dst.write_i8(v));
    }
    Ok(())
}

#[inline]
fn write_bare_int_array<W>(dst: &mut W, value: &[i32]) -> Result<(), NbtError>
   where W: io::Write {

    try!(dst.write_i32::<BigEndian>(value.len() as i32));
    for &v in value {
        try!(dst.write_i32::<BigEndian>(v));
    }
    Ok(())
}

#[inline]
fn write_bare_string<W>(dst: &mut W, value: &str) -> Result<(), NbtError>
   where W: io::Write {

    try!(dst.write_u16::<BigEndian>(value.len() as u16));
    dst.write_all(value.as_bytes()).map_err(From::from)
}

#[inline]
fn write_bare_list<'a, W, I, T>(dst: &mut W, values: I) -> Result<(), NbtError>
   where W: io::Write,
         I: Iterator<Item=&'a T> + ExactSizeIterator,
         T: 'a + NbtFmt {

    // The list contents are prefixed by a byte tag for the type and the
    // length of the list (a big-endian i32).
    try!(dst.write_u8(T::tag()));
    try!(dst.write_i32::<BigEndian>(values.len() as i32));

    for ref value in values {
       try!(value.write_nbt_fmt(dst));
    }

    Ok(())
}

#[inline]
fn write_bare_compound<'a, W, I, T, S>(dst: &mut W, values: I) -> Result<(), NbtError>
   where W: io::Write,
         I: Iterator<Item=(&'a S, &'a T)>,
         S: 'a + AsRef<str>,
         T: 'a + NbtFmt {

    for (key, ref value) in values {
        try!(value.write_nbt_fmt_with_name(dst, key.as_ref()));
    }

    // Write the marker for the end of the Compound.
    dst.write_u8(0x00).map_err(From::from)
}

#[test]
fn nbt_test_struct_serialize() {
  struct TestStruct {
    name: String,
    health: i8,
    food: f32,
    emeralds: i16,
    timestamp: i32
  }

  impl NbtFmt for TestStruct {
    fn write_nbt_fmt<W>(&self, dst: &mut W) -> Result<(), NbtError>
           where W: io::Write {

            self.name.write_nbt_fmt_with_name(dst, "name");
            self.health.write_nbt_fmt_with_name(dst, "health");
            self.food.write_nbt_fmt_with_name(dst, "food");
            self.emeralds.write_nbt_fmt_with_name(dst, "emeralds");
            self.timestamp.write_nbt_fmt_with_name(dst, "timestamp");

            dst.write_u8(0x00).map_err(From::from)
        }
  }

  let test = TestStruct {
    name: "Herobrine".to_string(),
    health: 100, food: 20.0, emeralds: 12345, timestamp: 1424778774
  };

  let mut test_encoded = Vec::new();
  test.write_nbt_fmt_with_name(&mut test_encoded, "");

  let bytes = [
        0x0a,
            0x00, 0x00,
            0x08,
                0x00, 0x04,
                0x6e, 0x61, 0x6d, 0x65,
                0x00, 0x09,
                0x48, 0x65, 0x72, 0x6f, 0x62, 0x72, 0x69, 0x6e, 0x65,
            0x01,
                0x00, 0x06,
                0x68, 0x65, 0x61, 0x6c, 0x74, 0x68,
                0x64,
            0x05,
                0x00, 0x04,
                0x66, 0x6f, 0x6f, 0x64,
                0x41, 0xa0, 0x00, 0x00,
            0x02,
                0x00, 0x08,
                0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x64, 0x73,
                0x30, 0x39,
            0x03,
                0x00, 0x09,
                0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
                0x54, 0xec, 0x66, 0x16,
        0x00
    ];

    assert_eq!(&bytes[..], &test_encoded[..]);
}
<|endoftext|>


<commit_before>use std::io::Read;

use reqwest::header::{self, HeaderMap, HeaderValue};
use reqwest::Client;
use url::form_urlencoded::Serializer;

use errors::SendgridResult;
use mail::Mail;

static API_URL: &'static str = "https://api.sendgrid.com/api/mail.send.json?";

/// This is the struct that allows you to authenticate to the SendGrid API.
/// It's only field is the API key which allows you to send messages.
pub struct SGClient {
    api_key: String,
}

// Given a form value and a key, generate the correct key.
fn make_form_key(form: &str, key: &str) -> String {
    let mut value = String::new();
    value.push_str(form);
    value.push('[');
    value.push_str(key);
    value.push(']');

    value
}

// Use the URL form encoder to properly generate the body used in the mail send request.
fn make_post_body(mut mail_info: Mail) -> SendgridResult<String> {
    let body = String::new();
    let mut encoder = Serializer::new(body);

    for to in mail_info.to.iter() {
        encoder.append_pair("to[]", to.address);
        encoder.append_pair("toname[]", to.name);
    }

    for cc in mail_info.cc.iter() {
        encoder.append_pair("cc[]", &cc);
    }

    for bcc in mail_info.bcc.iter() {
        encoder.append_pair("bcc[]", &bcc);
    }

    for (attachment, contents) in &mail_info.attachments {
        encoder.append_pair(&make_form_key("files", attachment), &contents);
    }

    for (id, value) in &mail_info.content {
        encoder.append_pair(&make_form_key("content", id), &value);
    }

    encoder.append_pair("from", &mail_info.from);
    encoder.append_pair("subject", &mail_info.subject);
    encoder.append_pair("html", &mail_info.html);
    encoder.append_pair("text", &mail_info.text);
    encoder.append_pair("fromname", &mail_info.from_name);
    encoder.append_pair("replyto", &mail_info.reply_to);
    encoder.append_pair("date", &mail_info.date);
    encoder.append_pair("headers", &mail_info.make_header_string()?);
    encoder.append_pair("x-smtpapi", &mail_info.x_smtpapi);

    Ok(encoder.finish())
}

impl SGClient {
    /// Makes a new SendGrid cient with the specified API key.
    pub fn new(key: String) -> SGClient {
        SGClient { api_key: key }
    }

    /// Sends a messages through the SendGrid API. It takes a Mail struct as an
    /// argument. It returns the string response from the API as JSON.
    /// It sets the Content-Type to be application/x-www-form-urlencoded.
    pub fn send(&self, mail_info: Mail) -> SendgridResult<String> {
        let client = Client::new();
        let mut headers = HeaderMap::new();
        headers.insert(
            header::AUTHORIZATION,
            HeaderValue::from_str(&format!("Bearer {}", self.api_key.clone()))?,
        );
        headers.insert(
            header::CONTENT_TYPE,
            HeaderValue::from_static("application/x-www-form-urlencoded"),
        );
        headers.insert(header::USER_AGENT, HeaderValue::from_static("sendgrid-rs"));

        let post_body = make_post_body(mail_info)?;
        let mut res = client
            .post(API_URL)
            .headers(headers)
            .body(post_body)
            .send()?;
        let mut body = String::new();
        res.read_to_string(&mut body)?;
        Ok(body)
    }
}

#[test]
fn basic_message_body() {
    use mail::Destination;

    let m = Mail::new()
        .add_to(Destination {
            address: "test@example.com",
            name: "Testy mcTestFace",
        })
        .add_from("me@example.com")
        .add_subject("Test")
        .add_text("It works");

    let body = make_post_body(m);
    let want = "to%5B%5D=test%40example.com&toname%5B%5D=Testy+mcTestFace&from=me%40example.com&subject=Test&\
                html=&text=It+works&fromname=&replyto=&date=&headers=%7B%7D&x-smtpapi=";
    assert_eq!(body.unwrap(), want);
}

#[test]
fn test_proper_key() {
    let want = "files[test.jpg]";
    let got = make_form_key("files", "test.jpg");
    assert_eq!(want, got);
}
<commit_msg>SGClient: Add Clone + Debug traits (#45)<commit_after>use std::io::Read;

use reqwest::header::{self, HeaderMap, HeaderValue};
use reqwest::Client;
use url::form_urlencoded::Serializer;

use errors::SendgridResult;
use mail::Mail;

static API_URL: &'static str = "https://api.sendgrid.com/api/mail.send.json?";

/// This is the struct that allows you to authenticate to the SendGrid API.
/// It's only field is the API key which allows you to send messages.
#[derive(Clone, Debug)]
pub struct SGClient {
    api_key: String,
}

// Given a form value and a key, generate the correct key.
fn make_form_key(form: &str, key: &str) -> String {
    let mut value = String::new();
    value.push_str(form);
    value.push('[');
    value.push_str(key);
    value.push(']');

    value
}

// Use the URL form encoder to properly generate the body used in the mail send request.
fn make_post_body(mut mail_info: Mail) -> SendgridResult<String> {
    let body = String::new();
    let mut encoder = Serializer::new(body);

    for to in mail_info.to.iter() {
        encoder.append_pair("to[]", to.address);
        encoder.append_pair("toname[]", to.name);
    }

    for cc in mail_info.cc.iter() {
        encoder.append_pair("cc[]", &cc);
    }

    for bcc in mail_info.bcc.iter() {
        encoder.append_pair("bcc[]", &bcc);
    }

    for (attachment, contents) in &mail_info.attachments {
        encoder.append_pair(&make_form_key("files", attachment), &contents);
    }

    for (id, value) in &mail_info.content {
        encoder.append_pair(&make_form_key("content", id), &value);
    }

    encoder.append_pair("from", &mail_info.from);
    encoder.append_pair("subject", &mail_info.subject);
    encoder.append_pair("html", &mail_info.html);
    encoder.append_pair("text", &mail_info.text);
    encoder.append_pair("fromname", &mail_info.from_name);
    encoder.append_pair("replyto", &mail_info.reply_to);
    encoder.append_pair("date", &mail_info.date);
    encoder.append_pair("headers", &mail_info.make_header_string()?);
    encoder.append_pair("x-smtpapi", &mail_info.x_smtpapi);

    Ok(encoder.finish())
}

impl SGClient {
    /// Makes a new SendGrid cient with the specified API key.
    pub fn new(key: String) -> SGClient {
        SGClient { api_key: key }
    }

    /// Sends a messages through the SendGrid API. It takes a Mail struct as an
    /// argument. It returns the string response from the API as JSON.
    /// It sets the Content-Type to be application/x-www-form-urlencoded.
    pub fn send(&self, mail_info: Mail) -> SendgridResult<String> {
        let client = Client::new();
        let mut headers = HeaderMap::new();
        headers.insert(
            header::AUTHORIZATION,
            HeaderValue::from_str(&format!("Bearer {}", self.api_key.clone()))?,
        );
        headers.insert(
            header::CONTENT_TYPE,
            HeaderValue::from_static("application/x-www-form-urlencoded"),
        );
        headers.insert(header::USER_AGENT, HeaderValue::from_static("sendgrid-rs"));

        let post_body = make_post_body(mail_info)?;
        let mut res = client
            .post(API_URL)
            .headers(headers)
            .body(post_body)
            .send()?;
        let mut body = String::new();
        res.read_to_string(&mut body)?;
        Ok(body)
    }
}

#[test]
fn basic_message_body() {
    use mail::Destination;

    let m = Mail::new()
        .add_to(Destination {
            address: "test@example.com",
            name: "Testy mcTestFace",
        })
        .add_from("me@example.com")
        .add_subject("Test")
        .add_text("It works");

    let body = make_post_body(m);
    let want = "to%5B%5D=test%40example.com&toname%5B%5D=Testy+mcTestFace&from=me%40example.com&subject=Test&\
                html=&text=It+works&fromname=&replyto=&date=&headers=%7B%7D&x-smtpapi=";
    assert_eq!(body.unwrap(), want);
}

#[test]
fn test_proper_key() {
    let want = "files[test.jpg]";
    let got = make_form_key("files", "test.jpg");
    assert_eq!(want, got);
}
<|endoftext|>


<commit_before>
// This pass generates x86-64 assembly from IR.

#![allow(non_upper_case_globals)]

use crate::util::*;
use crate::*;
use std::cell::RefCell;
use std::collections::HashMap;

macro_rules! p {
    ($fmt:expr) => {
        println!($fmt);
    };
    ($fmt:expr,$($x:tt)*) => {
        println!($fmt, $( $x )*);
    };
}

macro_rules! emit {
    ($fmt:expr) => {
        print!("\t");
        println!($fmt);
    };
    ($fmt:expr,$($x:tt)*) => {
        print!("\t");
        println!($fmt, $( $x )*);
    };
}

thread_local! {
    static ESCAPED: RefCell<HashMap<char,char>> = RefCell::new(HashMap::new());
}

pub const regs: [&'static str; 7] = ["r10", "r11", "rbx", "r12", "r13", "r14", "r15"];
pub const regs8: [&'static str; 7] = ["r10b", "r11b", "bl", "r12b", "r13b", "r14b", "r15b"];
pub const regs32: [&'static str; 7] = ["r10d", "r11d", "ebx", "r12d", "r13d", "r14d", "r15d"];

pub fn num_regs() -> usize {
    return regs.len();
}

const argregs: [&'static str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
const argregs8: [&'static str; 6] = ["dil", "sil", "dl", "cl", "r8b", "r9b"];
const argregs32: [&'static str; 6] = ["edi", "esi", "edx", "ecx", "r8d", "r9d"];

fn init_escaped() {
    ESCAPED.with(|e| {
        let mut escaped = e.borrow_mut();

        if escaped.len() > 0 {
            return;
        }

        escaped.insert(char::from(8), 'b');  // \b
        escaped.insert(char::from(12), 'f'); // \f
        escaped.insert(char::from(10), 'n'); // \n
        escaped.insert(char::from(13), 'r'); // \r
        escaped.insert(char::from(9), 't');  // \t
        escaped.insert('\\', '\\');
        escaped.insert('\'', '\'');
        escaped.insert('\"', '"');
    })
}

fn escaped(c: char) -> Option<char> {
    ESCAPED.with(|e| {
        let escaped = e.borrow();
        match escaped.get(&c) {
            Some(esc) => Some(*esc),
            None => None,
        }
    })
}

fn backslash_escape(s: & String) -> String {
    init_escaped();

    let mut buf = String::new();
    let mut chars = s.chars();
    while let Some(c) = chars.next() {
        if let Some(esc) = escaped(c) {
            buf.push('\\');
            buf.push(esc);
        } else if c.is_ascii_graphic() || c == ' ' {
            buf.push(c);
        } else {
            buf.push_str(&format!("\\{:03o}", u32::from(c)));
        }
    }

    //buf.push(char::from(0));
    return buf;
}

fn emit_cmp(insn: &str, ir: &IR) {
    let lhs = ir.lhs as usize;
    let rhs = ir.rhs as usize;

    emit!("cmp {}, {}", regs[lhs], regs[rhs]);
    emit!("{} {}", insn, regs8[lhs]);
    emit!("movzb {}, {}", regs[lhs], regs8[lhs]);
}

fn reg(r: usize, size: i32) -> &'static str {
    match size {
        1 => regs8[r],
        4 => regs32[r],
        8 => regs[r],
        _ => panic!(),
    }
}

fn argreg(r: usize, size: i32) -> &'static str {
    match size {
        1 => argregs8[r],
        4 => argregs32[r],
        8 => argregs[r],
        _ => panic!(),
    }
}

fn emit_ir(ir: & IR, ret: & String) {
    let lhs = ir.lhs;
    let rhs = ir.rhs;

    match ir.op {
        IRType::IMM => {
            emit!("mov {}, {}", regs[lhs as usize], rhs);
        }
        IRType::BPREL => {
            emit!("lea {}, [rbp{}]", regs[lhs as usize], rhs);
        }
        IRType::MOV => {
            emit!("mov {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::RETURN => {
            emit!("mov rax, {}", regs[lhs as usize]);
            emit!("jmp {}", ret);
        }
        IRType::CALL => {
            for i in 0..ir.nargs {
                emit!("mov {}, {}", argregs[i], regs[ir.args[i] as usize]);
            }

            emit!("push r10");
            emit!("push r11");
            emit!("mov rax, 0");
            emit!("call {}", ir.name);
            emit!("pop r11");
            emit!("pop r10");

            emit!("mov {}, rax", regs[lhs as usize]);
        }
        IRType::LABEL_ADDR => {
            emit!("lea {}, {}", regs[lhs as usize], ir.name);
        }
        IRType::EQ => {
            emit_cmp("sete", ir)
        }
        IRType::NE => {
            emit_cmp("setne", ir)
        }
        IRType::LT => {
            emit_cmp("setl", ir)
        }
        IRType::LE => {
            emit_cmp("setle", ir)
        }
        IRType::AND => {
            emit!("and {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::OR => {
            emit!("or {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::XOR => {
            emit!("xor {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::SHL => {
            emit!("mov cl, {}", regs8[rhs as usize]);
            emit!("shl {}, cl", regs[lhs as usize]);
        }
        IRType::SHR => {
            emit!("mov cl, {}", regs8[rhs as usize]);
            emit!("shr {}, cl", regs[lhs as usize]);
        }
        IRType::JMP => {
            emit!("jmp .L{}", ir.bb1.borrow().label);
        }
        IRType::BR => {
            emit!("cmp {}, 0", regs[lhs as usize]);
            emit!("jne .L{}", ir.bb1.borrow().label);
            emit!("jmp .L{}", ir.bb2.borrow().label);
        }
        IRType::LOAD => {
            emit!("mov {}, [{}]", reg(lhs as usize, ir.size), regs[rhs as usize]);
            if ir.size == 1 {
                emit!("movzb {}, {}", regs[lhs as usize], regs8[lhs as usize]);
            }
        }
        IRType::STORE => {
            emit!("mov [{}], {}", regs[lhs as usize], reg(rhs as usize, ir.size));
        }
        IRType::STORE_ARG => {
            emit!("mov [rbp{}], {}", lhs, argreg(rhs as usize, ir.size));
        }
        IRType::ADD => {
            emit!("add {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::SUB => {
            emit!("sub {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::MUL => loop {
            emit!("mov rax, {}", regs[rhs as usize]);
            emit!("imul {}", regs[lhs as usize]);
            emit!("mov {}, rax", regs[lhs as usize]);
            break;
        }
        IRType::DIV => {
            emit!("mov rax, {}", regs[lhs as usize]);
            emit!("cqo");
            emit!("idiv {}", regs[rhs as usize]);
            emit!("mov {}, rax", regs[lhs as usize]);
        }
        IRType::MOD => {
            emit!("mov rax, {}", regs[lhs as usize]);
            emit!("cqo");
            emit!("idiv {}", regs[rhs as usize]);
            emit!("mov {}, rdx", regs[lhs as usize]);
        }
        IRType::NOP => {}
        ref i => {
            panic!("unknown operator {:?}", i);
        }
    }
}

fn emit_code(fun: &Function) {
    let ret = format!(".Lend{}", bump_nlabel());

    p!(".text");
    p!(".global {}", fun.name);
    p!("{}:", fun.name);
    emit!("push rbp");
    emit!("mov rbp, rsp");
    emit!("sub rsp, {}", roundup(fun.stacksize, 16));
    emit!("push r12");
    emit!("push r13");
    emit!("push r14");
    emit!("push r15");

    for bb in fun.bbs.iter() {
        p!(".L{}:", bb.borrow().label);
        for ir in bb.borrow().ir.iter() {
            emit_ir(&*ir.borrow(), &ret);
        }
    }
    p!("{}:", ret);
    emit!("pop r15");
    emit!("pop r14");
    emit!("pop r13");
    emit!("pop r12");
    emit!("mov rsp, rbp");
    emit!("pop rbp");
    emit!("ret");
}

fn emit_data(var: & Var) {
    if var.data.is_some() {
        p!(".data");
        p!("{}:", var.name);
        emit!(".ascii \"{}\"", backslash_escape(&var.data.clone().unwrap()));
        return;
    }

    p!(".bss");
    p!("{}:", var.name);
    emit!(".zero {}", var.ty.size);
}

pub fn gen_x86(prog: &mut Program) {
    p!(".intel_syntax noprefix");

    for v in prog.gvars.iter() {
        emit_data(&v.borrow());
   }

    for f in prog.funcs.iter() {
        emit_code(&*f.borrow());
    }
}
<commit_msg>Refactor.<commit_after>
// This pass generates x86-64 assembly from IR.

#![allow(non_upper_case_globals)]

use crate::util::*;
use crate::*;
use std::cell::RefCell;
use std::collections::HashMap;

macro_rules! p {
    ($fmt:expr) => {
        println!($fmt);
    };
    ($fmt:expr,$($x:tt)*) => {
        println!($fmt, $( $x )*);
    };
}

macro_rules! emit {
    ($fmt:expr) => {
        print!("\t");
        println!($fmt);
    };
    ($fmt:expr,$($x:tt)*) => {
        print!("\t");
        println!($fmt, $( $x )*);
    };
}

thread_local! {
    static ESCAPED: RefCell<HashMap<char,char>> = RefCell::new(HashMap::new());
}

pub const regs: [&'static str; 7] = ["r10", "r11", "rbx", "r12", "r13", "r14", "r15"];
pub const regs8: [&'static str; 7] = ["r10b", "r11b", "bl", "r12b", "r13b", "r14b", "r15b"];
pub const regs32: [&'static str; 7] = ["r10d", "r11d", "ebx", "r12d", "r13d", "r14d", "r15d"];

pub fn num_regs() -> usize {
    return regs.len();
}

const argregs: [&'static str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
const argregs8: [&'static str; 6] = ["dil", "sil", "dl", "cl", "r8b", "r9b"];
const argregs32: [&'static str; 6] = ["edi", "esi", "edx", "ecx", "r8d", "r9d"];

fn init_escaped() {
    ESCAPED.with(|e| {
        let mut escaped = e.borrow_mut();

        if escaped.len() > 0 {
            return;
        }

        escaped.insert(char::from(8), 'b');  // \b
        escaped.insert(char::from(12), 'f'); // \f
        escaped.insert(char::from(10), 'n'); // \n
        escaped.insert(char::from(13), 'r'); // \r
        escaped.insert(char::from(9), 't');  // \t
        escaped.insert('\\', '\\');
        escaped.insert('\'', '\'');
        escaped.insert('\"', '"');
    })
}

fn escaped(c: char) -> Option<char> {
    ESCAPED.with(|e| {
        let escaped = e.borrow();
        match escaped.get(&c) {
            Some(esc) => Some(*esc),
            None => None,
        }
    })
}

fn emit_cmp(insn: &str, ir: &IR) {
    let lhs = ir.lhs as usize;
    let rhs = ir.rhs as usize;

    emit!("cmp {}, {}", regs[lhs], regs[rhs]);
    emit!("{} {}", insn, regs8[lhs]);
    emit!("movzb {}, {}", regs[lhs], regs8[lhs]);
}

fn reg(r: usize, size: i32) -> &'static str {
    match size {
        1 => regs8[r],
        4 => regs32[r],
        8 => regs[r],
        _ => panic!(),
    }
}

fn argreg(r: usize, size: i32) -> &'static str {
    match size {
        1 => argregs8[r],
        4 => argregs32[r],
        8 => argregs[r],
        _ => panic!(),
    }
}

fn emit_ir(ir: & IR, ret: & String) {
    let lhs = ir.lhs;
    let rhs = ir.rhs;

    match ir.op {
        IRType::IMM => {
            emit!("mov {}, {}", regs[lhs as usize], rhs);
        }
        IRType::BPREL => {
            emit!("lea {}, [rbp{}]", regs[lhs as usize], rhs);
        }
        IRType::MOV => {
            emit!("mov {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::RETURN => {
            emit!("mov rax, {}", regs[lhs as usize]);
            emit!("jmp {}", ret);
        }
        IRType::CALL => {
            for i in 0..ir.nargs {
                emit!("mov {}, {}", argregs[i], regs[ir.args[i] as usize]);
            }

            emit!("push r10");
            emit!("push r11");
            emit!("mov rax, 0");
            emit!("call {}", ir.name);
            emit!("pop r11");
            emit!("pop r10");

            emit!("mov {}, rax", regs[lhs as usize]);
        }
        IRType::LABEL_ADDR => {
            emit!("lea {}, {}", regs[lhs as usize], ir.name);
        }
        IRType::EQ => {
            emit_cmp("sete", ir)
        }
        IRType::NE => {
            emit_cmp("setne", ir)
        }
        IRType::LT => {
            emit_cmp("setl", ir)
        }
        IRType::LE => {
            emit_cmp("setle", ir)
        }
        IRType::AND => {
            emit!("and {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::OR => {
            emit!("or {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::XOR => {
            emit!("xor {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::SHL => {
            emit!("mov cl, {}", regs8[rhs as usize]);
            emit!("shl {}, cl", regs[lhs as usize]);
        }
        IRType::SHR => {
            emit!("mov cl, {}", regs8[rhs as usize]);
            emit!("shr {}, cl", regs[lhs as usize]);
        }
        IRType::JMP => {
            emit!("jmp .L{}", ir.bb1.borrow().label);
        }
        IRType::BR => {
            emit!("cmp {}, 0", regs[lhs as usize]);
            emit!("jne .L{}", ir.bb1.borrow().label);
            emit!("jmp .L{}", ir.bb2.borrow().label);
        }
        IRType::LOAD => {
            emit!("mov {}, [{}]", reg(lhs as usize, ir.size), regs[rhs as usize]);
            if ir.size == 1 {
                emit!("movzb {}, {}", regs[lhs as usize], regs8[lhs as usize]);
            }
        }
        IRType::STORE => {
            emit!("mov [{}], {}", regs[lhs as usize], reg(rhs as usize, ir.size));
        }
        IRType::STORE_ARG => {
            emit!("mov [rbp{}], {}", lhs, argreg(rhs as usize, ir.size));
        }
        IRType::ADD => {
            emit!("add {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::SUB => {
            emit!("sub {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::MUL => loop {
            emit!("mov rax, {}", regs[rhs as usize]);
            emit!("imul {}", regs[lhs as usize]);
            emit!("mov {}, rax", regs[lhs as usize]);
            break;
        }
        IRType::DIV => {
            emit!("mov rax, {}", regs[lhs as usize]);
            emit!("cqo");
            emit!("idiv {}", regs[rhs as usize]);
            emit!("mov {}, rax", regs[lhs as usize]);
        }
        IRType::MOD => {
            emit!("mov rax, {}", regs[lhs as usize]);
            emit!("cqo");
            emit!("idiv {}", regs[rhs as usize]);
            emit!("mov {}, rdx", regs[lhs as usize]);
        }
        IRType::NOP => {}
        ref i => {
            panic!("unknown operator {:?}", i);
        }
    }
}

fn emit_code(fun: &Function) {
    let ret = format!(".Lend{}", bump_nlabel());

    p!(".text");
    p!(".global {}", fun.name);
    p!("{}:", fun.name);
    emit!("push rbp");
    emit!("mov rbp, rsp");
    emit!("sub rsp, {}", roundup(fun.stacksize, 16));
    emit!("push r12");
    emit!("push r13");
    emit!("push r14");
    emit!("push r15");

    for bb in fun.bbs.iter() {
        p!(".L{}:", bb.borrow().label);
        for ir in bb.borrow().ir.iter() {
            emit_ir(&*ir.borrow(), &ret);
        }
    }
    p!("{}:", ret);
    emit!("pop r15");
    emit!("pop r14");
    emit!("pop r13");
    emit!("pop r12");
    emit!("mov rsp, rbp");
    emit!("pop rbp");
    emit!("ret");
}

fn backslash_escape(s: & String) -> String {
    init_escaped();

    let mut buf = String::new();
    let mut chars = s.chars();
    while let Some(c) = chars.next() {
        if let Some(esc) = escaped(c) {
            buf.push('\\');
            buf.push(esc);
        } else if c.is_ascii_graphic() || c == ' ' {
            buf.push(c);
        } else {
            buf.push_str(&format!("\\{:03o}", u32::from(c)));
        }
    }

    //buf.push(char::from(0));
    return buf;
}

fn emit_data(var: & Var) {
    if var.data.is_some() {
        p!(".data");
        p!("{}:", var.name);
        emit!(".ascii \"{}\"", backslash_escape(&var.data.clone().unwrap()));
        return;
    }

    p!(".bss");
    p!("{}:", var.name);
    emit!(".zero {}", var.ty.size);
}

pub fn gen_x86(prog: &mut Program) {
    p!(".intel_syntax noprefix");

    for v in prog.gvars.iter() {
        emit_data(&v.borrow());
   }

    for f in prog.funcs.iter() {
        emit_code(&*f.borrow());
    }
}
<|endoftext|>


<commit_before>use clap::{App, Arg, ArgMatches};
use hyper::method::Method;
use serde_json;

use CliResult;
use commands::Config;
use utils::{make_subcommand, get_org_and_project};

#[derive(Debug, Serialize, Deserialize)]
struct ReleaseInfo {
    version: String,
    #[serde(rename="ref", skip_serializing_if="Option::is_none")]
    reference: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    url: Option<String>,
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("manage releases on Sentry")
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .subcommand(make_subcommand("new")
                .about("Create a new release")
                .arg(Arg::with_name("version")
                     .long("version")
                     .value_name("VERSION")
                     .required(true)
                     .help("The version identifier for this release"))
                .arg(Arg::with_name("ref")
                     .long("ref")
                     .value_name("REF")
                     .help("Optional commit reference (commit hash)"))
                .arg(Arg::with_name("url")
                     .long("url")
                     .value_name("URL")
                     .help("Optional URL to the release for information purposes")))
        .subcommand(make_subcommand("delete")
                .about("Delete a release")
                .arg(Arg::with_name("version")
                     .long("version")
                     .value_name("VERSION")
                     .required(true)
                     .help("The version to delete")))
}

pub fn execute_new<'a>(matches: &ArgMatches<'a>, config: &Config,
                       org: &str, project: &str) -> CliResult<()> {
    let info = ReleaseInfo {
        version: matches.value_of("version").unwrap().to_owned(),
        reference: matches.value_of("ref").map(|x| x.to_owned()),
        url: matches.value_of("url").map(|x| x.to_owned()),
    };
    let mut resp = try!(config.json_api_request(
        Method::Post, &format!("/projects/{}/{}/releases/", org, project),
        &info));
    if !resp.status.is_success() {
        fail!(resp);
    } else {
        let info_rv : ReleaseInfo = try!(serde_json::from_reader(&mut resp));
        println!("{}", info_rv.version);
    }
    Ok(())
}

pub fn execute_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                          org: &str, project: &str) -> CliResult<()> {
    let version = matches.value_of("version").unwrap();
    let resp = try!(config.api_request(
        Method::Delete, &format!("/projects/{}/{}/releases/{}/", org, project, version)));
    if !resp.status.is_success() {
        fail!(resp);
    } else {
        println!("Deleted!");
    }
    Ok(())
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> CliResult<()> {
    if let Some(sub_matches) = matches.subcommand_matches("new") {
        let (org, project) = try!(get_org_and_project(matches));
        return execute_new(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        let (org, project) = try!(get_org_and_project(matches));
        return execute_delete(sub_matches, config, &org, &project);
    }

    Ok(())
}
<commit_msg>Some small UI improvements<commit_after>use clap::{App, Arg, ArgMatches};
use hyper::method::Method;
use hyper::status::StatusCode;
use serde_json;

use CliResult;
use commands::Config;
use utils::{make_subcommand, get_org_and_project};

#[derive(Debug, Serialize, Deserialize)]
struct ReleaseInfo {
    version: String,
    #[serde(rename="ref", skip_serializing_if="Option::is_none")]
    reference: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    url: Option<String>,
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("manage releases on Sentry")
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .subcommand(make_subcommand("new")
                .about("Create a new release")
                .arg(Arg::with_name("version")
                     .value_name("VERSION")
                     .required(true)
                     .index(1)
                     .help("The version identifier for this release"))
                .arg(Arg::with_name("ref")
                     .long("ref")
                     .value_name("REF")
                     .help("Optional commit reference (commit hash)"))
                .arg(Arg::with_name("url")
                     .long("url")
                     .value_name("URL")
                     .help("Optional URL to the release for information purposes")))
        .subcommand(make_subcommand("delete")
                .about("Delete a release")
                .arg(Arg::with_name("version")
                     .value_name("VERSION")
                     .required(true)
                     .index(1)
                     .help("The version to delete")))
}

pub fn execute_new<'a>(matches: &ArgMatches<'a>, config: &Config,
                       org: &str, project: &str) -> CliResult<()> {
    let info = ReleaseInfo {
        version: matches.value_of("version").unwrap().to_owned(),
        reference: matches.value_of("ref").map(|x| x.to_owned()),
        url: matches.value_of("url").map(|x| x.to_owned()),
    };
    let mut resp = try!(config.json_api_request(
        Method::Post, &format!("/projects/{}/{}/releases/", org, project),
        &info));
    if !resp.status.is_success() {
        fail!(resp);
    } else {
        let info_rv : ReleaseInfo = try!(serde_json::from_reader(&mut resp));
        println!("Created release {}.", info_rv.version);
    }
    Ok(())
}

pub fn execute_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                          org: &str, project: &str) -> CliResult<()> {
    let version = matches.value_of("version").unwrap();
    let resp = try!(config.api_request(
        Method::Delete, &format!("/projects/{}/{}/releases/{}/", org, project, version)));
    if resp.status == StatusCode::NotFound {
        println!("Did nothing. Release with this version ({}) does not exist.", version);
    } else if !resp.status.is_success() {
        fail!(resp);
    } else {
        println!("Deleted release {}!", version);
    }
    Ok(())
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> CliResult<()> {
    if let Some(sub_matches) = matches.subcommand_matches("new") {
        let (org, project) = try!(get_org_and_project(matches));
        return execute_new(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        let (org, project) = try!(get_org_and_project(matches));
        return execute_delete(sub_matches, config, &org, &project);
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::mem;

use rustc::ty::{self, layout::{self, Size, Align}};
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc::mir;

use rand::RngCore;

use crate::*;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}

pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Gets an instance for a path.
    fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> {
        let this = self.eval_context_ref();
        this.tcx
            .crates()
            .iter()
            .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0])
            .and_then(|krate| {
                let krate = DefId {
                    krate: *krate,
                    index: CRATE_DEF_INDEX,
                };
                let mut items = this.tcx.item_children(krate);
                let mut path_it = path.iter().skip(1).peekable();

                while let Some(segment) = path_it.next() {
                    for item in mem::replace(&mut items, Default::default()).iter() {
                        if item.ident.name.as_str() == *segment {
                            if path_it.peek().is_none() {
                                return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id()));
                            }

                            items = this.tcx.item_children(item.res.def_id());
                            break;
                        }
                    }
                }
                None
            })
            .ok_or_else(|| {
                let path = path.iter().map(|&s| s.to_owned()).collect();
                err_unsup!(PathNotFound(path)).into()
            })
    }

    /// Write a 0 of the appropriate size to `dest`.
    fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
        self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
    }

    /// Test if this immediate equals 0.
    fn is_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_ref();
        let null = Scalar::from_int(0, this.memory().pointer_size());
        this.ptr_eq(val, null)
    }

    /// Turn a Scalar into an Option<NonNullScalar>
    fn test_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, Option<Scalar<Tag>>> {
        let this = self.eval_context_ref();
        Ok(if this.is_null(val)? {
            None
        } else {
            Some(val)
        })
    }

    /// Get the `Place` for a local
    fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> {
        let this = self.eval_context_mut();
        let place = mir::Place { base: mir::PlaceBase::Local(local), projection: None };
        this.eval_place(&place)
    }

    /// Generate some random bytes, and write them to `dest`.
    fn gen_random(
        &mut self,
        ptr: Scalar<Tag>,
        len: usize,
    ) -> InterpResult<'tcx>  {
        // Some programs pass in a null pointer and a length of 0
        // to their platform's random-generation function (e.g. getrandom())
        // on Linux. For compatibility with these programs, we don't perform
        // any additional checks - it's okay if the pointer is invalid,
        // since we wouldn't actually be writing to it.
        if len == 0 {
            return Ok(());
        }
        let this = self.eval_context_mut();

        let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? {
            Some(ptr) => ptr,
            None => return Ok(()), // zero-sized access
        };

        let rng = this.memory_mut().extra.rng.get_mut();
        let mut data = vec![0; len];
        rng.fill_bytes(&mut data);

        let tcx = &{this.tcx.tcx};
        this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data)
    }

    /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter
    /// will be true if this is frozen, false if this is in an `UnsafeCell`.
    fn visit_freeze_sensitive(
        &self,
        place: MPlaceTy<'tcx, Tag>,
        size: Size,
        mut action: impl FnMut(Pointer<Tag>, Size, bool) -> InterpResult<'tcx>,
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_ref();
        trace!("visit_frozen(place={:?}, size={:?})", *place, size);
        debug_assert_eq!(size,
            this.size_and_align_of_mplace(place)?
            .map(|(size, _)| size)
            .unwrap_or_else(|| place.layout.size)
        );
        // Store how far we proceeded into the place so far. Everything to the left of
        // this offset has already been handled, in the sense that the frozen parts
        // have had `action` called on them.
        let mut end_ptr = place.ptr.assert_ptr();
        // Called when we detected an `UnsafeCell` at the given offset and size.
        // Calls `action` and advances `end_ptr`.
        let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar<Tag>, unsafe_cell_size: Size| {
            let unsafe_cell_ptr = unsafe_cell_ptr.assert_ptr();
            debug_assert_eq!(unsafe_cell_ptr.alloc_id, end_ptr.alloc_id);
            debug_assert_eq!(unsafe_cell_ptr.tag, end_ptr.tag);
            // We assume that we are given the fields in increasing offset order,
            // and nothing else changes.
            let unsafe_cell_offset = unsafe_cell_ptr.offset;
            let end_offset = end_ptr.offset;
            assert!(unsafe_cell_offset >= end_offset);
            let frozen_size = unsafe_cell_offset - end_offset;
            // Everything between the end_ptr and this `UnsafeCell` is frozen.
            if frozen_size != Size::ZERO {
                action(end_ptr, frozen_size, /*frozen*/true)?;
            }
            // This `UnsafeCell` is NOT frozen.
            if unsafe_cell_size != Size::ZERO {
                action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/false)?;
            }
            // Update end end_ptr.
            end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this);
            // Done
            Ok(())
        };
        // Run a visitor
        {
            let mut visitor = UnsafeCellVisitor {
                ecx: this,
                unsafe_cell_action: |place| {
                    trace!("unsafe_cell_action on {:?}", place.ptr);
                    // We need a size to go on.
                    let unsafe_cell_size = this.size_and_align_of_mplace(place)?
                        .map(|(size, _)| size)
                        // for extern types, just cover what we can
                        .unwrap_or_else(|| place.layout.size);
                    // Now handle this `UnsafeCell`, unless it is empty.
                    if unsafe_cell_size != Size::ZERO {
                        unsafe_cell_action(place.ptr, unsafe_cell_size)
                    } else {
                        Ok(())
                    }
                },
            };
            visitor.visit_value(place)?;
        }
        // The part between the end_ptr and the end of the place is also frozen.
        // So pretend there is a 0-sized `UnsafeCell` at the end.
        unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?;
        // Done!
        return Ok(());

        /// Visiting the memory covered by a `MemPlace`, being aware of
        /// whether we are inside an `UnsafeCell` or not.
        struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
            where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            ecx: &'ecx MiriEvalContext<'mir, 'tcx>,
            unsafe_cell_action: F,
        }

        impl<'ecx, 'mir, 'tcx, F>
            ValueVisitor<'mir, 'tcx, Evaluator<'tcx>>
        for
            UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
        where
            F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            type V = MPlaceTy<'tcx, Tag>;

            #[inline(always)]
            fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> {
                &self.ecx
            }

            // Hook to detect `UnsafeCell`.
            fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
                let is_unsafe_cell = match v.layout.ty.sty {
                    ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(),
                    _ => false,
                };
                if is_unsafe_cell {
                    // We do not have to recurse further, this is an `UnsafeCell`.
                    (self.unsafe_cell_action)(v)
                } else if self.ecx.type_is_freeze(v.layout.ty) {
                    // This is `Freeze`, there cannot be an `UnsafeCell`
                    Ok(())
                } else {
                    // Proceed further
                    self.walk_value(v)
                }
            }

            // Make sure we visit aggregrates in increasing offset order.
            fn visit_aggregate(
                &mut self,
                place: MPlaceTy<'tcx, Tag>,
                fields: impl Iterator<Item=InterpResult<'tcx, MPlaceTy<'tcx, Tag>>>,
            ) -> InterpResult<'tcx> {
                match place.layout.fields {
                    layout::FieldPlacement::Array { .. } => {
                        // For the array layout, we know the iterator will yield sorted elements so
                        // we can avoid the allocation.
                        self.walk_aggregate(place, fields)
                    }
                    layout::FieldPlacement::Arbitrary { .. } => {
                        // Gather the subplaces and sort them before visiting.
                        let mut places = fields.collect::<InterpResult<'tcx, Vec<MPlaceTy<'tcx, Tag>>>>()?;
                        places.sort_by_key(|place| place.ptr.assert_ptr().offset);
                        self.walk_aggregate(place, places.into_iter().map(Ok))
                    }
                    layout::FieldPlacement::Union { .. } => {
                        // Uh, what?
                        bug!("a union is not an aggregate we should ever visit")
                    }
                }
            }

            // We have to do *something* for unions.
            fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                // With unions, we fall back to whatever the type says, to hopefully be consistent
                // with LLVM IR.
                // FIXME: are we consistent, and is this really the behavior we want?
                let frozen = self.ecx.type_is_freeze(v.layout.ty);
                if frozen {
                    Ok(())
                } else {
                    (self.unsafe_cell_action)(v)
                }
            }

            // We should never get to a primitive, but always short-circuit somewhere above.
            fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                bug!("we should always short-circuit before coming to a primitive")
            }
        }
    }
}
<commit_msg>Replace match with expect()<commit_after>use std::mem;

use rustc::ty::{self, layout::{self, Size, Align}};
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc::mir;

use rand::RngCore;

use crate::*;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}

pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Gets an instance for a path.
    fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> {
        let this = self.eval_context_ref();
        this.tcx
            .crates()
            .iter()
            .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0])
            .and_then(|krate| {
                let krate = DefId {
                    krate: *krate,
                    index: CRATE_DEF_INDEX,
                };
                let mut items = this.tcx.item_children(krate);
                let mut path_it = path.iter().skip(1).peekable();

                while let Some(segment) = path_it.next() {
                    for item in mem::replace(&mut items, Default::default()).iter() {
                        if item.ident.name.as_str() == *segment {
                            if path_it.peek().is_none() {
                                return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id()));
                            }

                            items = this.tcx.item_children(item.res.def_id());
                            break;
                        }
                    }
                }
                None
            })
            .ok_or_else(|| {
                let path = path.iter().map(|&s| s.to_owned()).collect();
                err_unsup!(PathNotFound(path)).into()
            })
    }

    /// Write a 0 of the appropriate size to `dest`.
    fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
        self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
    }

    /// Test if this immediate equals 0.
    fn is_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_ref();
        let null = Scalar::from_int(0, this.memory().pointer_size());
        this.ptr_eq(val, null)
    }

    /// Turn a Scalar into an Option<NonNullScalar>
    fn test_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, Option<Scalar<Tag>>> {
        let this = self.eval_context_ref();
        Ok(if this.is_null(val)? {
            None
        } else {
            Some(val)
        })
    }

    /// Get the `Place` for a local
    fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> {
        let this = self.eval_context_mut();
        let place = mir::Place { base: mir::PlaceBase::Local(local), projection: None };
        this.eval_place(&place)
    }

    /// Generate some random bytes, and write them to `dest`.
    fn gen_random(
        &mut self,
        ptr: Scalar<Tag>,
        len: usize,
    ) -> InterpResult<'tcx>  {
        // Some programs pass in a null pointer and a length of 0
        // to their platform's random-generation function (e.g. getrandom())
        // on Linux. For compatibility with these programs, we don't perform
        // any additional checks - it's okay if the pointer is invalid,
        // since we wouldn't actually be writing to it.
        if len == 0 {
            return Ok(());
        }
        let this = self.eval_context_mut();

        let ptr = this.memory().check_ptr_access(
            ptr,
            Size::from_bytes(len as u64),
            Align::from_bytes(1).unwrap()
        )?.expect("we already checked for size 0");

        let rng = this.memory_mut().extra.rng.get_mut();
        let mut data = vec![0; len];
        rng.fill_bytes(&mut data);

        let tcx = &{this.tcx.tcx};
        this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data)
    }

    /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter
    /// will be true if this is frozen, false if this is in an `UnsafeCell`.
    fn visit_freeze_sensitive(
        &self,
        place: MPlaceTy<'tcx, Tag>,
        size: Size,
        mut action: impl FnMut(Pointer<Tag>, Size, bool) -> InterpResult<'tcx>,
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_ref();
        trace!("visit_frozen(place={:?}, size={:?})", *place, size);
        debug_assert_eq!(size,
            this.size_and_align_of_mplace(place)?
            .map(|(size, _)| size)
            .unwrap_or_else(|| place.layout.size)
        );
        // Store how far we proceeded into the place so far. Everything to the left of
        // this offset has already been handled, in the sense that the frozen parts
        // have had `action` called on them.
        let mut end_ptr = place.ptr.assert_ptr();
        // Called when we detected an `UnsafeCell` at the given offset and size.
        // Calls `action` and advances `end_ptr`.
        let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar<Tag>, unsafe_cell_size: Size| {
            let unsafe_cell_ptr = unsafe_cell_ptr.assert_ptr();
            debug_assert_eq!(unsafe_cell_ptr.alloc_id, end_ptr.alloc_id);
            debug_assert_eq!(unsafe_cell_ptr.tag, end_ptr.tag);
            // We assume that we are given the fields in increasing offset order,
            // and nothing else changes.
            let unsafe_cell_offset = unsafe_cell_ptr.offset;
            let end_offset = end_ptr.offset;
            assert!(unsafe_cell_offset >= end_offset);
            let frozen_size = unsafe_cell_offset - end_offset;
            // Everything between the end_ptr and this `UnsafeCell` is frozen.
            if frozen_size != Size::ZERO {
                action(end_ptr, frozen_size, /*frozen*/true)?;
            }
            // This `UnsafeCell` is NOT frozen.
            if unsafe_cell_size != Size::ZERO {
                action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/false)?;
            }
            // Update end end_ptr.
            end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this);
            // Done
            Ok(())
        };
        // Run a visitor
        {
            let mut visitor = UnsafeCellVisitor {
                ecx: this,
                unsafe_cell_action: |place| {
                    trace!("unsafe_cell_action on {:?}", place.ptr);
                    // We need a size to go on.
                    let unsafe_cell_size = this.size_and_align_of_mplace(place)?
                        .map(|(size, _)| size)
                        // for extern types, just cover what we can
                        .unwrap_or_else(|| place.layout.size);
                    // Now handle this `UnsafeCell`, unless it is empty.
                    if unsafe_cell_size != Size::ZERO {
                        unsafe_cell_action(place.ptr, unsafe_cell_size)
                    } else {
                        Ok(())
                    }
                },
            };
            visitor.visit_value(place)?;
        }
        // The part between the end_ptr and the end of the place is also frozen.
        // So pretend there is a 0-sized `UnsafeCell` at the end.
        unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?;
        // Done!
        return Ok(());

        /// Visiting the memory covered by a `MemPlace`, being aware of
        /// whether we are inside an `UnsafeCell` or not.
        struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
            where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            ecx: &'ecx MiriEvalContext<'mir, 'tcx>,
            unsafe_cell_action: F,
        }

        impl<'ecx, 'mir, 'tcx, F>
            ValueVisitor<'mir, 'tcx, Evaluator<'tcx>>
        for
            UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
        where
            F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            type V = MPlaceTy<'tcx, Tag>;

            #[inline(always)]
            fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> {
                &self.ecx
            }

            // Hook to detect `UnsafeCell`.
            fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
                let is_unsafe_cell = match v.layout.ty.sty {
                    ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(),
                    _ => false,
                };
                if is_unsafe_cell {
                    // We do not have to recurse further, this is an `UnsafeCell`.
                    (self.unsafe_cell_action)(v)
                } else if self.ecx.type_is_freeze(v.layout.ty) {
                    // This is `Freeze`, there cannot be an `UnsafeCell`
                    Ok(())
                } else {
                    // Proceed further
                    self.walk_value(v)
                }
            }

            // Make sure we visit aggregrates in increasing offset order.
            fn visit_aggregate(
                &mut self,
                place: MPlaceTy<'tcx, Tag>,
                fields: impl Iterator<Item=InterpResult<'tcx, MPlaceTy<'tcx, Tag>>>,
            ) -> InterpResult<'tcx> {
                match place.layout.fields {
                    layout::FieldPlacement::Array { .. } => {
                        // For the array layout, we know the iterator will yield sorted elements so
                        // we can avoid the allocation.
                        self.walk_aggregate(place, fields)
                    }
                    layout::FieldPlacement::Arbitrary { .. } => {
                        // Gather the subplaces and sort them before visiting.
                        let mut places = fields.collect::<InterpResult<'tcx, Vec<MPlaceTy<'tcx, Tag>>>>()?;
                        places.sort_by_key(|place| place.ptr.assert_ptr().offset);
                        self.walk_aggregate(place, places.into_iter().map(Ok))
                    }
                    layout::FieldPlacement::Union { .. } => {
                        // Uh, what?
                        bug!("a union is not an aggregate we should ever visit")
                    }
                }
            }

            // We have to do *something* for unions.
            fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                // With unions, we fall back to whatever the type says, to hopefully be consistent
                // with LLVM IR.
                // FIXME: are we consistent, and is this really the behavior we want?
                let frozen = self.ecx.type_is_freeze(v.layout.ty);
                if frozen {
                    Ok(())
                } else {
                    (self.unsafe_cell_action)(v)
                }
            }

            // We should never get to a primitive, but always short-circuit somewhere above.
            fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                bug!("we should always short-circuit before coming to a primitive")
            }
        }
    }
}
<|endoftext|>