<commit_before>use std::num::Float;
use std::ops::Sub;

// The Earth's radius in kilometers.
static EARTH_RADIUS: f64 = 6371.009;

/// A geographic location.
#[derive(Default, Copy, PartialEq)]
pub struct GeoLocation {
    /// Latitude in degrees.
    pub latitude: f64,
    /// Longitude in degrees.
    pub longitude: f64
}

impl GeoLocation {
    /// Creates a new `GeoLocation` with latitude and longitude set to
    /// zero.
    ///
    /// # Example
    ///
    /// ```
    /// let l = geohashrust::GeoLocation::new();
    /// assert_eq!(l.latitude, 0.0);
    /// assert_eq!(l.longitude, 0.0);
    /// ```
    pub fn new() -> GeoLocation {
        GeoLocation {
            latitude: 0.0,
            longitude: 0.0
        }
    }

    /// Creates a new `GeoLocation` with `latitude` and `longitude`.
    ///
    /// # Example
    ///
    /// ```
    /// let l = geohashrust::GeoLocation::from_coordinates(48.1333, 11.5667);
    /// assert_eq!(l.latitude, 48.1333);
    /// assert_eq!(l.longitude, 11.5667);
    /// ```
    pub fn from_coordinates(latitude: f64, longitude: f64) -> GeoLocation {
        assert!(latitude.abs()<=90.0);
        assert!(longitude.abs()<=180.0);
        GeoLocation {
            latitude: latitude,
            longitude: longitude
        }
    }

    /// Returns the distance between `self` and `other` in meters. The
    /// calculation is done using the Haversine formula.
    ///
    /// # Example
    ///
    /// ```
    /// use std::num::Float;
    /// let new_york = geohashrust::GeoLocation::from_coordinates(40.7127, -74.0059);
    /// let helsinki = geohashrust::GeoLocation::from_coordinates(60.1708, 24.9375);
    /// assert_eq!(new_york.distance_to(helsinki).round(), 6618.0);
    /// ```
    pub fn distance_to(&self, other: GeoLocation) -> f64 {
        let lat1 = self.latitude.to_radians();
        let lat2 = other.latitude.to_radians();
        let dlat = (other.latitude - self.latitude).to_radians();
        let dlon = (other.longitude - self.longitude).to_radians();

        let a = (dlat / 2.0).sin() * (dlat / 2.0).sin() +
            lat1.cos() * lat2.cos() *
            (dlon / 2.0).sin() * (dlon / 2.0).sin();
        let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());

        EARTH_RADIUS * c
    }
}

/// Returns the distance between `self` and `other` in meters. The
/// calculation is done using the Haversine formula.
///
/// # Example
///
/// ```
/// use std::num::Float;
/// let new_york = geohashrust::GeoLocation::from_coordinates(40.7127, -74.0059);
/// let helsinki = geohashrust::GeoLocation::from_coordinates(60.1708, 24.9375);
/// assert_eq!((new_york-helsinki).round(), 6618.0);
/// ```
impl Sub<GeoLocation> for GeoLocation {
    type Output = f64;
     fn sub(self, rhs: GeoLocation) -> f64 {
        self.distance_to(rhs)
     }
}

<commit_msg>Format<commit_after>use std::num::Float;
use std::ops::Sub;

// The Earth's radius in kilometers.
static EARTH_RADIUS: f64 = 6371.009;

/// A geographic location.
#[derive(Default, Copy, PartialEq)]
pub struct GeoLocation {
    /// Latitude in degrees.
    pub latitude: f64,
    /// Longitude in degrees.
    pub longitude: f64
}

impl GeoLocation {
    /// Creates a new `GeoLocation` with latitude and longitude set to
    /// zero.
    ///
    /// # Example
    ///
    /// ```
    /// let l = geohashrust::GeoLocation::new();
    /// assert_eq!(l.latitude, 0.0);
    /// assert_eq!(l.longitude, 0.0);
    /// ```
    pub fn new() -> GeoLocation {
        GeoLocation {
            latitude: 0.0,
            longitude: 0.0
        }
    }

    /// Creates a new `GeoLocation` with `latitude` and `longitude`.
    ///
    /// # Example
    ///
    /// ```
    /// let l = geohashrust::GeoLocation::from_coordinates(48.1333, 11.5667);
    /// assert_eq!(l.latitude, 48.1333);
    /// assert_eq!(l.longitude, 11.5667);
    /// ```
    pub fn from_coordinates(latitude: f64, longitude: f64) -> GeoLocation {
        assert!(latitude.abs()<=90.0);
        assert!(longitude.abs()<=180.0);
        GeoLocation {
            latitude: latitude,
            longitude: longitude
        }
    }

    /// Returns the distance between `self` and `other` in meters. The
    /// calculation is done using the Haversine formula.
    ///
    /// # Example
    ///
    /// ```
    /// use std::num::Float;
    /// let new_york = geohashrust::GeoLocation::from_coordinates(40.7127, -74.0059);
    /// let helsinki = geohashrust::GeoLocation::from_coordinates(60.1708, 24.9375);
    /// assert_eq!(new_york.distance_to(helsinki).round(), 6618.0);
    /// ```
    pub fn distance_to(&self, other: GeoLocation) -> f64 {
        let lat1 = self.latitude.to_radians();
        let lat2 = other.latitude.to_radians();
        let dlat = (other.latitude - self.latitude).to_radians();
        let dlon = (other.longitude - self.longitude).to_radians();

        let a = (dlat / 2.0).sin() * (dlat / 2.0).sin() +
            lat1.cos() * lat2.cos() *
            (dlon / 2.0).sin() * (dlon / 2.0).sin();
        let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());

        EARTH_RADIUS * c
    }
}

/// Returns the distance between `self` and `other` in meters. The
/// calculation is done using the Haversine formula.
///
/// # Example
///
/// ```
/// use std::num::Float;
/// let new_york = geohashrust::GeoLocation::from_coordinates(40.7127, -74.0059);
/// let helsinki = geohashrust::GeoLocation::from_coordinates(60.1708, 24.9375);
/// assert_eq!((new_york-helsinki).round(), 6618.0);
/// ```
impl Sub<GeoLocation> for GeoLocation {
    type Output = f64;
    fn sub(self, rhs: GeoLocation) -> f64 {
        self.distance_to(rhs)
    }
}

<|endoftext|>


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

//! Helpers for reading directory structures from the local filesystem.

use std::sync;
use std::os::{last_os_error};
use std::io::{TypeDirectory};
use std::io::fs::{lstat};

use std::c_str::CString;
use libc::funcs::posix88::dirent;
use libc::types::common::posix88::{DIR,dirent_t};
use libc::types::os::arch::c95::c_char;
use libc::{c_int};

pub struct DirIterator {
  fd: *mut DIR,
}

impl DirIterator {
  pub fn new(path: Path) -> Result<DirIterator, String> {
    let fd = path.with_c_str(|c_str| unsafe { dirent::opendir(c_str) });

    if fd as int > 0 { Ok(DirIterator{fd:fd}) }
    else { Err(last_os_error()) }
  }

  fn read(&mut self) -> String {
    extern {
      fn rust_dirent_t_size() -> c_int;
      fn rust_list_dir_val(ptr: *mut dirent_t) -> *const c_char;
    }

    let mut entry_ptr = 0 as *mut dirent_t;

    let size = unsafe { rust_dirent_t_size() };
    let mut buf = Vec::<u8>::with_capacity(size as uint);
    let buf_ptr = buf.as_mut_ptr() as *mut dirent_t;

    let retval = unsafe { dirent::readdir_r(self.fd, buf_ptr, &mut entry_ptr) };

    if retval == 0 && !entry_ptr.is_null() {
      let cstr = unsafe { CString::new(rust_list_dir_val(entry_ptr), false) };
      cstr.as_str().expect("Path not UTF8.").into_string()
    } else { "".to_string() }

  }

}

impl Drop for DirIterator {
  fn drop(&mut self) {
    unsafe {
      dirent::closedir(self.fd)
    };
  }
}

impl Iterator<String> for DirIterator {
  fn next(&mut self) -> Option<String> {
    let name = self.read();
    if name.len() == 0 { None }
    else { Some(name) }
  }
}

pub trait PathHandler<D> {
  fn handle_path(&mut self, D, Path) -> Option<D>;
}

pub fn iterate_recursively<P: Send + Clone, W: PathHandler<P> + Send + Clone>
  (root: (Path, P), worker: &mut W)
{
  let threads = 5;
  let (push_ch, work_ch) = sync_channel(threads);
  let mut pool = sync::TaskPool::new(threads, || proc(_){()});

  // Insert the first task into the queue:
  push_ch.send(Some(root));
  let mut running_workers = 0i;

  // Master thread:
  loop {
    match work_ch.recv() {
      None => {
        // A worker has reached completion and has decremented the counter.
        // We are done when no more workers are active (i.e. all tasks are done):
        running_workers -= 1;
        if running_workers == 0 {
          break
        }
      },
      Some((root, payload)) => {
        let t_worker = worker.clone();
        let t_push_ch = push_ch.clone();

        // Execute the task in a pool thread:
        running_workers += 1;
        pool.execute(proc(&()) {
          let mut root = root;
          let mut t_worker = t_worker;
          let res = DirIterator::new(root.clone());
          if res.is_ok() {
            let mut it = res.unwrap();
            for file in it {
              if file != ".".into_string() && file != "..".into_string() {
                let rel_path = Path::new(file);
                root.push(rel_path);
                let dir_opt = t_worker.handle_path(payload.clone(), root.clone());
                if dir_opt.is_some() {
                  t_push_ch.send(Some((root.clone(), dir_opt.unwrap())));
                }
                root.pop();
              }
            }
          }

          // Count this pool thread as idle:
          t_push_ch.send(None)
        });
      }
    }
  }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
  fn clone(&self) -> PrintPathHandler { PrintPathHandler }
}

impl PathHandler<()> for PrintPathHandler {
  fn handle_path(&mut self, _: (), path: Path) -> Option<()> {
    let filename_opt = path.filename_str();
    println!("{}", path.display());
    match filename_opt {
      Some(".") | Some("..") | None => None,
      Some(_) =>
      match lstat(&path) {
        Ok(ref st) if st.kind == TypeDirectory => Some(()),
        _ => None,
      }
    }
  }
}
<commit_msg>Minor: fix comment to reflect previous commit.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Helpers for reading directory structures from the local filesystem.

use std::sync;
use std::os::{last_os_error};
use std::io::{TypeDirectory};
use std::io::fs::{lstat};

use std::c_str::CString;
use libc::funcs::posix88::dirent;
use libc::types::common::posix88::{DIR,dirent_t};
use libc::types::os::arch::c95::c_char;
use libc::{c_int};

pub struct DirIterator {
  fd: *mut DIR,
}

impl DirIterator {
  pub fn new(path: Path) -> Result<DirIterator, String> {
    let fd = path.with_c_str(|c_str| unsafe { dirent::opendir(c_str) });

    if fd as int > 0 { Ok(DirIterator{fd:fd}) }
    else { Err(last_os_error()) }
  }

  fn read(&mut self) -> String {
    extern {
      fn rust_dirent_t_size() -> c_int;
      fn rust_list_dir_val(ptr: *mut dirent_t) -> *const c_char;
    }

    let mut entry_ptr = 0 as *mut dirent_t;

    let size = unsafe { rust_dirent_t_size() };
    let mut buf = Vec::<u8>::with_capacity(size as uint);
    let buf_ptr = buf.as_mut_ptr() as *mut dirent_t;

    let retval = unsafe { dirent::readdir_r(self.fd, buf_ptr, &mut entry_ptr) };

    if retval == 0 && !entry_ptr.is_null() {
      let cstr = unsafe { CString::new(rust_list_dir_val(entry_ptr), false) };
      cstr.as_str().expect("Path not UTF8.").into_string()
    } else { "".to_string() }

  }

}

impl Drop for DirIterator {
  fn drop(&mut self) {
    unsafe {
      dirent::closedir(self.fd)
    };
  }
}

impl Iterator<String> for DirIterator {
  fn next(&mut self) -> Option<String> {
    let name = self.read();
    if name.len() == 0 { None }
    else { Some(name) }
  }
}

pub trait PathHandler<D> {
  fn handle_path(&mut self, D, Path) -> Option<D>;
}

pub fn iterate_recursively<P: Send + Clone, W: PathHandler<P> + Send + Clone>
  (root: (Path, P), worker: &mut W)
{
  let threads = 5;
  let (push_ch, work_ch) = sync_channel(threads);
  let mut pool = sync::TaskPool::new(threads, || proc(_){()});

  // Insert the first task into the queue:
  push_ch.send(Some(root));
  let mut running_workers = 0i;

  // Master thread:
  loop {
    match work_ch.recv() {
      None => {
        // A worker has completed a task.
        // We are done when no more workers are active (i.e. all tasks are done):
        running_workers -= 1;
        if running_workers == 0 {
          break
        }
      },
      Some((root, payload)) => {
        let t_worker = worker.clone();
        let t_push_ch = push_ch.clone();

        // Execute the task in a pool thread:
        running_workers += 1;
        pool.execute(proc(&()) {
          let mut root = root;
          let mut t_worker = t_worker;
          let res = DirIterator::new(root.clone());
          if res.is_ok() {
            let mut it = res.unwrap();
            for file in it {
              if file != ".".into_string() && file != "..".into_string() {
                let rel_path = Path::new(file);
                root.push(rel_path);
                let dir_opt = t_worker.handle_path(payload.clone(), root.clone());
                if dir_opt.is_some() {
                  t_push_ch.send(Some((root.clone(), dir_opt.unwrap())));
                }
                root.pop();
              }
            }
          }

          // Count this pool thread as idle:
          t_push_ch.send(None)
        });
      }
    }
  }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
  fn clone(&self) -> PrintPathHandler { PrintPathHandler }
}

impl PathHandler<()> for PrintPathHandler {
  fn handle_path(&mut self, _: (), path: Path) -> Option<()> {
    let filename_opt = path.filename_str();
    println!("{}", path.display());
    match filename_opt {
      Some(".") | Some("..") | None => None,
      Some(_) =>
      match lstat(&path) {
        Ok(ref st) if st.kind == TypeDirectory => Some(()),
        _ => None,
      }
    }
  }
}
<|endoftext|>


<commit_before>use rustc::middle::{const_eval, def_id, ty};
use rustc_mir::mir_map::MirMap;
use rustc_mir::repr::{self as mir, Mir};
use syntax::ast::Attribute;
use syntax::attr::AttrMetaMethods;

use std::iter;

#[derive(Clone, Debug, PartialEq)]
enum Value {
    Uninit,
    Bool(bool),
    Int(i64), // FIXME: Should be bit-width aware.
    Func(def_id::DefId),
}

#[derive(Debug)]
struct Frame {
    offset: usize,
    num_args: usize,
    num_vars: usize,
    num_temps: usize,
}

impl Frame {
    fn size(&self) -> usize {
        1 + self.num_args + self.num_vars + self.num_temps
    }
}

struct Interpreter<'a, 'tcx: 'a> {
    tcx: &'a ty::ctxt<'tcx>,
    mir_map: &'a MirMap<'tcx>,
    value_stack: Vec<Value>,
    call_stack: Vec<Frame>,
}

impl<'a, 'tcx> Interpreter<'a, 'tcx> {
    fn new(tcx: &'a ty::ctxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
        Interpreter {
            tcx: tcx,
            mir_map: mir_map,
            value_stack: Vec::new(),
            call_stack: Vec::new(),
        }
    }

    fn push_stack_frame(&mut self, mir: &Mir, args: &[Value]) {
        self.call_stack.push(Frame {
            offset: self.value_stack.len(),
            num_args: mir.arg_decls.len(),
            num_vars: mir.var_decls.len(),
            num_temps: mir.temp_decls.len(),
        });

        let frame = self.call_stack.last().unwrap();
        self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size()));

        for (i, arg) in args.iter().enumerate() {
            self.value_stack[frame.offset + 1 + i] = arg.clone();
        }
    }

    fn pop_stack_frame(&mut self) {
        let frame = self.call_stack.pop().expect("tried to pop stack frame, but there were none");
        self.value_stack.truncate(frame.offset);
    }

    fn call(&mut self, mir: &Mir, args: &[Value]) -> Value {
        self.push_stack_frame(mir, args);
        let mut block = mir::START_BLOCK;

        loop {
            use rustc_mir::repr::Terminator::*;

            let block_data = mir.basic_block_data(block);

            for stmt in &block_data.statements {
                use rustc_mir::repr::StatementKind::*;

                match stmt.kind {
                    Assign(ref lvalue, ref rvalue) => {
                        let index = self.eval_lvalue(lvalue);
                        let value = self.eval_rvalue(rvalue);
                        self.value_stack[index] = value;
                    }

                    Drop(_kind, ref _lv) => {
                        // TODO
                    },
                }
            }

            match block_data.terminator {
                Return => break,
                Goto { target } => block = target,

                Call { data: mir::CallData { ref destination, ref func, ref args }, targets } => {
                    let index = self.eval_lvalue(destination);
                    let func_val = self.eval_operand(func);

                    if let Value::Func(def_id) = func_val {
                        let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
                        let mir = &self.mir_map[&node_id];
                        let arg_vals: Vec<Value> =
                            args.iter().map(|arg| self.eval_operand(arg)).collect();

                        self.value_stack[index] = self.call(mir, &arg_vals);
                        block = targets[0];
                    } else {
                        panic!("tried to call a non-function value: {:?}", func_val);
                    }
                }

                If { ref cond, targets } => {
                    match self.eval_operand(cond) {
                        Value::Bool(true) => block = targets[0],
                        Value::Bool(false) => block = targets[1],
                        cond_val => panic!("Non-boolean `if` condition value: {:?}", cond_val),
                    }
                }

                SwitchInt { ref discr, switch_ty: _, ref values, ref targets } => {
                    let discr_val = &self.value_stack[self.eval_lvalue(discr)];

                    let index = values.iter().position(|v| *discr_val == self.eval_constant(v))
                        .expect("discriminant matched no values");

                    block = targets[index];
                }

                // Diverge => unimplemented!(),
                // Panic { target } => unimplemented!(),
                // Switch { ref discr, adt_def, ref targets } => unimplemented!(),
                _ => unimplemented!(),
            }
        }

        let ret_val = self.value_stack[self.eval_lvalue(&mir::Lvalue::ReturnPointer)].clone();
        self.pop_stack_frame();
        ret_val
    }

    fn eval_lvalue(&self, lvalue: &mir::Lvalue) -> usize {
        use rustc_mir::repr::Lvalue::*;

        let frame = self.call_stack.last().expect("missing call frame");

        match *lvalue {
            ReturnPointer => frame.offset,
            Arg(i)  => frame.offset + 1 + i as usize,
            Var(i)  => frame.offset + 1 + frame.num_args + i as usize,
            Temp(i) => frame.offset + 1 + frame.num_args + frame.num_vars + i as usize,
            _ => unimplemented!(),
        }
    }

    fn eval_rvalue(&mut self, rvalue: &mir::Rvalue) -> Value {
        use rustc_mir::repr::Rvalue::*;
        use rustc_mir::repr::BinOp::*;
        use rustc_mir::repr::UnOp::*;

        match *rvalue {
            Use(ref operand) => self.eval_operand(operand),

            BinaryOp(bin_op, ref left, ref right) => {
                match (self.eval_operand(left), self.eval_operand(right)) {
                    (Value::Int(l), Value::Int(r)) => {
                        match bin_op {
                            Add => Value::Int(l + r),
                            Sub => Value::Int(l - r),
                            Mul => Value::Int(l * r),
                            Div => Value::Int(l / r),
                            Rem => Value::Int(l % r),
                            BitXor => Value::Int(l ^ r),
                            BitAnd => Value::Int(l & r),
                            BitOr => Value::Int(l | r),
                            Shl => Value::Int(l << r),
                            Shr => Value::Int(l >> r),
                            Eq => Value::Bool(l == r),
                            Lt => Value::Bool(l < r),
                            Le => Value::Bool(l <= r),
                            Ne => Value::Bool(l != r),
                            Ge => Value::Bool(l >= r),
                            Gt => Value::Bool(l > r),
                        }
                    }
                    _ => unimplemented!(),
                }
            }

            UnaryOp(un_op, ref operand) => {
                match (un_op, self.eval_operand(operand)) {
                    (Not, Value::Int(n)) => Value::Int(!n),
                    (Neg, Value::Int(n)) => Value::Int(-n),
                    _ => unimplemented!(),
                }
            }

            _ => unimplemented!(),
        }
    }

    fn eval_operand(&mut self, op: &mir::Operand) -> Value {
        use rustc_mir::repr::Operand::*;

        match *op {
            Consume(ref lvalue) => self.value_stack[self.eval_lvalue(lvalue)].clone(),

            Constant(ref constant) => {
                match constant.literal {
                    mir::Literal::Value { ref value } => self.eval_constant(value),

                    mir::Literal::Item { def_id, substs: _ } => {
                        Value::Func(def_id)
                    }
                }
            }
        }
    }

    fn eval_constant(&self, const_val: &const_eval::ConstVal) -> Value {
        use rustc::middle::const_eval::ConstVal::*;

        match *const_val {
            Float(_f) => unimplemented!(),
            Int(i) => Value::Int(i),
            Uint(_u) => unimplemented!(),
            Str(ref _s) => unimplemented!(),
            ByteStr(ref _bs) => unimplemented!(),
            Bool(b) => Value::Bool(b),
            Struct(_node_id) => unimplemented!(),
            Tuple(_node_id) => unimplemented!(),
            Function(_def_id) => unimplemented!(),
        }
    }
}

pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx>) {
    for (&id, mir) in mir_map {
        for attr in tcx.map.attrs(id) {
            if attr.check_name("miri_run") {
                let item = tcx.map.expect_item(id);

                println!("Interpreting: {}", item.name);
                let mut interpreter = Interpreter::new(tcx, mir_map);
                let val = interpreter.call(mir, &[]);
                let val_str = format!("{:?}", val);

                if !check_expected(&val_str, attr) {
                    println!("=> {}\n", val_str);
                }
            }
        }
    }
}

fn check_expected(actual: &str, attr: &Attribute) -> bool {
    if let Some(meta_items) = attr.meta_item_list() {
        for meta_item in meta_items {
            if meta_item.check_name("expected") {
                let expected = meta_item.value_str().unwrap();

                if actual == &expected[..] {
                    println!("Test passed!\n");
                } else {
                    println!("Actual value:\t{}\nExpected value:\t{}\n", actual, expected);
                }

                return true;
            }
        }
    }

    false
}
<commit_msg>Add a constant flag to enable and disable execution trac printouts.<commit_after>use rustc::middle::{const_eval, def_id, ty};
use rustc_mir::mir_map::MirMap;
use rustc_mir::repr::{self as mir, Mir};
use syntax::ast::Attribute;
use syntax::attr::AttrMetaMethods;

use std::iter;

const TRACE_EXECUTION: bool = false;

#[derive(Clone, Debug, PartialEq)]
enum Value {
    Uninit,
    Bool(bool),
    Int(i64), // FIXME: Should be bit-width aware.
    Func(def_id::DefId),
}

#[derive(Debug)]
struct Frame {
    offset: usize,
    num_args: usize,
    num_vars: usize,
    num_temps: usize,
}

impl Frame {
    fn size(&self) -> usize {
        1 + self.num_args + self.num_vars + self.num_temps
    }
}

struct Interpreter<'a, 'tcx: 'a> {
    tcx: &'a ty::ctxt<'tcx>,
    mir_map: &'a MirMap<'tcx>,
    value_stack: Vec<Value>,
    call_stack: Vec<Frame>,
}

impl<'a, 'tcx> Interpreter<'a, 'tcx> {
    fn new(tcx: &'a ty::ctxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
        Interpreter {
            tcx: tcx,
            mir_map: mir_map,
            value_stack: Vec::new(),
            call_stack: Vec::new(),
        }
    }

    fn push_stack_frame(&mut self, mir: &Mir, args: &[Value]) {
        self.call_stack.push(Frame {
            offset: self.value_stack.len(),
            num_args: mir.arg_decls.len(),
            num_vars: mir.var_decls.len(),
            num_temps: mir.temp_decls.len(),
        });

        let frame = self.call_stack.last().unwrap();
        self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size()));

        for (i, arg) in args.iter().enumerate() {
            self.value_stack[frame.offset + 1 + i] = arg.clone();
        }
    }

    fn pop_stack_frame(&mut self) {
        let frame = self.call_stack.pop().expect("tried to pop stack frame, but there were none");
        self.value_stack.truncate(frame.offset);
    }

    fn call(&mut self, mir: &Mir, args: &[Value]) -> Value {
        self.push_stack_frame(mir, args);
        let mut block = mir::START_BLOCK;

        loop {
            use rustc_mir::repr::Terminator::*;

            let block_data = mir.basic_block_data(block);

            for stmt in &block_data.statements {
                use rustc_mir::repr::StatementKind::*;

                if TRACE_EXECUTION { println!("{:?}", stmt); }

                match stmt.kind {
                    Assign(ref lvalue, ref rvalue) => {
                        let index = self.eval_lvalue(lvalue);
                        let value = self.eval_rvalue(rvalue);
                        self.value_stack[index] = value;
                    }

                    Drop(_kind, ref _lv) => {
                        // TODO
                    },
                }
            }

            if TRACE_EXECUTION { println!("{:?}", block_data.terminator); }

            match block_data.terminator {
                Return => break,
                Goto { target } => block = target,

                Call { data: mir::CallData { ref destination, ref func, ref args }, targets } => {
                    let index = self.eval_lvalue(destination);
                    let func_val = self.eval_operand(func);

                    if let Value::Func(def_id) = func_val {
                        let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
                        let mir = &self.mir_map[&node_id];
                        let arg_vals: Vec<Value> =
                            args.iter().map(|arg| self.eval_operand(arg)).collect();

                        self.value_stack[index] = self.call(mir, &arg_vals);
                        block = targets[0];
                    } else {
                        panic!("tried to call a non-function value: {:?}", func_val);
                    }
                }

                If { ref cond, targets } => {
                    match self.eval_operand(cond) {
                        Value::Bool(true) => block = targets[0],
                        Value::Bool(false) => block = targets[1],
                        cond_val => panic!("Non-boolean `if` condition value: {:?}", cond_val),
                    }
                }

                SwitchInt { ref discr, switch_ty: _, ref values, ref targets } => {
                    let discr_val = &self.value_stack[self.eval_lvalue(discr)];

                    let index = values.iter().position(|v| *discr_val == self.eval_constant(v))
                        .expect("discriminant matched no values");

                    block = targets[index];
                }

                // Diverge => unimplemented!(),
                // Panic { target } => unimplemented!(),
                // Switch { ref discr, adt_def, ref targets } => unimplemented!(),
                _ => unimplemented!(),
            }
        }

        let ret_val = self.value_stack[self.eval_lvalue(&mir::Lvalue::ReturnPointer)].clone();
        self.pop_stack_frame();
        ret_val
    }

    fn eval_lvalue(&self, lvalue: &mir::Lvalue) -> usize {
        use rustc_mir::repr::Lvalue::*;

        let frame = self.call_stack.last().expect("missing call frame");

        match *lvalue {
            ReturnPointer => frame.offset,
            Arg(i)  => frame.offset + 1 + i as usize,
            Var(i)  => frame.offset + 1 + frame.num_args + i as usize,
            Temp(i) => frame.offset + 1 + frame.num_args + frame.num_vars + i as usize,
            _ => unimplemented!(),
        }
    }

    fn eval_rvalue(&mut self, rvalue: &mir::Rvalue) -> Value {
        use rustc_mir::repr::Rvalue::*;
        use rustc_mir::repr::BinOp::*;
        use rustc_mir::repr::UnOp::*;

        match *rvalue {
            Use(ref operand) => self.eval_operand(operand),

            BinaryOp(bin_op, ref left, ref right) => {
                match (self.eval_operand(left), self.eval_operand(right)) {
                    (Value::Int(l), Value::Int(r)) => {
                        match bin_op {
                            Add => Value::Int(l + r),
                            Sub => Value::Int(l - r),
                            Mul => Value::Int(l * r),
                            Div => Value::Int(l / r),
                            Rem => Value::Int(l % r),
                            BitXor => Value::Int(l ^ r),
                            BitAnd => Value::Int(l & r),
                            BitOr => Value::Int(l | r),
                            Shl => Value::Int(l << r),
                            Shr => Value::Int(l >> r),
                            Eq => Value::Bool(l == r),
                            Lt => Value::Bool(l < r),
                            Le => Value::Bool(l <= r),
                            Ne => Value::Bool(l != r),
                            Ge => Value::Bool(l >= r),
                            Gt => Value::Bool(l > r),
                        }
                    }
                    _ => unimplemented!(),
                }
            }

            UnaryOp(un_op, ref operand) => {
                match (un_op, self.eval_operand(operand)) {
                    (Not, Value::Int(n)) => Value::Int(!n),
                    (Neg, Value::Int(n)) => Value::Int(-n),
                    _ => unimplemented!(),
                }
            }

            _ => unimplemented!(),
        }
    }

    fn eval_operand(&mut self, op: &mir::Operand) -> Value {
        use rustc_mir::repr::Operand::*;

        match *op {
            Consume(ref lvalue) => self.value_stack[self.eval_lvalue(lvalue)].clone(),

            Constant(ref constant) => {
                match constant.literal {
                    mir::Literal::Value { ref value } => self.eval_constant(value),

                    mir::Literal::Item { def_id, substs: _ } => {
                        Value::Func(def_id)
                    }
                }
            }
        }
    }

    fn eval_constant(&self, const_val: &const_eval::ConstVal) -> Value {
        use rustc::middle::const_eval::ConstVal::*;

        match *const_val {
            Float(_f) => unimplemented!(),
            Int(i) => Value::Int(i),
            Uint(_u) => unimplemented!(),
            Str(ref _s) => unimplemented!(),
            ByteStr(ref _bs) => unimplemented!(),
            Bool(b) => Value::Bool(b),
            Struct(_node_id) => unimplemented!(),
            Tuple(_node_id) => unimplemented!(),
            Function(_def_id) => unimplemented!(),
        }
    }
}

pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx>) {
    for (&id, mir) in mir_map {
        for attr in tcx.map.attrs(id) {
            if attr.check_name("miri_run") {
                let item = tcx.map.expect_item(id);

                println!("Interpreting: {}", item.name);
                let mut interpreter = Interpreter::new(tcx, mir_map);
                let val = interpreter.call(mir, &[]);
                let val_str = format!("{:?}", val);

                if !check_expected(&val_str, attr) {
                    println!("=> {}\n", val_str);
                }
            }
        }
    }
}

fn check_expected(actual: &str, attr: &Attribute) -> bool {
    if let Some(meta_items) = attr.meta_item_list() {
        for meta_item in meta_items {
            if meta_item.check_name("expected") {
                let expected = meta_item.value_str().unwrap();

                if actual == &expected[..] {
                    println!("Test passed!\n");
                } else {
                    println!("Actual value:\t{}\nExpected value:\t{}\n", actual, expected);
                }

                return true;
            }
        }
    }

    false
}
<|endoftext|>


<commit_before>
use super::internal::*;
use super::*;
use std::cmp;
use std::iter;

/// An [`IndexedParallelIterator`] that iterates over two parallel iterators of equal
/// length simultaneously.
///
/// This struct is created by the [`zip_eq`] method on [`IndexedParallelIterator`],
/// see its documentation for more information.
///
/// [`zip_eq`]: trait.IndexedParallelIterator.html#method.zip_eq
/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct ZipEq<A: IndexedParallelIterator, B: IndexedParallelIterator> {
    zip: Zip<A, B>
}

/// Create a new `ZipEq` iterator.
///
/// NB: a free fn because it is NOT part of the end-user API.
#[inline]
pub fn new<A, B>(a: A, b: B) -> ZipEq<A, B>
    where A: IndexedParallelIterator,
          B: IndexedParallelIterator
{
    ZipEq { zip: super::zip::new(a, b) }
}

impl<A, B> ParallelIterator for ZipEq<A, B>
    where A: IndexedParallelIterator,
          B: IndexedParallelIterator
{
    type Item = (A::Item, B::Item);

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self.zip, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.zip.len())
    }
}

impl<A, B> IndexedParallelIterator for ZipEq<A, B>
    where A: IndexedParallelIterator,
          B: IndexedParallelIterator
{
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self.zip, consumer)
    }

    fn len(&mut self) -> usize {
        self.zip.len()
    }

    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        self.zip.with_producer(callback)
    }
}
<commit_msg>remove unused imports from `zip_eq`<commit_after>
use super::internal::*;
use super::*;

/// An [`IndexedParallelIterator`] that iterates over two parallel iterators of equal
/// length simultaneously.
///
/// This struct is created by the [`zip_eq`] method on [`IndexedParallelIterator`],
/// see its documentation for more information.
///
/// [`zip_eq`]: trait.IndexedParallelIterator.html#method.zip_eq
/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct ZipEq<A: IndexedParallelIterator, B: IndexedParallelIterator> {
    zip: Zip<A, B>
}

/// Create a new `ZipEq` iterator.
///
/// NB: a free fn because it is NOT part of the end-user API.
#[inline]
pub fn new<A, B>(a: A, b: B) -> ZipEq<A, B>
    where A: IndexedParallelIterator,
          B: IndexedParallelIterator
{
    ZipEq { zip: super::zip::new(a, b) }
}

impl<A, B> ParallelIterator for ZipEq<A, B>
    where A: IndexedParallelIterator,
          B: IndexedParallelIterator
{
    type Item = (A::Item, B::Item);

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge(self.zip, consumer)
    }

    fn opt_len(&mut self) -> Option<usize> {
        Some(self.zip.len())
    }
}

impl<A, B> IndexedParallelIterator for ZipEq<A, B>
    where A: IndexedParallelIterator,
          B: IndexedParallelIterator
{
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        bridge(self.zip, consumer)
    }

    fn len(&mut self) -> usize {
        self.zip.len()
    }

    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        self.zip.with_producer(callback)
    }
}
<|endoftext|>


<commit_before>use errno;
use libc;
use region;
use std::mem;
use std::ptr;

/// Round `size` up to the nearest multiple of `page_size`.
fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
    (size + (page_size - 1)) & !(page_size - 1)
}

/// A simple struct consisting of a pointer and length.
struct PtrLen {
    ptr: *mut u8,
    len: usize,
}

impl PtrLen {
    /// Create a new empty `PtrLen`.
    fn new() -> Self {
        Self {
            ptr: ptr::null_mut(),
            len: 0,
        }
    }

    /// Create a new `PtrLen` pointing to at least `size` bytes of memory,
    /// suitably sized and aligned for memory protection.
    #[cfg(not(target_os = "windows"))]
    fn with_size(size: usize) -> Result<Self, String> {
        let page_size = region::page::size();
        let alloc_size = round_up_to_page_size(size, page_size);
        unsafe {
            let mut ptr: *mut libc::c_void = mem::uninitialized();
            let err = libc::posix_memalign(&mut ptr, page_size, alloc_size);
            if err == 0 {
                Ok(Self {
                    ptr: ptr as *mut u8,
                    len: alloc_size,
                })
            } else {
                Err(errno::Errno(err).to_string())
            }
        }
    }

    #[cfg(target_os = "windows")]
    fn with_size(size: usize) -> Result<Self, String> {
        use winapi::um::memoryapi::VirtualAlloc;
        use winapi::um::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_READWRITE};

        let page_size = region::page::size();

        // VirtualAlloc always rounds up to the next multiple of the page size
        let ptr = unsafe {
            VirtualAlloc(
                ptr::null_mut(),
                size,
                MEM_COMMIT | MEM_RESERVE,
                PAGE_READWRITE,
            )
        };
        if !ptr.is_null() {
            Ok(Self {
                ptr: ptr as *mut u8,
                len: round_up_to_page_size(size, page_size),
            })
        } else {
            Err(errno::errno().to_string())
        }
    }
}

/// JIT memory manager. This manages pages of suitably aligned and
/// accessible memory.
pub struct Memory {
    allocations: Vec<PtrLen>,
    executable: usize,
    current: PtrLen,
    position: usize,
}

impl Memory {
    pub fn new() -> Self {
        Self {
            allocations: Vec::new(),
            executable: 0,
            current: PtrLen::new(),
            position: 0,
        }
    }

    fn finish_current(&mut self) {
        self.allocations
            .push(mem::replace(&mut self.current, PtrLen::new()));
        self.position = 0;
    }

    /// TODO: Use a proper error type.
    pub fn allocate(&mut self, size: usize, align: u8) -> Result<*mut u8, String> {
        if self.position % align as usize != 0 {
            self.position += align as usize - self.position % align as usize;
            debug_assert!(self.position % align as usize == 0);
        }

        if size <= self.current.len - self.position {
            // TODO: Ensure overflow is not possible.
            let ptr = unsafe { self.current.ptr.add(self.position) };
            self.position += size;
            return Ok(ptr);
        }

        self.finish_current();

        // TODO: Allocate more at a time.
        self.current = PtrLen::with_size(size)?;
        self.position = size;
        Ok(self.current.ptr)
    }

    /// Set all memory allocated in this `Memory` up to now as readable and executable.
    pub fn set_readable_and_executable(&mut self) {
        self.finish_current();

        for &PtrLen { ptr, len } in &self.allocations[self.executable..] {
            if len != 0 {
                unsafe {
                    region::protect(ptr, len, region::Protection::ReadExecute)
                        .expect("unable to make memory readable+executable");
                }
            }
        }
    }

    /// Set all memory allocated in this `Memory` up to now as readonly.
    pub fn set_readonly(&mut self) {
        self.finish_current();

        for &PtrLen { ptr, len } in &self.allocations[self.executable..] {
            if len != 0 {
                unsafe {
                    region::protect(ptr, len, region::Protection::Read)
                        .expect("unable to make memory readonly");
                }
            }
        }
    }
}

// TODO: Implement Drop to unprotect and deallocate the memory?

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

    #[test]
    fn test_round_up_to_page_size() {
        assert_eq!(round_up_to_page_size(0, 4096), 0);
        assert_eq!(round_up_to_page_size(1, 4096), 4096);
        assert_eq!(round_up_to_page_size(4096, 4096), 4096);
        assert_eq!(round_up_to_page_size(4097, 4096), 8192);
    }
}
<commit_msg>Fix mem::uninitialized depricated since 1.38<commit_after>use errno;
use libc;
use region;
use std::mem;
use std::ptr;

/// Round `size` up to the nearest multiple of `page_size`.
fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
    (size + (page_size - 1)) & !(page_size - 1)
}

/// A simple struct consisting of a pointer and length.
struct PtrLen {
    ptr: *mut u8,
    len: usize,
}

impl PtrLen {
    /// Create a new empty `PtrLen`.
    fn new() -> Self {
        Self {
            ptr: ptr::null_mut(),
            len: 0,
        }
    }

    /// Create a new `PtrLen` pointing to at least `size` bytes of memory,
    /// suitably sized and aligned for memory protection.
    #[cfg(not(target_os = "windows"))]
    fn with_size(size: usize) -> Result<Self, String> {
        let mut ptr = ptr::null_mut();
        let page_size = region::page::size();
        let alloc_size = round_up_to_page_size(size, page_size);
        unsafe {
            let err = libc::posix_memalign(&mut ptr, page_size, alloc_size);
            if err == 0 {
                Ok(Self {
                    ptr: ptr as *mut u8,
                    len: alloc_size,
                })
            } else {
                Err(errno::Errno(err).to_string())
            }
        }
    }

    #[cfg(target_os = "windows")]
    fn with_size(size: usize) -> Result<Self, String> {
        use winapi::um::memoryapi::VirtualAlloc;
        use winapi::um::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_READWRITE};

        let page_size = region::page::size();

        // VirtualAlloc always rounds up to the next multiple of the page size
        let ptr = unsafe {
            VirtualAlloc(
                ptr::null_mut(),
                size,
                MEM_COMMIT | MEM_RESERVE,
                PAGE_READWRITE,
            )
        };
        if !ptr.is_null() {
            Ok(Self {
                ptr: ptr as *mut u8,
                len: round_up_to_page_size(size, page_size),
            })
        } else {
            Err(errno::errno().to_string())
        }
    }
}

/// JIT memory manager. This manages pages of suitably aligned and
/// accessible memory.
pub struct Memory {
    allocations: Vec<PtrLen>,
    executable: usize,
    current: PtrLen,
    position: usize,
}

impl Memory {
    pub fn new() -> Self {
        Self {
            allocations: Vec::new(),
            executable: 0,
            current: PtrLen::new(),
            position: 0,
        }
    }

    fn finish_current(&mut self) {
        self.allocations
            .push(mem::replace(&mut self.current, PtrLen::new()));
        self.position = 0;
    }

    /// TODO: Use a proper error type.
    pub fn allocate(&mut self, size: usize, align: u8) -> Result<*mut u8, String> {
        if self.position % align as usize != 0 {
            self.position += align as usize - self.position % align as usize;
            debug_assert!(self.position % align as usize == 0);
        }

        if size <= self.current.len - self.position {
            // TODO: Ensure overflow is not possible.
            let ptr = unsafe { self.current.ptr.add(self.position) };
            self.position += size;
            return Ok(ptr);
        }

        self.finish_current();

        // TODO: Allocate more at a time.
        self.current = PtrLen::with_size(size)?;
        self.position = size;
        Ok(self.current.ptr)
    }

    /// Set all memory allocated in this `Memory` up to now as readable and executable.
    pub fn set_readable_and_executable(&mut self) {
        self.finish_current();

        for &PtrLen { ptr, len } in &self.allocations[self.executable..] {
            if len != 0 {
                unsafe {
                    region::protect(ptr, len, region::Protection::ReadExecute)
                        .expect("unable to make memory readable+executable");
                }
            }
        }
    }

    /// Set all memory allocated in this `Memory` up to now as readonly.
    pub fn set_readonly(&mut self) {
        self.finish_current();

        for &PtrLen { ptr, len } in &self.allocations[self.executable..] {
            if len != 0 {
                unsafe {
                    region::protect(ptr, len, region::Protection::Read)
                        .expect("unable to make memory readonly");
                }
            }
        }
    }
}

// TODO: Implement Drop to unprotect and deallocate the memory?

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

    #[test]
    fn test_round_up_to_page_size() {
        assert_eq!(round_up_to_page_size(0, 4096), 0);
        assert_eq!(round_up_to_page_size(1, 4096), 4096);
        assert_eq!(round_up_to_page_size(4096, 4096), 4096);
        assert_eq!(round_up_to_page_size(4097, 4096), 8192);
    }
}
<|endoftext|>


<commit_before>use ::cairo;
use ::glib_sys;
use ::glib;

use glib::translate::*;
use cairo::MatrixTrait;

/* Keep this in sync with ../../rsvg-private.h:RsvgBbox */
#[repr(C)]
pub struct RsvgBbox {
    pub rect:   cairo::Rectangle,
    pub affine: cairo::Matrix,
    virgin:     glib_sys::gboolean
}

impl RsvgBbox {
    pub fn is_virgin (&self) -> bool {
        from_glib (self.virgin)
    }
}

#[no_mangle]
pub extern fn rsvg_bbox_init (raw_bbox: *mut RsvgBbox, raw_matrix: *const cairo::Matrix) {
    assert! (!raw_bbox.is_null ());
    assert! (!raw_matrix.is_null ());

    let bbox: &mut RsvgBbox = unsafe { &mut (*raw_bbox) };

    bbox.virgin = true.to_glib ();
    bbox.affine = unsafe { *raw_matrix };
}

#[no_mangle]
pub extern fn rsvg_bbox_insert (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox) {
    assert! (!raw_dst.is_null ());
    assert! (!raw_src.is_null ());

    let dst: &mut RsvgBbox = unsafe { &mut (*raw_dst) };
    let src: &RsvgBbox = unsafe { &*raw_src };

    if src.is_virgin () {
        return;
    }

    let mut xmin: f64;
    let mut ymin: f64;
    let mut xmax: f64;
    let mut ymax: f64;

    if !dst.is_virgin () {
        xmin = dst.rect.x;
        ymin = dst.rect.y;
        xmax = dst.rect.x + dst.rect.width;
        ymax = dst.rect.y + dst.rect.height;
    } else {
        xmin = 0.0;
        ymin = 0.0;
        xmax = 0.0;
        ymax = 0.0;
    }

    let mut affine = dst.affine;

    affine.invert (); // this will panic!() if it's not invertible... should we check on our own?
    affine = cairo::Matrix::multiply (&src.affine, &affine);

    /* This is a trick.  We want to transform each of the corners of
     * the rectangle defined by src.rect with the affine
     * transformation, and get the bounding box of all the four
     * resulting points.  The modulus and division accomplish this by
     * running through all the combinations of adding or not adding
     * the width/height to the first point src.rect.(x, y).
     */
    for i in 0..4 {
        let rx: f64 = src.rect.x + src.rect.width * (i % 2) as f64;
        let ry: f64 = src.rect.y + src.rect.height * (i / 2) as f64;
        let x: f64  = affine.xx * rx + affine.xy * ry + affine.x0;
        let y: f64  = affine.yx * rx + affine.yy * ry + affine.y0;

        if dst.is_virgin () {
            xmin = x;
            xmax = x;
            ymin = y;
            ymax = y;
            dst.virgin = false.to_glib ();
        } else {
            if x < xmin { xmin = x; }
            if x > xmax { xmax = x; }
            if y < ymin { ymin = y; }
            if y > ymax { ymax = y; }
        }
    }

    dst.rect.x = xmin;
    dst.rect.y = ymin;
    dst.rect.width = xmax - xmin;
    dst.rect.height = ymax - ymin;
}

#[no_mangle]
pub extern fn rsvg_bbox_clip (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox) {
    assert! (!raw_dst.is_null ());
    assert! (!raw_src.is_null ());

    let dst: &mut RsvgBbox = unsafe { &mut (*raw_dst) };
    let src: &RsvgBbox = unsafe { &*raw_src };

    if src.is_virgin () {
        return;
    }

    let mut xmin: f64;
    let mut ymin: f64;
    let mut xmax: f64;
    let mut ymax: f64;

    if !dst.is_virgin () {
        xmin = dst.rect.x + dst.rect.width;
        ymin = dst.rect.y + dst.rect.height;
        xmax = dst.rect.x;
        ymax = dst.rect.y;
    } else {
        xmin = 0.0;
        ymin = 0.0;
        xmax = 0.0;
        ymax = 0.0;
    }

    let mut affine = dst.affine;

    affine.invert ();
    affine = cairo::Matrix::multiply (&src.affine, &affine);

    /* This is a trick.  See rsvg_bbox_insert() for a description of how it works. */
    for i in 0..4 {
        let rx: f64 = src.rect.x + src.rect.width * (i % 2) as f64;
        let ry: f64 = src.rect.y + src.rect.height * (i / 2) as f64;
        let x = affine.xx * rx + affine.xy * ry + affine.x0;
        let y = affine.yx * rx + affine.yy * ry + affine.y0;

        if dst.is_virgin () {
            xmin = x;
            xmax = x;
            ymin = y;
            ymax = y;
            dst.virgin = false.to_glib ();
        } else {
            if x < xmin { xmin = x; }
            if x > xmax { xmax = x; }
            if y < ymin { ymin = y; }
            if y > ymax { ymax = y; }
        }
    }

    if xmin < dst.rect.x { xmin = dst.rect.x; }
    if ymin < dst.rect.y { ymin = dst.rect.y; }

    if xmax > dst.rect.x + dst.rect.width { xmax = dst.rect.x + dst.rect.width; }
    if ymax > dst.rect.y + dst.rect.height { ymax = dst.rect.y + dst.rect.height; }

    dst.rect.x = xmin;
    dst.rect.width = xmax - xmin;
    dst.rect.y = ymin;
    dst.rect.height = ymax - ymin;
}
<commit_msg>Remove unused imports<commit_after>use ::cairo;
use ::glib_sys;

use glib::translate::*;
use cairo::MatrixTrait;

/* Keep this in sync with ../../rsvg-private.h:RsvgBbox */
#[repr(C)]
pub struct RsvgBbox {
    pub rect:   cairo::Rectangle,
    pub affine: cairo::Matrix,
    virgin:     glib_sys::gboolean
}

impl RsvgBbox {
    pub fn is_virgin (&self) -> bool {
        from_glib (self.virgin)
    }
}

#[no_mangle]
pub extern fn rsvg_bbox_init (raw_bbox: *mut RsvgBbox, raw_matrix: *const cairo::Matrix) {
    assert! (!raw_bbox.is_null ());
    assert! (!raw_matrix.is_null ());

    let bbox: &mut RsvgBbox = unsafe { &mut (*raw_bbox) };

    bbox.virgin = true.to_glib ();
    bbox.affine = unsafe { *raw_matrix };
}

#[no_mangle]
pub extern fn rsvg_bbox_insert (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox) {
    assert! (!raw_dst.is_null ());
    assert! (!raw_src.is_null ());

    let dst: &mut RsvgBbox = unsafe { &mut (*raw_dst) };
    let src: &RsvgBbox = unsafe { &*raw_src };

    if src.is_virgin () {
        return;
    }

    let mut xmin: f64;
    let mut ymin: f64;
    let mut xmax: f64;
    let mut ymax: f64;

    if !dst.is_virgin () {
        xmin = dst.rect.x;
        ymin = dst.rect.y;
        xmax = dst.rect.x + dst.rect.width;
        ymax = dst.rect.y + dst.rect.height;
    } else {
        xmin = 0.0;
        ymin = 0.0;
        xmax = 0.0;
        ymax = 0.0;
    }

    let mut affine = dst.affine;

    affine.invert (); // this will panic!() if it's not invertible... should we check on our own?
    affine = cairo::Matrix::multiply (&src.affine, &affine);

    /* This is a trick.  We want to transform each of the corners of
     * the rectangle defined by src.rect with the affine
     * transformation, and get the bounding box of all the four
     * resulting points.  The modulus and division accomplish this by
     * running through all the combinations of adding or not adding
     * the width/height to the first point src.rect.(x, y).
     */
    for i in 0..4 {
        let rx: f64 = src.rect.x + src.rect.width * (i % 2) as f64;
        let ry: f64 = src.rect.y + src.rect.height * (i / 2) as f64;
        let x: f64  = affine.xx * rx + affine.xy * ry + affine.x0;
        let y: f64  = affine.yx * rx + affine.yy * ry + affine.y0;

        if dst.is_virgin () {
            xmin = x;
            xmax = x;
            ymin = y;
            ymax = y;
            dst.virgin = false.to_glib ();
        } else {
            if x < xmin { xmin = x; }
            if x > xmax { xmax = x; }
            if y < ymin { ymin = y; }
            if y > ymax { ymax = y; }
        }
    }

    dst.rect.x = xmin;
    dst.rect.y = ymin;
    dst.rect.width = xmax - xmin;
    dst.rect.height = ymax - ymin;
}

#[no_mangle]
pub extern fn rsvg_bbox_clip (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox) {
    assert! (!raw_dst.is_null ());
    assert! (!raw_src.is_null ());

    let dst: &mut RsvgBbox = unsafe { &mut (*raw_dst) };
    let src: &RsvgBbox = unsafe { &*raw_src };

    if src.is_virgin () {
        return;
    }

    let mut xmin: f64;
    let mut ymin: f64;
    let mut xmax: f64;
    let mut ymax: f64;

    if !dst.is_virgin () {
        xmin = dst.rect.x + dst.rect.width;
        ymin = dst.rect.y + dst.rect.height;
        xmax = dst.rect.x;
        ymax = dst.rect.y;
    } else {
        xmin = 0.0;
        ymin = 0.0;
        xmax = 0.0;
        ymax = 0.0;
    }

    let mut affine = dst.affine;

    affine.invert ();
    affine = cairo::Matrix::multiply (&src.affine, &affine);

    /* This is a trick.  See rsvg_bbox_insert() for a description of how it works. */
    for i in 0..4 {
        let rx: f64 = src.rect.x + src.rect.width * (i % 2) as f64;
        let ry: f64 = src.rect.y + src.rect.height * (i / 2) as f64;
        let x = affine.xx * rx + affine.xy * ry + affine.x0;
        let y = affine.yx * rx + affine.yy * ry + affine.y0;

        if dst.is_virgin () {
            xmin = x;
            xmax = x;
            ymin = y;
            ymax = y;
            dst.virgin = false.to_glib ();
        } else {
            if x < xmin { xmin = x; }
            if x > xmax { xmax = x; }
            if y < ymin { ymin = y; }
            if y > ymax { ymax = y; }
        }
    }

    if xmin < dst.rect.x { xmin = dst.rect.x; }
    if ymin < dst.rect.y { ymin = dst.rect.y; }

    if xmax > dst.rect.x + dst.rect.width { xmax = dst.rect.x + dst.rect.width; }
    if ymax > dst.rect.y + dst.rect.height { ymax = dst.rect.y + dst.rect.height; }

    dst.rect.x = xmin;
    dst.rect.width = xmax - xmin;
    dst.rect.y = ymin;
    dst.rect.height = ymax - ymin;
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;

pub fn main() {
    let stdin = io::stdin();
    let mut part1 = 0;
    let mut part2 = 0;
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        let split = line.split("x");
        let mut nums = split.map(|s| s.parse().unwrap()).collect::<Vec<i32>>();
        nums.sort();
        let area1 = nums[0] * nums[1];
        let area2 = nums[0] * nums[2];
        let area3 = nums[1] * nums[2];
        part1 += area1 * 2 + area2 * 2 + area3 * 2 + area1;
        part2 += nums[0] * 2 + nums[1] * 2 + nums[0] * nums[1] * nums[2];
    }
    println!("Part1: {}", part1);
    println!("Part2: {}", part2);
}
<commit_msg>create a test for rust day2<commit_after>use std::io;
use std::io::prelude::*;

fn day2<R> (input: R) -> (i32, i32)
    where R: BufRead
{
    let mut part1 = 0;
    let mut part2 = 0;
    for line in input.lines() {
        let line = line.unwrap();
        let split = line.split("x");
        let mut nums = split.map(|s| s.parse().unwrap()).collect::<Vec<i32>>();
        nums.sort();
        let area1 = nums[0] * nums[1];
        let area2 = nums[0] * nums[2];
        let area3 = nums[1] * nums[2];
        part1 += area1 * 2 + area2 * 2 + area3 * 2 + area1;
        part2 += nums[0] * 2 + nums[1] * 2 + nums[0] * nums[1] * nums[2];
    }
    (part1, part2)
}

pub fn main() {
    let stdin = io::stdin();
    let (part1, part2) = day2(stdin.lock());
    println!("Part1: {}", part1);
    println!("Part2: {}", part2);
}

#[test]
fn test() {
    use std::fs::File;
    use std::io::BufReader;
    let f = File::open("../puzzles/day02/input.txt").unwrap();
    let (part1, part2) = day2(BufReader::new(f));
    assert_eq!(part1, 1598415);
    assert_eq!(part2, 3812909);
}
<|endoftext|>


<commit_before>use super::IsMessage;
use super::response::CoAPResponse;
use super::packet::{CoAPOption, Packet};
use super::header::{Header, MessageClass};
use std::net::SocketAddr;
use std::str;

pub use super::header::RequestType as Method;

#[derive(Clone, Debug)]
pub struct CoAPRequest {
    pub message: Packet,
    pub response: Option<CoAPResponse>,
    pub source: Option<SocketAddr>,
}

impl CoAPRequest {
    pub fn new() -> CoAPRequest {
        CoAPRequest {
            response: None,
            message: Packet::new(),
            source: None,
        }
    }

    pub fn from_packet(packet: Packet, source: &SocketAddr) -> CoAPRequest {
        CoAPRequest {
            response: CoAPResponse::new(&packet),
            message: packet,
            source: Some(source.clone()),
        }
    }

    pub fn set_method(&mut self, method: Method) {
        self.message.header.code = MessageClass::Request(method);
    }

    pub fn get_method(&self) -> &Method {
        match self.message.header.code {
            MessageClass::Request(Method::Get) => &Method::Get,
            MessageClass::Request(Method::Post) => &Method::Post,
            MessageClass::Request(Method::Put) => &Method::Put,
            MessageClass::Request(Method::Delete) => &Method::Delete,
            _ => &Method::UnKnown,
        }
    }

    pub fn set_path(&mut self, path: &str) {
        self.clear_option(CoAPOption::UriPath);

        let segs = path.split("/");
        for s in segs {
            if s.len() == 0 {
                continue;
            }

            self.add_option(CoAPOption::UriPath, s.as_bytes().to_vec());
        }
    }

    pub fn get_path(&self) -> String {
        match self.get_option(CoAPOption::UriPath) {
            Some(options) => {
                let mut vec = Vec::new();
                for option in options.iter() {
                    if let Ok(seg) = str::from_utf8(option) {
                        vec.push(seg);
                    }
                }
                vec.join("/")
            }
            _ => "".to_string(),
        }
    }
}

impl IsMessage for CoAPRequest {
    fn get_message(&self) -> &Packet {
        &self.message
    }
    fn get_mut_message(&mut self) -> &mut Packet {
        &mut self.message
    }
    fn get_header(&self) -> &Header {
        &self.message.header
    }
    fn get_mut_header(&mut self) -> &mut Header {
        &mut self.message.header
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::packet::{CoAPOption, Packet};
    use super::super::header::MessageType;
    use super::IsMessage;
    use std::net::SocketAddr;
    use std::str::FromStr;

    #[test]
    fn test_request_create() {

        let mut packet = Packet::new();
        let mut request1 = CoAPRequest::new();

        packet.set_token(vec![0x17, 0x38]);
        request1.set_token(vec![0x17, 0x38]);

        packet.add_option(CoAPOption::UriPath, b"test-interface".to_vec());
        request1.add_option(CoAPOption::UriPath, b"test-interface".to_vec());

        packet.header.set_message_id(42);
        request1.set_message_id(42);

        packet.header.set_version(2);
        request1.set_version(2);

        packet.header.set_type(MessageType::Confirmable);
        request1.set_type(MessageType::Confirmable);

        packet.header.set_code("0.04");
        request1.set_code("0.04");

        let request2 =
            CoAPRequest::from_packet(packet, &SocketAddr::from_str("127.0.0.1:1234").unwrap());

        assert_eq!(
            request1.message.to_bytes().unwrap(),
            request2.message.to_bytes().unwrap()
        );
    }

    #[test]
    fn test_method() {
        let mut request = CoAPRequest::new();

        request.set_code("0.01");
        assert_eq!(&Method::Get, request.get_method());

        request.set_code("0.02");
        assert_eq!(&Method::Post, request.get_method());

        request.set_code("0.03");
        assert_eq!(&Method::Put, request.get_method());

        request.set_code("0.04");
        assert_eq!(&Method::Delete, request.get_method());

        request.set_method(Method::Get);
        assert_eq!("0.01", request.get_code());

        request.set_method(Method::Post);
        assert_eq!("0.02", request.get_code());

        request.set_method(Method::Put);
        assert_eq!("0.03", request.get_code());

        request.set_method(Method::Delete);
        assert_eq!("0.04", request.get_code());
    }

    #[test]
    fn test_path() {
        let mut request = CoAPRequest::new();

        let path = "test-interface";
        request.add_option(CoAPOption::UriPath, path.as_bytes().to_vec());
        assert_eq!(path, request.get_path());

        let path2 = "test-interface2";
        request.set_path(path2);
        assert_eq!(
            path2.as_bytes().to_vec(),
            *request
                .get_option(CoAPOption::UriPath)
                .unwrap()
                .front()
                .unwrap()
        );

        request.set_path("/test-interface2");
        assert_eq!(
            path2.as_bytes().to_vec(),
            *request
                .get_option(CoAPOption::UriPath)
                .unwrap()
                .front()
                .unwrap()
        );
    }
}
<commit_msg>hold back empty path<commit_after>use super::IsMessage;
use super::response::CoAPResponse;
use super::packet::{CoAPOption, Packet};
use super::header::{Header, MessageClass};
use std::net::SocketAddr;
use std::str;

pub use super::header::RequestType as Method;

#[derive(Clone, Debug)]
pub struct CoAPRequest {
    pub message: Packet,
    pub response: Option<CoAPResponse>,
    pub source: Option<SocketAddr>,
}

impl CoAPRequest {
    pub fn new() -> CoAPRequest {
        CoAPRequest {
            response: None,
            message: Packet::new(),
            source: None,
        }
    }

    pub fn from_packet(packet: Packet, source: &SocketAddr) -> CoAPRequest {
        CoAPRequest {
            response: CoAPResponse::new(&packet),
            message: packet,
            source: Some(source.clone()),
        }
    }

    pub fn set_method(&mut self, method: Method) {
        self.message.header.code = MessageClass::Request(method);
    }

    pub fn get_method(&self) -> &Method {
        match self.message.header.code {
            MessageClass::Request(Method::Get) => &Method::Get,
            MessageClass::Request(Method::Post) => &Method::Post,
            MessageClass::Request(Method::Put) => &Method::Put,
            MessageClass::Request(Method::Delete) => &Method::Delete,
            _ => &Method::UnKnown,
        }
    }

    pub fn set_path(&mut self, path: &str) {
        self.clear_option(CoAPOption::UriPath);

        let segs = path.split("/");
        for (i, s) in segs.enumerate() {
            if i == 0 && s.len() == 0 {
                continue;
            }

            self.add_option(CoAPOption::UriPath, s.as_bytes().to_vec());
        }
    }

    pub fn get_path(&self) -> String {
        match self.get_option(CoAPOption::UriPath) {
            Some(options) => {
                let mut vec = Vec::new();
                for option in options.iter() {
                    if let Ok(seg) = str::from_utf8(option) {
                        vec.push(seg);
                    }
                }
                vec.join("/")
            }
            _ => "".to_string(),
        }
    }
}

impl IsMessage for CoAPRequest {
    fn get_message(&self) -> &Packet {
        &self.message
    }
    fn get_mut_message(&mut self) -> &mut Packet {
        &mut self.message
    }
    fn get_header(&self) -> &Header {
        &self.message.header
    }
    fn get_mut_header(&mut self) -> &mut Header {
        &mut self.message.header
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::packet::{CoAPOption, Packet};
    use super::super::header::MessageType;
    use super::IsMessage;
    use std::net::SocketAddr;
    use std::str::FromStr;

    #[test]
    fn test_request_create() {

        let mut packet = Packet::new();
        let mut request1 = CoAPRequest::new();

        packet.set_token(vec![0x17, 0x38]);
        request1.set_token(vec![0x17, 0x38]);

        packet.add_option(CoAPOption::UriPath, b"test-interface".to_vec());
        request1.add_option(CoAPOption::UriPath, b"test-interface".to_vec());

        packet.header.set_message_id(42);
        request1.set_message_id(42);

        packet.header.set_version(2);
        request1.set_version(2);

        packet.header.set_type(MessageType::Confirmable);
        request1.set_type(MessageType::Confirmable);

        packet.header.set_code("0.04");
        request1.set_code("0.04");

        let request2 =
            CoAPRequest::from_packet(packet, &SocketAddr::from_str("127.0.0.1:1234").unwrap());

        assert_eq!(
            request1.message.to_bytes().unwrap(),
            request2.message.to_bytes().unwrap()
        );
    }

    #[test]
    fn test_method() {
        let mut request = CoAPRequest::new();

        request.set_code("0.01");
        assert_eq!(&Method::Get, request.get_method());

        request.set_code("0.02");
        assert_eq!(&Method::Post, request.get_method());

        request.set_code("0.03");
        assert_eq!(&Method::Put, request.get_method());

        request.set_code("0.04");
        assert_eq!(&Method::Delete, request.get_method());

        request.set_method(Method::Get);
        assert_eq!("0.01", request.get_code());

        request.set_method(Method::Post);
        assert_eq!("0.02", request.get_code());

        request.set_method(Method::Put);
        assert_eq!("0.03", request.get_code());

        request.set_method(Method::Delete);
        assert_eq!("0.04", request.get_code());
    }

    #[test]
    fn test_path() {
        let mut request = CoAPRequest::new();

        let path = "test-interface";
        request.add_option(CoAPOption::UriPath, path.as_bytes().to_vec());
        assert_eq!(path, request.get_path());

        let path2 = "test-interface2";
        request.set_path(path2);
        assert_eq!(
            path2.as_bytes().to_vec(),
            *request
                .get_option(CoAPOption::UriPath)
                .unwrap()
                .front()
                .unwrap()
        );

        request.set_path("/test-interface2");
        assert_eq!(
            path2.as_bytes().to_vec(),
            *request
                .get_option(CoAPOption::UriPath)
                .unwrap()
                .front()
                .unwrap()
        );

        let path3 = "test-interface2/";
        request.set_path(path3);
        assert_eq!(path3, request.get_path());
    }
}
<|endoftext|>


<commit_before>//! A lexer for the Ruby programming language.

use tokenizer::new;
use tokenizer::Tokenizer;
use tokenizer::StateFunction;
use token::Token;
use token::Category;

fn initial_state(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    tokenizer.consume_whitespace();
    match tokenizer.current_char() {
        Some(c) => {
            if tokenizer.starts_with_lexeme("class") {
                tokenizer.tokenize_next(5, Category::Keyword);
                tokenizer.states.push(StateFunction(identifier));
                return Some(StateFunction(whitespace))
            } else if tokenizer.starts_with_lexeme("def") {
                tokenizer.tokenize_next(3, Category::Keyword);
                tokenizer.states.push(StateFunction(method));
                return Some(StateFunction(whitespace))
            } else if tokenizer.starts_with_lexeme("do") {
                tokenizer.tokenize_next(2, Category::Keyword);
                tokenizer.states.push(StateFunction(initial_state));
                return Some(StateFunction(whitespace))
            } else if tokenizer.starts_with_lexeme("end") {
                tokenizer.tokenize_next(3, Category::Keyword);
                return Some(StateFunction(initial_state))
            } else if tokenizer.starts_with_lexeme("true") {
                tokenizer.tokenize_next(4, Category::Boolean);
                return Some(StateFunction(initial_state))
            } else if tokenizer.starts_with_lexeme("false") {
                tokenizer.tokenize_next(5, Category::Boolean);
                return Some(StateFunction(initial_state))
            } else if ['+'].iter().any(|o| *o == c) {
                tokenizer.tokenize_next(1, Category::Operator);
                return Some(StateFunction(initial_state))
            }

            match c {
                '"' => {
                    tokenizer.tokenize(Category::Text);
                    tokenizer.advance();
                    return Some(StateFunction(inside_string));
                },
                '\'' => {
                    tokenizer.tokenize(Category::Text);
                    tokenizer.advance();
                    return Some(StateFunction(inside_single_quote_string));
                },
                ' ' | '\n' => {
                    tokenizer.tokenize(Category::Text);
                    tokenizer.advance();
                    tokenizer.states.push(StateFunction(initial_state));
                    return Some(StateFunction(whitespace));
                },
                '#' => {
                    tokenizer.tokenize(Category::Text);
                    tokenizer.advance();
                    tokenizer.states.push(StateFunction(initial_state));
                    return Some(StateFunction(comment));
                },
                '|' => {
                    tokenizer.tokenize_next(1, Category::Text);
                    tokenizer.states.push(StateFunction(argument));
                    return Some(StateFunction(whitespace));
                },
                '.' => {
                    tokenizer.tokenize_next(1, Category::Text);
                    return Some(StateFunction(initial_state));
                },
                '(' => {
                    tokenizer.tokenize(Category::Call);
                    tokenizer.tokenize_next(1, Category::Text);
                    return Some(StateFunction(argument));
                },
                _ => {
                    tokenizer.advance();

                    if c.is_numeric() {
                        return Some(StateFunction(integer));
                    }
                }
            }

            Some(StateFunction(initial_state))
        }

        None => {
            tokenizer.tokenize(Category::Text);
            None
        }
    }
}

fn inside_string(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                '"' => {
                    tokenizer.advance();
                    tokenizer.tokenize(Category::String);
                    Some(StateFunction(initial_state))
                },
                '\\' => {
                    tokenizer.advance();
                    tokenizer.advance();
                    Some(StateFunction(inside_string))
                }
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(inside_string))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::String);
            None
        }
    }
}

fn inside_single_quote_string(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                '\'' => {
                    tokenizer.advance();
                    tokenizer.tokenize(Category::String);
                    Some(StateFunction(initial_state))
                },
                '\\' => {
                    tokenizer.advance();
                    tokenizer.advance();
                    Some(StateFunction(inside_single_quote_string))
                }
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(inside_single_quote_string))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::String);
            None
        }
    }
}

fn whitespace(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                ' ' | '\n' => {
                    tokenizer.advance();
                    Some(StateFunction(whitespace))
                },
                _ => {
                    tokenizer.tokenize(Category::Whitespace);
                    match tokenizer.states.pop() {
                        Some(state) => Some(state),
                        None => Some(StateFunction(initial_state)),
                    }
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Whitespace);
            None
        }
    }
}

fn argument(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    if tokenizer.starts_with_lexeme("true") {
        tokenizer.tokenize_next(4, Category::Boolean);
        return Some(StateFunction(argument))
    } else if tokenizer.starts_with_lexeme("false") {
        tokenizer.tokenize_next(5, Category::Boolean);
        return Some(StateFunction(argument))
    }

    match tokenizer.current_char() {
        Some(c) => {
            match c {
                ' ' | '\n' => {
                    tokenizer.tokenize(Category::Identifier);
                    tokenizer.states.push(StateFunction(argument));
                    Some(StateFunction(whitespace))
                },
                '|' | ')' => {
                    tokenizer.tokenize(Category::Identifier);
                    tokenizer.tokenize_next(1, Category::Text);
                    Some(StateFunction(initial_state))
                },
                '=' | ',' => {
                    tokenizer.tokenize(Category::Identifier);
                    tokenizer.tokenize_next(1, Category::Text);
                    Some(StateFunction(argument))
                },
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(argument))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Identifier);
            None
        }
    }
}

fn identifier(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                ' ' | '\n' => {
                    tokenizer.tokenize(Category::Identifier);
                    Some(StateFunction(initial_state))
                },
                '|' | ')' | '-' => {
                    tokenizer.tokenize(Category::Identifier);
                    tokenizer.tokenize_next(1, Category::Text);
                    Some(StateFunction(initial_state))
                },
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(identifier))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Identifier);
            None
        }
    }
}

fn method(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                ' ' | '\n' => {
                    tokenizer.tokenize(Category::Method);
                    Some(StateFunction(initial_state))
                },
                '(' => {
                    tokenizer.tokenize(Category::Method);
                    tokenizer.tokenize_next(1, Category::Text);
                    Some(StateFunction(argument))
                },
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(method))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Whitespace);
            None
        }
    }
}

fn comment(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                '\n' => {
                    tokenizer.tokenize(Category::Comment);
                    Some(StateFunction(initial_state))
                },
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(comment))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Whitespace);
            None
        }
    }
}

fn integer(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            if c.is_numeric() {
                tokenizer.advance();
                Some(StateFunction(integer))
            } else {
                tokenizer.tokenize(Category::Integer);
                Some(StateFunction(initial_state))
            }
        }

        None => {
            tokenizer.tokenize(Category::Integer);
            None
        }
    }
}

/// Lexes a Ruby document.
pub fn lex(data: &str) -> Vec<Token> {
    let mut tokenizer = new(data);
    let mut state_function = StateFunction(initial_state);
    loop {
        let StateFunction(actual_function) = state_function;
        match actual_function(&mut tokenizer) {
            Some(f) => state_function = f,
            None => {
                match tokenizer.states.pop() {
                    Some(f) => state_function = f,
                    None => return tokenizer.tokens(),
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::lex;
    use token::Token;
    use token::Category;

    #[test]
    fn it_works() {
        let data = include_str!("../../test_data/ruby.rb");
        let tokens = lex(data);
        let expected_tokens = vec![
            Token{ lexeme: "class".to_string(), category: Category::Keyword },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "Ruby".to_string(), category: Category::Identifier },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "def".to_string(), category: Category::Keyword },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "method".to_string(), category: Category::Method },
            Token{ lexeme: "(".to_string(), category: Category::Text },
            Token{ lexeme: "argument".to_string(), category: Category::Identifier },
            Token{ lexeme: ")".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "# comment".to_string(), category: Category::Comment },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "[".to_string(), category: Category::Text },
            Token{ lexeme: "\"ruby\"".to_string(), category: Category::String },
            Token{ lexeme: "]".to_string(), category: Category::Text },
            Token{ lexeme: ".".to_string(), category: Category::Text },
            Token{ lexeme: "each".to_string(), category: Category::Text },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "do".to_string(), category: Category::Keyword },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "|".to_string(), category: Category::Text },
            Token{ lexeme: "string".to_string(), category: Category::Identifier },
            Token{ lexeme: "|".to_string(), category: Category::Text },
            Token{ lexeme: "\n      ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'string'".to_string(), category: Category::String },
            Token{ lexeme: "\n      ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "method_call".to_string(), category: Category::Call },
            Token{ lexeme: "(".to_string(), category: Category::Text },
            Token{ lexeme: "argument".to_string(), category: Category::Identifier },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "=".to_string(), category: Category::Text },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "false".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "another_argument".to_string(), category: Category::Identifier },
            Token{ lexeme: ")".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "end".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "end".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n".to_string(), category: Category::Whitespace },
            Token{ lexeme: "end".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n".to_string(), category: Category::Whitespace }
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }

    #[test]
    fn it_identifies_integers_and_operators() {
        let data = "123 + 456";
        let tokens = lex(data);
        let expected_tokens = vec![
            Token{ lexeme: "123".to_string(), category: Category::Integer },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "+".to_string(), category: Category::Operator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "456".to_string(), category: Category::Integer },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }
}
<commit_msg>Clean up Ruby lexer's initial_state function. Add if keyword support.<commit_after>//! A lexer for the Ruby programming language.

use tokenizer::new;
use tokenizer::Tokenizer;
use tokenizer::StateFunction;
use token::Token;
use token::Category;

fn initial_state(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    tokenizer.consume_whitespace();

    if tokenizer.starts_with_lexeme("class") {
        tokenizer.tokenize_next(5, Category::Keyword);
        tokenizer.states.push(StateFunction(identifier));
        return Some(StateFunction(whitespace))
    } else if tokenizer.starts_with_lexeme("def") {
        tokenizer.tokenize_next(3, Category::Keyword);
        tokenizer.states.push(StateFunction(method));
        return Some(StateFunction(whitespace))
    } else if tokenizer.starts_with_lexeme("do") {
        tokenizer.tokenize_next(2, Category::Keyword);
        return Some(StateFunction(whitespace))
    } else if tokenizer.starts_with_lexeme("if") {
        tokenizer.tokenize_next(2, Category::Keyword);
        return Some(StateFunction(whitespace))
    } else if tokenizer.starts_with_lexeme("end") {
        tokenizer.tokenize_next(3, Category::Keyword);
        return Some(StateFunction(initial_state))
    } else if tokenizer.starts_with_lexeme("true") {
        tokenizer.tokenize_next(4, Category::Boolean);
        return Some(StateFunction(initial_state))
    } else if tokenizer.starts_with_lexeme("false") {
        tokenizer.tokenize_next(5, Category::Boolean);
        return Some(StateFunction(initial_state))
    }

    match tokenizer.current_char() {
        Some('"') => {
            tokenizer.tokenize(Category::Text);
            tokenizer.advance();
            Some(StateFunction(inside_string))
        },
        Some('\'') => {
            tokenizer.tokenize(Category::Text);
            tokenizer.advance();
            Some(StateFunction(inside_single_quote_string))
        },
        Some('#') => {
            tokenizer.tokenize(Category::Text);
            tokenizer.advance();
            tokenizer.states.push(StateFunction(initial_state));
            Some(StateFunction(comment))
        },
        Some('|') => {
            tokenizer.tokenize_next(1, Category::Text);
            tokenizer.states.push(StateFunction(argument));
            Some(StateFunction(whitespace))
        },
        Some('.') => {
            tokenizer.tokenize_next(1, Category::Text);
            Some(StateFunction(initial_state))
        },
        Some('(') => {
            tokenizer.tokenize(Category::Call);
            tokenizer.tokenize_next(1, Category::Text);
            Some(StateFunction(argument))
        },
        Some('+') => {
            tokenizer.tokenize_next(1, Category::Operator);
            Some(StateFunction(initial_state))
        },
        Some(c) => {
            tokenizer.advance();

            if c.is_numeric() {
                Some(StateFunction(integer))
            } else {
                Some(StateFunction(initial_state))
            }
        }

        None => {
            tokenizer.tokenize(Category::Text);
            None
        }
    }
}

fn inside_string(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                '"' => {
                    tokenizer.advance();
                    tokenizer.tokenize(Category::String);
                    Some(StateFunction(initial_state))
                },
                '\\' => {
                    tokenizer.advance();
                    tokenizer.advance();
                    Some(StateFunction(inside_string))
                }
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(inside_string))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::String);
            None
        }
    }
}

fn inside_single_quote_string(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                '\'' => {
                    tokenizer.advance();
                    tokenizer.tokenize(Category::String);
                    Some(StateFunction(initial_state))
                },
                '\\' => {
                    tokenizer.advance();
                    tokenizer.advance();
                    Some(StateFunction(inside_single_quote_string))
                }
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(inside_single_quote_string))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::String);
            None
        }
    }
}

fn whitespace(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                ' ' | '\n' => {
                    tokenizer.advance();
                    Some(StateFunction(whitespace))
                },
                _ => {
                    tokenizer.tokenize(Category::Whitespace);
                    match tokenizer.states.pop() {
                        Some(state) => Some(state),
                        None => Some(StateFunction(initial_state)),
                    }
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Whitespace);
            None
        }
    }
}

fn argument(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    if tokenizer.starts_with_lexeme("true") {
        tokenizer.tokenize_next(4, Category::Boolean);
        return Some(StateFunction(argument))
    } else if tokenizer.starts_with_lexeme("false") {
        tokenizer.tokenize_next(5, Category::Boolean);
        return Some(StateFunction(argument))
    }

    match tokenizer.current_char() {
        Some(c) => {
            match c {
                ' ' | '\n' => {
                    tokenizer.tokenize(Category::Identifier);
                    tokenizer.states.push(StateFunction(argument));
                    Some(StateFunction(whitespace))
                },
                '|' | ')' => {
                    tokenizer.tokenize(Category::Identifier);
                    tokenizer.tokenize_next(1, Category::Text);
                    Some(StateFunction(initial_state))
                },
                '=' | ',' => {
                    tokenizer.tokenize(Category::Identifier);
                    tokenizer.tokenize_next(1, Category::Text);
                    Some(StateFunction(argument))
                },
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(argument))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Identifier);
            None
        }
    }
}

fn identifier(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                ' ' | '\n' => {
                    tokenizer.tokenize(Category::Identifier);
                    Some(StateFunction(initial_state))
                },
                '|' | ')' | '-' => {
                    tokenizer.tokenize(Category::Identifier);
                    tokenizer.tokenize_next(1, Category::Text);
                    Some(StateFunction(initial_state))
                },
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(identifier))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Identifier);
            None
        }
    }
}

fn method(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                ' ' | '\n' => {
                    tokenizer.tokenize(Category::Method);
                    Some(StateFunction(initial_state))
                },
                '(' => {
                    tokenizer.tokenize(Category::Method);
                    tokenizer.tokenize_next(1, Category::Text);
                    Some(StateFunction(argument))
                },
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(method))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Whitespace);
            None
        }
    }
}

fn comment(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            match c {
                '\n' => {
                    tokenizer.tokenize(Category::Comment);
                    Some(StateFunction(initial_state))
                },
                _ => {
                    tokenizer.advance();
                    Some(StateFunction(comment))
                }
            }
        }

        None => {
            tokenizer.tokenize(Category::Whitespace);
            None
        }
    }
}

fn integer(tokenizer: &mut Tokenizer) -> Option<StateFunction> {
    match tokenizer.current_char() {
        Some(c) => {
            if c.is_numeric() {
                tokenizer.advance();
                Some(StateFunction(integer))
            } else {
                tokenizer.tokenize(Category::Integer);
                Some(StateFunction(initial_state))
            }
        }

        None => {
            tokenizer.tokenize(Category::Integer);
            None
        }
    }
}

/// Lexes a Ruby document.
pub fn lex(data: &str) -> Vec<Token> {
    let mut tokenizer = new(data);
    let mut state_function = StateFunction(initial_state);
    loop {
        let StateFunction(actual_function) = state_function;
        match actual_function(&mut tokenizer) {
            Some(f) => state_function = f,
            None => {
                match tokenizer.states.pop() {
                    Some(f) => state_function = f,
                    None => return tokenizer.tokens(),
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::lex;
    use token::Token;
    use token::Category;

    #[test]
    fn it_works() {
        let data = include_str!("../../test_data/ruby.rb");
        let tokens = lex(data);
        let expected_tokens = vec![
            Token{ lexeme: "class".to_string(), category: Category::Keyword },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "Ruby".to_string(), category: Category::Identifier },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "def".to_string(), category: Category::Keyword },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "method".to_string(), category: Category::Method },
            Token{ lexeme: "(".to_string(), category: Category::Text },
            Token{ lexeme: "argument".to_string(), category: Category::Identifier },
            Token{ lexeme: ")".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "# comment".to_string(), category: Category::Comment },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "[".to_string(), category: Category::Text },
            Token{ lexeme: "\"ruby\"".to_string(), category: Category::String },
            Token{ lexeme: "]".to_string(), category: Category::Text },
            Token{ lexeme: ".".to_string(), category: Category::Text },
            Token{ lexeme: "each".to_string(), category: Category::Text },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "do".to_string(), category: Category::Keyword },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "|".to_string(), category: Category::Text },
            Token{ lexeme: "string".to_string(), category: Category::Identifier },
            Token{ lexeme: "|".to_string(), category: Category::Text },
            Token{ lexeme: "\n      ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'string'".to_string(), category: Category::String },
            Token{ lexeme: "\n      ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "method_call".to_string(), category: Category::Call },
            Token{ lexeme: "(".to_string(), category: Category::Text },
            Token{ lexeme: "argument".to_string(), category: Category::Identifier },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "=".to_string(), category: Category::Text },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "false".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "another_argument".to_string(), category: Category::Identifier },
            Token{ lexeme: ")".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "end".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "end".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n".to_string(), category: Category::Whitespace },
            Token{ lexeme: "end".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n".to_string(), category: Category::Whitespace }
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }

    #[test]
    fn it_identifies_integers_and_operators() {
        let data = "123 + 456";
        let tokens = lex(data);
        let expected_tokens = vec![
            Token{ lexeme: "123".to_string(), category: Category::Integer },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "+".to_string(), category: Category::Operator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "456".to_string(), category: Category::Integer },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }
}
<|endoftext|>