<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use diff;
use std::collections::VecDeque;
use std::io;
use term;
use utils::isatty;

#[derive(Debug, PartialEq)]
pub enum DiffLine {
    Context(String),
    Expected(String),
    Resulting(String),
}

#[derive(Debug, PartialEq)]
pub struct Mismatch {
    pub line_number: u32,
    pub lines: Vec<DiffLine>,
}

impl Mismatch {
    fn new(line_number: u32) -> Mismatch {
        Mismatch {
            line_number: line_number,
            lines: Vec::new(),
        }
    }
}

// Produces a diff between the expected output and actual output of rustfmt.
pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
    let mut line_number = 1;
    let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
    let mut lines_since_mismatch = context_size + 1;
    let mut results = Vec::new();
    let mut mismatch = Mismatch::new(0);

    for result in diff::lines(expected, actual) {
        match result {
            diff::Result::Left(str) => {
                if lines_since_mismatch >= context_size {
                    results.push(mismatch);
                    mismatch = Mismatch::new(line_number - context_queue.len() as u32);
                }

                while let Some(line) = context_queue.pop_front() {
                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
                }

                mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
                lines_since_mismatch = 0;
            }
            diff::Result::Right(str) => {
                if lines_since_mismatch >= context_size {
                    results.push(mismatch);
                    mismatch = Mismatch::new(line_number - context_queue.len() as u32);
                }

                while let Some(line) = context_queue.pop_front() {
                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
                }

                mismatch.lines.push(DiffLine::Expected(str.to_owned()));
                line_number += 1;
                lines_since_mismatch = 0;
            }
            diff::Result::Both(str, _) => {
                if context_queue.len() >= context_size {
                    let _ = context_queue.pop_front();
                }

                if lines_since_mismatch < context_size {
                    mismatch.lines.push(DiffLine::Context(str.to_owned()));
                } else {
                    context_queue.push_back(str);
                }

                line_number += 1;
                lines_since_mismatch += 1;
            }
        }
    }

    results.push(mismatch);
    results.remove(0);

    results
}

pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F)
where
    F: Fn(u32) -> String,
{
    match term::stdout() {
        Some(ref t) if isatty() && t.supports_color() => {
            print_diff_fancy(diff, get_section_title, term::stdout().unwrap())
        }
        _ => print_diff_basic(diff, get_section_title),
    }
}

fn print_diff_fancy<F>(
    diff: Vec<Mismatch>,
    get_section_title: F,
    mut t: Box<term::Terminal<Output = io::Stdout>>,
) where
    F: Fn(u32) -> String,
{
    for mismatch in diff {
        let title = get_section_title(mismatch.line_number);
        writeln!(t, "{}", title).unwrap();

        for line in mismatch.lines {
            match line {
                DiffLine::Context(ref str) => {
                    t.reset().unwrap();
                    writeln!(t, " {}⏎", str).unwrap();
                }
                DiffLine::Expected(ref str) => {
                    t.fg(term::color::GREEN).unwrap();
                    writeln!(t, "+{}⏎", str).unwrap();
                }
                DiffLine::Resulting(ref str) => {
                    t.fg(term::color::RED).unwrap();
                    writeln!(t, "-{}⏎", str).unwrap();
                }
            }
        }
        t.reset().unwrap();
    }
}

pub fn print_diff_basic<F>(diff: Vec<Mismatch>, get_section_title: F)
where
    F: Fn(u32) -> String,
{
    for mismatch in diff {
        let title = get_section_title(mismatch.line_number);
        println!("{}", title);

        for line in mismatch.lines {
            match line {
                DiffLine::Context(ref str) => {
                    println!(" {}⏎", str);
                }
                DiffLine::Expected(ref str) => {
                    println!("+{}⏎", str);
                }
                DiffLine::Resulting(ref str) => {
                    println!("-{}⏎", str);
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::{make_diff,Mismatch};
    use super::DiffLine::*;

    #[test]
    fn diff_simple() {
        let src = "one\ntwo\nthree\nfour\nfive\n";
        let dest= "one\ntwo\ntrois\nfour\nfive\n";
        let diff = make_diff(src, dest, 1);
        assert_eq!(diff, vec![Mismatch { line_number: 2,
                                         lines: vec![
                                             Context("two".into()),
                                             Resulting("three".into()),
                                             Expected("trois".into()),
                                             Context("four".into()),
                                         ] }]);
    }

    #[test]
    fn diff_zerocontext() {
        let src = "one\ntwo\nthree\nfour\nfive\n";
        let dest= "one\ntwo\ntrois\nfour\nfive\n";
        let diff = make_diff(src, dest, 0);
        assert_eq!(diff, vec![Mismatch { line_number: 3,
                                         lines: vec![
                                             Resulting("three".into()),
                                             Expected("trois".into()),
                                         ] }]);
    }
}<commit_msg>Add a test for two nearby chunks (with context).<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use diff;
use std::collections::VecDeque;
use std::io;
use term;
use utils::isatty;

#[derive(Debug, PartialEq)]
pub enum DiffLine {
    Context(String),
    Expected(String),
    Resulting(String),
}

#[derive(Debug, PartialEq)]
pub struct Mismatch {
    pub line_number: u32,
    pub lines: Vec<DiffLine>,
}

impl Mismatch {
    fn new(line_number: u32) -> Mismatch {
        Mismatch {
            line_number: line_number,
            lines: Vec::new(),
        }
    }
}

// Produces a diff between the expected output and actual output of rustfmt.
pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
    let mut line_number = 1;
    let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
    let mut lines_since_mismatch = context_size + 1;
    let mut results = Vec::new();
    let mut mismatch = Mismatch::new(0);

    for result in diff::lines(expected, actual) {
        match result {
            diff::Result::Left(str) => {
                if lines_since_mismatch >= context_size {
                    results.push(mismatch);
                    mismatch = Mismatch::new(line_number - context_queue.len() as u32);
                }

                while let Some(line) = context_queue.pop_front() {
                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
                }

                mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
                lines_since_mismatch = 0;
            }
            diff::Result::Right(str) => {
                if lines_since_mismatch >= context_size {
                    results.push(mismatch);
                    mismatch = Mismatch::new(line_number - context_queue.len() as u32);
                }

                while let Some(line) = context_queue.pop_front() {
                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
                }

                mismatch.lines.push(DiffLine::Expected(str.to_owned()));
                line_number += 1;
                lines_since_mismatch = 0;
            }
            diff::Result::Both(str, _) => {
                if context_queue.len() >= context_size {
                    let _ = context_queue.pop_front();
                }

                if lines_since_mismatch < context_size {
                    mismatch.lines.push(DiffLine::Context(str.to_owned()));
                } else {
                    context_queue.push_back(str);
                }

                line_number += 1;
                lines_since_mismatch += 1;
            }
        }
    }

    results.push(mismatch);
    results.remove(0);

    results
}

pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F)
where
    F: Fn(u32) -> String,
{
    match term::stdout() {
        Some(ref t) if isatty() && t.supports_color() => {
            print_diff_fancy(diff, get_section_title, term::stdout().unwrap())
        }
        _ => print_diff_basic(diff, get_section_title),
    }
}

fn print_diff_fancy<F>(
    diff: Vec<Mismatch>,
    get_section_title: F,
    mut t: Box<term::Terminal<Output = io::Stdout>>,
) where
    F: Fn(u32) -> String,
{
    for mismatch in diff {
        let title = get_section_title(mismatch.line_number);
        writeln!(t, "{}", title).unwrap();

        for line in mismatch.lines {
            match line {
                DiffLine::Context(ref str) => {
                    t.reset().unwrap();
                    writeln!(t, " {}⏎", str).unwrap();
                }
                DiffLine::Expected(ref str) => {
                    t.fg(term::color::GREEN).unwrap();
                    writeln!(t, "+{}⏎", str).unwrap();
                }
                DiffLine::Resulting(ref str) => {
                    t.fg(term::color::RED).unwrap();
                    writeln!(t, "-{}⏎", str).unwrap();
                }
            }
        }
        t.reset().unwrap();
    }
}

pub fn print_diff_basic<F>(diff: Vec<Mismatch>, get_section_title: F)
where
    F: Fn(u32) -> String,
{
    for mismatch in diff {
        let title = get_section_title(mismatch.line_number);
        println!("{}", title);

        for line in mismatch.lines {
            match line {
                DiffLine::Context(ref str) => {
                    println!(" {}⏎", str);
                }
                DiffLine::Expected(ref str) => {
                    println!("+{}⏎", str);
                }
                DiffLine::Resulting(ref str) => {
                    println!("-{}⏎", str);
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::{make_diff,Mismatch};
    use super::DiffLine::*;

    #[test]
    fn diff_simple() {
        let src = "one\ntwo\nthree\nfour\nfive\n";
        let dest= "one\ntwo\ntrois\nfour\nfive\n";
        let diff = make_diff(src, dest, 1);
        assert_eq!(diff, vec![Mismatch { line_number: 2,
                                         lines: vec![
                                             Context("two".into()),
                                             Resulting("three".into()),
                                             Expected("trois".into()),
                                             Context("four".into()),
                                         ] }]);
    }

    #[test]
    fn diff_simple2() {
        let src = "one\ntwo\nthree\nfour\nfive\nsix\nseven\n";
        let dest= "one\ntwo\ntrois\nfour\ncinq\nsix\nseven\n";
        let diff = make_diff(src, dest, 1);
        assert_eq!(diff, vec![Mismatch { line_number: 2,
                                         lines: vec![
                                             Context("two".into()),
                                             Resulting("three".into()),
                                             Expected("trois".into()),
                                             Context("four".into()),
                                         ] },
                              Mismatch { line_number: 5,
                                         lines: vec![
                                             Resulting("five".into()),
                                             Expected("cinq".into()),
                                             Context("six".into()),
                                         ] }]);
    }

    #[test]
    fn diff_zerocontext() {
        let src = "one\ntwo\nthree\nfour\nfive\n";
        let dest= "one\ntwo\ntrois\nfour\nfive\n";
        let diff = make_diff(src, dest, 0);
        assert_eq!(diff, vec![Mismatch { line_number: 3,
                                         lines: vec![
                                             Resulting("three".into()),
                                             Expected("trois".into()),
                                         ] }]);
    }
}<|endoftext|>


<commit_before>use core::sync::atomic::{AtomicUsize, Ordering};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use crate::arch::debug::Writer;
use crate::event;
use crate::scheme::*;
use crate::sync::WaitQueue;
use crate::syscall::flag::{EventFlags, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use crate::syscall::scheme::Scheme;

pub static DEBUG_SCHEME_ID: AtomicSchemeId = AtomicSchemeId::default();

/// Input queue
static INPUT: Once<WaitQueue<u8>> = Once::new();

/// Initialize input queue, called if needed
fn init_input() -> WaitQueue<u8> {
    WaitQueue::new()
}

static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

static HANDLES: Once<RwLock<BTreeMap<usize, usize>>> = Once::new();

fn init_handles() -> RwLock<BTreeMap<usize, usize>> {
    RwLock::new(BTreeMap::new())
}

fn handles() -> RwLockReadGuard<'static, BTreeMap<usize, usize>> {
    HANDLES.call_once(init_handles).read()
}

fn handles_mut() -> RwLockWriteGuard<'static, BTreeMap<usize, usize>> {
    HANDLES.call_once(init_handles).write()
}

/// Add to the input queue
pub fn debug_input(b: u8) {
    INPUT.call_once(init_input).send(b);
    for (id, _flags) in handles().iter() {
        event::trigger(DEBUG_SCHEME_ID.load(Ordering::SeqCst), *id, EVENT_READ);
    }
}

pub struct DebugScheme;

impl DebugScheme {
    pub fn new(scheme_id: SchemeId) -> DebugScheme {
        DEBUG_SCHEME_ID.store(scheme_id, Ordering::SeqCst);
        DebugScheme
    }
}

impl Scheme for DebugScheme {
    fn open(&self, _path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        handles_mut().insert(id, flags & ! O_ACCMODE);

        Ok(id)
    }

    /// Read the file `number` into the `buffer`
    ///
    /// Returns the number of bytes read
    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        INPUT.call_once(init_input)
            .receive_into(buf, flags & O_NONBLOCK != O_NONBLOCK, "DebugScheme::read")
            .ok_or(Error::new(EINTR))
    }

    /// Write the `buffer` to the `file`
    ///
    /// Returns the number of bytes written
    fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Writer::new().write(buf);
        Ok(buf.len())
    }

    fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
        let mut handles = handles_mut();
        if let Some(flags) = handles.get_mut(&id) {
            match cmd {
                F_GETFL => Ok(*flags),
                F_SETFL => {
                    *flags = arg & ! O_ACCMODE;
                    Ok(0)
                },
                _ => Err(Error::new(EINVAL))
            }
        } else {
            Err(Error::new(EBADF))
        }
    }

    fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(EventFlags::empty())
    }

    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let mut i = 0;
        let scheme_path = b"debug:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        Ok(i)
    }

    fn fsync(&self, id: usize) -> Result<usize> {
        let _flags = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }

    /// Close the file `number`
    fn close(&self, id: usize) -> Result<usize> {
        let _flags = {
            let mut handles = handles_mut();
            handles.remove(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }
}
<commit_msg>Cleanup debug scheme<commit_after>use core::sync::atomic::{AtomicUsize, Ordering};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use crate::arch::debug::Writer;
use crate::event;
use crate::scheme::*;
use crate::sync::WaitQueue;
use crate::syscall::flag::{EventFlags, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use crate::syscall::scheme::Scheme;

static SCHEME_ID: AtomicSchemeId = AtomicSchemeId::default();

static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

/// Input queue
static INPUT: Once<WaitQueue<u8>> = Once::new();

/// Initialize input queue, called if needed
fn init_input() -> WaitQueue<u8> {
    WaitQueue::new()
}

#[derive(Clone, Copy)]
struct Handle {
    flags: usize,
}

static HANDLES: Once<RwLock<BTreeMap<usize, Handle>>> = Once::new();

fn init_handles() -> RwLock<BTreeMap<usize, Handle>> {
    RwLock::new(BTreeMap::new())
}

fn handles() -> RwLockReadGuard<'static, BTreeMap<usize, Handle>> {
    HANDLES.call_once(init_handles).read()
}

fn handles_mut() -> RwLockWriteGuard<'static, BTreeMap<usize, Handle>> {
    HANDLES.call_once(init_handles).write()
}

/// Add to the input queue
pub fn debug_input(data: u8) {
    INPUT.call_once(init_input).send(data);
    for (id, _handle) in handles().iter() {
        event::trigger(SCHEME_ID.load(Ordering::SeqCst), *id, EVENT_READ);
    }
}

pub struct DebugScheme;

impl DebugScheme {
    pub fn new(scheme_id: SchemeId) -> Self {
        SCHEME_ID.store(scheme_id, Ordering::SeqCst);
        Self
    }
}

impl Scheme for DebugScheme {
    fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
        if uid != 0 {
            return Err(Error::new(EPERM));
        }

        if ! path.is_empty() {
            return Err(Error::new(ENOENT));
        }

        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        handles_mut().insert(id, Handle {
            flags: flags & ! O_ACCMODE
        });

        Ok(id)
    }

    /// Read the file `number` into the `buffer`
    ///
    /// Returns the number of bytes read
    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        INPUT.call_once(init_input)
            .receive_into(buf, handle.flags & O_NONBLOCK != O_NONBLOCK, "DebugScheme::read")
            .ok_or(Error::new(EINTR))
    }

    /// Write the `buffer` to the `file`
    ///
    /// Returns the number of bytes written
    fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
        let _handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Writer::new().write(buf);
        Ok(buf.len())
    }

    fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
        let mut handles = handles_mut();
        if let Some(handle) = handles.get_mut(&id) {
            match cmd {
                F_GETFL => Ok(handle.flags),
                F_SETFL => {
                    handle.flags = arg & ! O_ACCMODE;
                    Ok(0)
                },
                _ => Err(Error::new(EINVAL))
            }
        } else {
            Err(Error::new(EBADF))
        }
    }

    fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
        let _handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(EventFlags::empty())
    }

    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let _handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let mut i = 0;
        let scheme_path = b"debug:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        Ok(i)
    }

    fn fsync(&self, id: usize) -> Result<usize> {
        let _handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }

    /// Close the file `number`
    fn close(&self, id: usize) -> Result<usize> {
        let _handle = {
            let mut handles = handles_mut();
            handles.remove(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }
}
<|endoftext|>


<commit_before>//! #Receptions
//!
//! A receptions object is a convenient iterator over all RPCs received
//! by a node.
//!
//! By default, iterating over a Receptions object will block indefinitely
//! while waiting for packet arrivals, but it's possible to specify an
//! imprecise timeout so the iterator is only valid for a span of time.
//!
//! It is also possible to filter the iterator so it only applies to particular
//! senders or RPC kinds without resorting to iterator adapters.

use {bus, rpc, time};
use node::resources;
use hash::Hash;

/// A blocking iterator over the RPCs received by a node.
pub struct Receptions {
   iter          : bus::BusIntoIter<resources::Update>,
   timeout       : Option<time::SteadyTime>,
   kind_filter   : Option<KindFilter>,
   sender_filter : Option<Vec<Hash>>,
   shutdown      : bool,
}

#[derive(Eq, PartialEq, Debug)]
pub enum KindFilter {
   Ping,
   PingResponse,
   Store,
   FindNode,
   FindNodeResponse,
   FindValue,
   FindValueResponse,
   Bootstrap,
   BootstrapResponse,
}

impl Receptions {
   pub fn new(resources: &resources::Resources) -> Receptions {
      Receptions {
         iter          : resources.updates.lock().unwrap().add_rx().into_iter(),
         timeout       : None,
         kind_filter    : None,
         sender_filter : None,
         shutdown      : false,
      }
   }

   /// Restricts the iterator to a particular span of time.
   pub fn during(mut self, lifespan: time::Duration) -> Receptions {
      self.timeout = Some(time::SteadyTime::now() + lifespan);
      self
   }

   /// Only produces a particular rpc kind.
   pub fn of_kind(mut self, filter: KindFilter) -> Receptions {
      self.kind_filter = Some(filter);
      self
   }

   /// Only from a sender.
   pub fn from(mut self, sender: Hash) -> Receptions {
      self.sender_filter = Some(vec![sender]);
      self
   }

   /// Only from a set of senders.
   pub fn from_senders(mut self, senders: Vec<Hash>) -> Receptions {
      self.sender_filter = Some(senders);
      self
   }
}

impl Iterator for Receptions {
   type Item = rpc::Rpc;

   fn next(&mut self) -> Option<rpc::Rpc> {
      loop {
         if let Some(timeout) = self.timeout {
            if time::SteadyTime::now() > timeout {
               break;
            }
         }
         if self.shutdown {
            break;
         }

         //if let Some(resources::Update::RpcReceived(rpc)) = self.iter.next() {
         match self.iter.next() {
            Some(resources::Update::RpcReceived(rpc)) => {
               if let Some(ref kind_filter) = self.kind_filter {
                  match rpc.kind {
                     rpc::Kind::Ping                 => if *kind_filter != KindFilter::Ping { continue; },
                     rpc::Kind::PingResponse         => if *kind_filter != KindFilter::PingResponse { continue; },
                     rpc::Kind::Store(_)             => if *kind_filter != KindFilter::Store { continue; },
                     rpc::Kind::FindNode(_)          => if *kind_filter != KindFilter::FindNode { continue; },
                     rpc::Kind::FindNodeResponse(_)  => if *kind_filter != KindFilter::FindNodeResponse { continue; },
                     rpc::Kind::FindValue(_)         => if *kind_filter != KindFilter::FindValue { continue; },
                     rpc::Kind::FindValueResponse(_) => if *kind_filter != KindFilter::FindValueResponse { continue; },
                     rpc::Kind::Bootstrap            => if *kind_filter != KindFilter::Bootstrap { continue; },
                     rpc::Kind::BootstrapResponse(_) => if *kind_filter != KindFilter::BootstrapResponse { continue; },
                  }
               }

               if let Some(ref sender_filter) = self.sender_filter {
                  if !sender_filter.contains(&rpc.sender_id) {
                     continue;
                  }
               }

               return Some(rpc);
            },
            Some(resources::Update::Shutdown) => self.shutdown = true,
            _ => (),
         }
      }
      None
   }
}

#[cfg(test)]
mod tests {
    use node;
    use time;
    use super::KindFilter;

    #[test]
    fn produces_rpcs_but_not_ticks() {
       let alpha = node::Node::new().unwrap();
       let beta = node::Node::new().unwrap();
       let table_size = alpha.bootstrap_until(beta.local_info(), 1).unwrap();

       assert_eq!(table_size, 1);
       let beta_receptions =
          beta.receptions()
              .during(time::Duration::seconds(1))
              .rpc(KindFilter::Ping);

       assert!(alpha.ping(beta.local_info().id).is_ok());
       assert!(alpha.ping(beta.local_info().id).is_ok());

       assert_eq!(beta_receptions.count(),2);
    }

    #[test]
    fn sender_filtering() {
       let receiver = node::Node::new().unwrap();
       let alpha = node::Node::new().unwrap();
       let beta  = node::Node::new().unwrap();

       let mut allowed = Vec::new();
       allowed.push(beta.local_info().id);

       let receptions =
          receiver.receptions()
                  .during(time::Duration::seconds(1))
                  .from_senders(allowed)
                  .rpc(KindFilter::Ping);

       assert!(alpha.bootstrap_until(receiver.local_info(), 1).is_ok());
       assert!(beta.bootstrap_until(receiver.local_info(), 1).is_ok());

       assert!(alpha.ping(receiver.local_info().id).is_ok());
       assert!(beta.ping(receiver.local_info().id).is_ok());

       assert_eq!(receptions.count(),1);
    }
}

<commit_msg>Fixed test<commit_after>//! #Receptions
//!
//! A receptions object is a convenient iterator over all RPCs received
//! by a node.
//!
//! By default, iterating over a Receptions object will block indefinitely
//! while waiting for packet arrivals, but it's possible to specify an
//! imprecise timeout so the iterator is only valid for a span of time.
//!
//! It is also possible to filter the iterator so it only applies to particular
//! senders or RPC kinds without resorting to iterator adapters.

use {bus, rpc, time};
use node::resources;
use hash::Hash;

/// A blocking iterator over the RPCs received by a node.
pub struct Receptions {
   iter          : bus::BusIntoIter<resources::Update>,
   timeout       : Option<time::SteadyTime>,
   kind_filter   : Option<KindFilter>,
   sender_filter : Option<Vec<Hash>>,
   shutdown      : bool,
}

#[derive(Eq, PartialEq, Debug)]
pub enum KindFilter {
   Ping,
   PingResponse,
   Store,
   FindNode,
   FindNodeResponse,
   FindValue,
   FindValueResponse,
   Bootstrap,
   BootstrapResponse,
}

impl Receptions {
   pub fn new(resources: &resources::Resources) -> Receptions {
      Receptions {
         iter          : resources.updates.lock().unwrap().add_rx().into_iter(),
         timeout       : None,
         kind_filter    : None,
         sender_filter : None,
         shutdown      : false,
      }
   }

   /// Restricts the iterator to a particular span of time.
   pub fn during(mut self, lifespan: time::Duration) -> Receptions {
      self.timeout = Some(time::SteadyTime::now() + lifespan);
      self
   }

   /// Only produces a particular rpc kind.
   pub fn of_kind(mut self, filter: KindFilter) -> Receptions {
      self.kind_filter = Some(filter);
      self
   }

   /// Only from a sender.
   pub fn from(mut self, sender: Hash) -> Receptions {
      self.sender_filter = Some(vec![sender]);
      self
   }

   /// Only from a set of senders.
   pub fn from_senders(mut self, senders: Vec<Hash>) -> Receptions {
      self.sender_filter = Some(senders);
      self
   }
}

impl Iterator for Receptions {
   type Item = rpc::Rpc;

   fn next(&mut self) -> Option<rpc::Rpc> {
      loop {
         if let Some(timeout) = self.timeout {
            if time::SteadyTime::now() > timeout {
               break;
            }
         }
         if self.shutdown {
            break;
         }

         //if let Some(resources::Update::RpcReceived(rpc)) = self.iter.next() {
         match self.iter.next() {
            Some(resources::Update::RpcReceived(rpc)) => {
               if let Some(ref kind_filter) = self.kind_filter {
                  match rpc.kind {
                     rpc::Kind::Ping                 => if *kind_filter != KindFilter::Ping { continue; },
                     rpc::Kind::PingResponse         => if *kind_filter != KindFilter::PingResponse { continue; },
                     rpc::Kind::Store(_)             => if *kind_filter != KindFilter::Store { continue; },
                     rpc::Kind::FindNode(_)          => if *kind_filter != KindFilter::FindNode { continue; },
                     rpc::Kind::FindNodeResponse(_)  => if *kind_filter != KindFilter::FindNodeResponse { continue; },
                     rpc::Kind::FindValue(_)         => if *kind_filter != KindFilter::FindValue { continue; },
                     rpc::Kind::FindValueResponse(_) => if *kind_filter != KindFilter::FindValueResponse { continue; },
                     rpc::Kind::Bootstrap            => if *kind_filter != KindFilter::Bootstrap { continue; },
                     rpc::Kind::BootstrapResponse(_) => if *kind_filter != KindFilter::BootstrapResponse { continue; },
                  }
               }

               if let Some(ref sender_filter) = self.sender_filter {
                  if !sender_filter.contains(&rpc.sender_id) {
                     continue;
                  }
               }

               return Some(rpc);
            },
            Some(resources::Update::Shutdown) => self.shutdown = true,
            _ => (),
         }
      }
      None
   }
}

#[cfg(test)]
mod tests {
    use node;
    use time;
    use super::KindFilter;

    #[test]
    fn produces_rpcs_but_not_ticks() {
       let alpha = node::Node::new().unwrap();
       let beta = node::Node::new().unwrap();
       let table_size = alpha.bootstrap_until(beta.local_info(), 1).unwrap();

       assert_eq!(table_size, 1);
       let beta_receptions =
          beta.receptions()
              .during(time::Duration::seconds(1))
              .of_kind(KindFilter::Ping);

       assert!(alpha.ping(beta.local_info().id).is_ok());
       assert!(alpha.ping(beta.local_info().id).is_ok());

       assert_eq!(beta_receptions.count(),2);
    }

    #[test]
    fn sender_filtering() {
       let receiver = node::Node::new().unwrap();
       let alpha = node::Node::new().unwrap();
       let beta  = node::Node::new().unwrap();

       let mut allowed = Vec::new();
       allowed.push(beta.local_info().id);

       let receptions =
          receiver.receptions()
                  .during(time::Duration::seconds(1))
                  .from_senders(allowed)
                  .of_kind(KindFilter::Ping);

       assert!(alpha.bootstrap_until(receiver.local_info(), 1).is_ok());
       assert!(beta.bootstrap_until(receiver.local_info(), 1).is_ok());

       assert!(alpha.ping(receiver.local_info().id).is_ok());
       assert!(beta.ping(receiver.local_info().id).is_ok());

       assert_eq!(receptions.count(),1);
    }
}

<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {

	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        let new_cpu_state = self.execute(cpu_state,mem);
        // Perform logging, recording here...
        *cpu_state = new_cpu_state
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);
        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65535) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65535) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( ((mem.read8(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65535 ) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap())
            },
            AddressMode::IndirectIndexed => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65535) as u16);
            },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( ((mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) % 255) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( ((mem.read8(cpu_state.pc+1).unwrap() + cpu_state.y) % 255) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState, mut mem:&Memory) -> CpuState {

    	// The state of the CPU after executing the current instruction.
    	let mut new_cpu_state = cpu_state.clone();

    	// Figure out which opcode is being executed.
    	let ref decode_register = cpu_state.decode_register;

    	match decode_register.info.opcode_class {

    		// ASL (Arithmetic Shift Left)
    		OpcodeClass::ASL => {

				// Shift accumulator to the left.
				new_cpu_state.a = cpu_state.a << 1;
				// Carry flag gets set to the most significant bit.
				new_cpu_state.C = (128 & cpu_state.a) > 0;
				// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// LDA (Load Accumulator)
    		OpcodeClass::LDA => {
    			new_cpu_state.a = decode_register.value_final.unwrap()
    		},

    		// LDX (Load X)
    		OpcodeClass::LDX => {
    			new_cpu_state.x = decode_register.value_final.unwrap()
    		},

    		// LDY (Load Y)
    		OpcodeClass::LDY => {
    			new_cpu_state.y = decode_register.value_final.unwrap()
    		},

    		// LSR (Logical Shift Right)
    		OpcodeClass::LSR => {

    			// Shift accumulator to the right.
    			new_cpu_state.a = cpu_state.a >> 1;
    			// Carry flag gets set to the least significant bit.
    			new_cpu_state.C = 1 & cpu_state.a > 0;
    			// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// NOP (No Operation)
    		OpcodeClass::NOP => {},

    		// Default: not sure what this opcode is.
			_ => panic!("Unrecognised opcode class: {:?}", decode_register.info.opcode_class)

    	}

    	// Expression returned is the updated cpu_state.
    	new_cpu_state
    }

}

<commit_msg>ZeroPageX/Y addressing modes now cast to u16 and back to u8 correctly<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {

	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        let new_cpu_state = self.execute(cpu_state,mem);
        // Perform logging, recording here...
        *cpu_state = new_cpu_state
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);
        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65535) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65535) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( ((mem.read8(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65535 ) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap())
            },
            AddressMode::IndirectIndexed => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65535) as u16);
            },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 255);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 255);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState, mut mem:&Memory) -> CpuState {

    	// The state of the CPU after executing the current instruction.
    	let mut new_cpu_state = cpu_state.clone();

    	// Figure out which opcode is being executed.
    	let ref decode_register = cpu_state.decode_register;

    	match decode_register.info.opcode_class {

    		// ASL (Arithmetic Shift Left)
    		OpcodeClass::ASL => {

				// Shift accumulator to the left.
				new_cpu_state.a = cpu_state.a << 1;
				// Carry flag gets set to the most significant bit.
				new_cpu_state.C = (128 & cpu_state.a) > 0;
				// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// LDA (Load Accumulator)
    		OpcodeClass::LDA => {
    			new_cpu_state.a = decode_register.value_final.unwrap()
    		},

    		// LDX (Load X)
    		OpcodeClass::LDX => {
    			new_cpu_state.x = decode_register.value_final.unwrap()
    		},

    		// LDY (Load Y)
    		OpcodeClass::LDY => {
    			new_cpu_state.y = decode_register.value_final.unwrap()
    		},

    		// LSR (Logical Shift Right)
    		OpcodeClass::LSR => {

    			// Shift accumulator to the right.
    			new_cpu_state.a = cpu_state.a >> 1;
    			// Carry flag gets set to the least significant bit.
    			new_cpu_state.C = 1 & cpu_state.a > 0;
    			// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// NOP (No Operation)
    		OpcodeClass::NOP => {},

    		// Default: not sure what this opcode is.
			_ => panic!("Unrecognised opcode class: {:?}", decode_register.info.opcode_class)

    	}

    	// Expression returned is the updated cpu_state.
    	new_cpu_state
    }

}

<|endoftext|>


<commit_before>extern mod std;

extern mod crypto {
  fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn MD5(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA224(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA256(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA384(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA512(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
}

enum HashMethod { MD5, SHA1, SHA224, SHA256, SHA384, SHA512 }

struct HashEngine {
  engine:      (extern unsafe fn(*u8, libc::c_uint, *u8) -> *u8),
  digest_size: uint,
  block_size:  uint
}

impl HashEngine {
  fn by_name(engine: HashMethod) -> ~HashEngine {
    unsafe {
      match engine {
        MD5    => ~HashEngine{ engine: crypto::MD5,    digest_size: 16, block_size: 64  },
        SHA1   => ~HashEngine{ engine: crypto::SHA1,   digest_size: 20, block_size: 64  },
        SHA224 => ~HashEngine{ engine: crypto::SHA224, digest_size: 28, block_size: 64  },
        SHA256 => ~HashEngine{ engine: crypto::SHA256, digest_size: 32, block_size: 64  },
        SHA384 => ~HashEngine{ engine: crypto::SHA384, digest_size: 48, block_size: 64  },
        SHA512 => ~HashEngine{ engine: crypto::SHA512, digest_size: 64, block_size: 128 }
      }
    }
  }

  fn hash(&self, data: ~[u8]) -> ~Digest {
    let hash_func = self.engine;
    Digest::new(
      unsafe {
        vec::from_buf(
          hash_func(
            vec::raw::to_ptr(data),
            data.len() as libc::c_uint, ptr::null()
          ),
          self.digest_size
        )
      }
    )
  }
}

struct Digest { digest: ~[u8] }

impl Digest {
  fn new(digest: ~[u8]) -> ~Digest { return ~Digest{ digest: digest } }

  fn hexdigest(&self) -> ~str {
    let mut acc = ~"";
    for self.digest.each |&byte| { acc += fmt!("%02x", byte as uint); }
    acc
  }
}

fn hash(engine_name: HashMethod, data: ~[u8]) -> ~Digest {
  let details   = HashEngine::by_name(engine_name);
  let hash_func = details.engine;

  Digest::new(
    unsafe {
      vec::from_buf(
        hash_func(
          vec::raw::to_ptr(data),
          data.len() as libc::c_uint, ptr::null()
        ),
        details.digest_size
      )
    }
  )
}

fn sha1(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::by_name(SHA1).hash(data)
  }
}

fn sha224(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::by_name(SHA224).hash(data)
  }
}

fn sha256(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::by_name(SHA256).hash(data)
  }
}

fn sha384(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::by_name(SHA384).hash(data)
  }
}

fn sha512(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::by_name(SHA512 ).hash(data)
  }
}

fn md5(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::by_name(MD5).hash(data)
  }
}

fn xor_with(subject: &str, val: u8) -> ~[u8] {
  do subject.to_bytes().map |&c| { val ^ c }
}

fn hmac_md5(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 64, md5)
}

fn hmac_sha1(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 64, sha1)
}

fn hmac_sha256(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 64, sha256)
}

fn hmac_sha512(key: ~str, message: ~str) -> ~Digest {
  hmac(key, message, 128, sha512)
}

fn hmac(key: ~str, message: ~str, block_size: uint, hash_func: &fn(~[u8]) -> ~Digest) -> ~Digest {
  let computed_key: &str = match key.len() {
    _ if key.len() > block_size => hash_func(key.to_bytes()).hexdigest(), // TODO this should be .digest more likely
    _ if key.len() < block_size => key + str::from_bytes(vec::from_elem(block_size - key.len(), 0)),
    _ => key
  };

  let o_key_pad = xor_with(computed_key, 0x5c);
  let i_key_pad = xor_with(computed_key, 0x36);
  let bin_message = message.to_bytes();

  hash_func(o_key_pad + hash_func(i_key_pad + bin_message).digest)
}

fn main() {
  if core::os::args().len() < 2 { fail!(~"Nothing to hash: supply an argument") }
  io::println(sha1(core::os::args()[1].clone().to_bytes()).hexdigest());
}

#[test]
fn test_sha1() {
  assert_eq!(sha1("testing SHA1".to_bytes()).hexdigest(), ~"a07bb2f7f56b7b47e54fd9e29b4629c8967dde4c");
}

#[test]
fn test_md5() {
  assert_eq!(md5("testing MD5".to_bytes()).hexdigest(), ~"da35df95d34f166890fa759f5e00e94c");
}

#[test]
fn test_hmac_sha1() {
  assert_eq!(
    hmac_sha1(~"my key", ~"some data to hmac").hexdigest(),
    ~"331c9bf4d7dc8ad7e9bab2f566c8612042a9f4e2"
  )
}

#[test]
fn test_hmac_sha256() {
  assert_eq!(
    hmac_sha256(~"my key", ~"some data to hmac").hexdigest(),
    ~"17764a8a2e8c23ae3b9e1781c5ebeb5754c7920806021032e9133051e10118be"
  );
}

#[test]
fn test_hmac_sha512() {
  assert_eq!(
    hmac_sha512(~"my key", ~"some data to hmac").hexdigest(),
    ~"b54973feba2e436c4f0911855c80e7320d72edd37b359d6474d714718c52775f163832b79214e9fa9d400208d21372a465b2cda2a1d5ab488bbc02b0daea9626"
  );
}

#[test]
fn test_hmac_md5() {
  assert_eq!(hmac_md5(~"my key", ~"some data to hmac").hexdigest(), ~"befd13e00ee07549520ade402c664a3a");
}
<commit_msg>Refactor HMAC into the HashEngine.<commit_after>extern mod std;

extern mod crypto {
  fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn MD5(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA224(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA256(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA384(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
  fn SHA512(src: *u8, sz: libc::c_uint, out: *u8) -> *u8;
}

enum HashMethod { MD5, SHA1, SHA224, SHA256, SHA384, SHA512 }

struct HashEngine {
  engine:      (extern unsafe fn(*u8, libc::c_uint, *u8) -> *u8),
  digest_size: uint,
  block_size:  uint
}

impl HashEngine {
  fn new(engine: HashMethod) -> ~HashEngine {
    unsafe {
      match engine {
        MD5    => ~HashEngine{ engine: crypto::MD5,    digest_size: 16, block_size: 64  },
        SHA1   => ~HashEngine{ engine: crypto::SHA1,   digest_size: 20, block_size: 64  },
        SHA224 => ~HashEngine{ engine: crypto::SHA224, digest_size: 28, block_size: 64  },
        SHA256 => ~HashEngine{ engine: crypto::SHA256, digest_size: 32, block_size: 64  },
        SHA384 => ~HashEngine{ engine: crypto::SHA384, digest_size: 48, block_size: 64  },
        SHA512 => ~HashEngine{ engine: crypto::SHA512, digest_size: 64, block_size: 128 }
      }
    }
  }

  fn hash(&self, data: ~[u8]) -> ~Digest {
    let hash_func = self.engine;
    Digest::new(
      unsafe {
        vec::from_buf(
          hash_func(
            vec::raw::to_ptr(data),
            data.len() as libc::c_uint, ptr::null()
          ),
          self.digest_size
        )
      }
    )
  }

  fn hmac(&self, key: ~str, message: ~str) -> ~Digest {
    let computed_key: &str = match key.len() {
      _ if key.len() > self.block_size => self.hash(key.to_bytes()).hexdigest(), // TODO this should be .digest more likely
      _ if key.len() < self.block_size => key + str::from_bytes(vec::from_elem(self.block_size - key.len(), 0)),
      _ => key
    };

    let o_key_pad = HashEngine::xor_with(computed_key, 0x5c);
    let i_key_pad = HashEngine::xor_with(computed_key, 0x36);
    let bytes = message.to_bytes();

    self.hash(o_key_pad + self.hash(i_key_pad + bytes).digest)
  }

  priv fn xor_with(subject: &str, val: u8) -> ~[u8] {
    do subject.to_bytes().map |&c| { val ^ c }
  }
}

struct Digest { digest: ~[u8] }

impl Digest {
  fn new(digest: ~[u8]) -> ~Digest { return ~Digest{ digest: digest } }

  fn hexdigest(&self) -> ~str {
    let mut acc = ~"";
    for self.digest.each |&byte| { acc += fmt!("%02x", byte as uint); }
    acc
  }
}

fn sha1(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::new(SHA1).hash(data)
  }
}

fn sha224(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::new(SHA224).hash(data)
  }
}

fn sha256(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::new(SHA256).hash(data)
  }
}

fn sha384(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::new(SHA384).hash(data)
  }
}

fn sha512(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::new(SHA512).hash(data)
  }
}

fn md5(data: ~[u8]) -> ~Digest {
  unsafe {
    HashEngine::new(MD5).hash(data)
  }
}

fn hmac_md5(key: ~str, message: ~str) -> ~Digest {
  HashEngine::new(MD5).hmac(key, message)
}

fn hmac_sha1(key: ~str, message: ~str) -> ~Digest {
  HashEngine::new(SHA1).hmac(key, message)
}

fn hmac_sha256(key: ~str, message: ~str) -> ~Digest {
  HashEngine::new(SHA256).hmac(key, message)
}

fn hmac_sha512(key: ~str, message: ~str) -> ~Digest {
  HashEngine::new(SHA512).hmac(key, message)
}

fn main() {
  if core::os::args().len() < 2 { fail!(~"Nothing to hash: supply an argument") }
  io::println(sha1(core::os::args()[1].clone().to_bytes()).hexdigest());
}

#[test]
fn test_sha1() {
  assert_eq!(sha1("testing SHA1".to_bytes()).hexdigest(), ~"a07bb2f7f56b7b47e54fd9e29b4629c8967dde4c");
}

#[test]
fn test_md5() {
  assert_eq!(md5("testing MD5".to_bytes()).hexdigest(), ~"da35df95d34f166890fa759f5e00e94c");
}

#[test]
fn test_hmac_sha1_with_a_40_byte_key() {
  assert_eq!(
    hmac_sha1(~"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", ~"some data to hmac").hexdigest(),
    ~"18f652f1bced11930d55a72ad60bb5e671573dec"
  )
}

#[test]
fn test_hmac_sha1_with_a_too_long_key() {
  assert_eq!(
    hmac_sha1(~"keyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", ~"some data to hmac").hexdigest(),
    ~"64109bfc49893757afcc3c0c80b8eb61ce0f60a5"
  )
}

#[test]
fn test_hmac_sha1_with_a_too_short_key() {
  assert_eq!(
    hmac_sha1(~"my key", ~"some data to hmac").hexdigest(),
    ~"331c9bf4d7dc8ad7e9bab2f566c8612042a9f4e2"
  )
}

#[test]
fn test_hmac_sha256() {
  assert_eq!(
    hmac_sha256(~"my key", ~"some data to hmac").hexdigest(),
    ~"17764a8a2e8c23ae3b9e1781c5ebeb5754c7920806021032e9133051e10118be"
  );
}

#[test]
fn test_hmac_sha512() {
  assert_eq!(
    hmac_sha512(~"my key", ~"some data to hmac").hexdigest(),
    ~"b54973feba2e436c4f0911855c80e7320d72edd37b359d6474d714718c52775f163832b79214e9fa9d400208d21372a465b2cda2a1d5ab488bbc02b0daea9626"
  );
}

#[test]
fn test_hmac_md5() {
  assert_eq!(hmac_md5(~"my key", ~"some data to hmac").hexdigest(), ~"befd13e00ee07549520ade402c664a3a");
}
<|endoftext|>


<commit_before>use super::*;
use super::len::ParallelLen;
use super::state::*;

pub struct Weight<M> {
    base: M,
    weight: f64,
}

impl<M> Weight<M> {
    pub fn new(base: M, weight: f64) -> Weight<M> {
        Weight { base: base, weight: weight }
    }
}

impl<M> ParallelIterator for Weight<M>
    where M: ParallelIterator,
{
    type Item = M::Item;
    type Shared = WeightShared<M>;
    type State = WeightState<M>;

    fn drive<C: Consumer<Item=Self::Item>>(self, consumer: C) -> C::Result {
        unimplemented!()
    }

    fn state(self) -> (Self::Shared, Self::State) {
        let (base_shared, base_state) = self.base.state();
        (WeightShared { base: base_shared, weight: self.weight },
         WeightState { base: base_state })
    }
}

unsafe impl<M: BoundedParallelIterator> BoundedParallelIterator for Weight<M> {
    fn upper_bound(&mut self) -> usize {
        self.base.upper_bound()
    }
}

unsafe impl<M: ExactParallelIterator> ExactParallelIterator for Weight<M> {
    fn len(&mut self) -> usize {
        self.base.len()
    }
}

pub struct WeightState<M>
    where M: ParallelIterator
{
    base: M::State,
}

pub struct WeightShared<M>
    where M: ParallelIterator
{
    base: M::Shared,
    weight: f64,
}

unsafe impl<M> ParallelIteratorState for WeightState<M>
    where M: ParallelIterator,
{
    type Item = M::Item;
    type Shared = WeightShared<M>;

    fn len(&mut self, shared: &Self::Shared) -> ParallelLen {
        let mut l = self.base.len(&shared.base);
        l.cost *= shared.weight;
        l
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.base.split_at(index);
        (WeightState { base: left }, WeightState { base: right })
    }

    fn next(&mut self, shared: &Self::Shared) -> Option<Self::Item> {
        self.base.next(&shared.base)
    }
}

///////////////////////////////////////////////////////////////////////////

pub struct WeightProducer
 {
    base: P
}

impl
 Producer for WeightProducer

{
    type Item = P::Item;
    type Shared = P::Shared;

    unsafe fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.base.split_at(index);
        (WeightProducer { base: left }, WeightProducer { base: right })
    }

    unsafe fn produce(&mut self, shared: &P::Shared) -> P::Item {
        self.base.produce(shared)
    }
}
<commit_msg>add `Weight` consumer<commit_after>use super::*;
use super::len::ParallelLen;
use super::state::*;

pub struct Weight<M> {
    base: M,
    weight: f64,
}

impl<M> Weight<M> {
    pub fn new(base: M, weight: f64) -> Weight<M> {
        Weight { base: base, weight: weight }
    }
}

impl<M> ParallelIterator for Weight<M>
    where M: ParallelIterator,
{
    type Item = M::Item;
    type Shared = WeightShared<M>;
    type State = WeightState<M>;

    fn drive<C: Consumer<Item=Self::Item>>(self, consumer: C) -> C::Result {
        unimplemented!()
    }

    fn state(self) -> (Self::Shared, Self::State) {
        let (base_shared, base_state) = self.base.state();
        (WeightShared { base: base_shared, weight: self.weight },
         WeightState { base: base_state })
    }
}

unsafe impl<M: BoundedParallelIterator> BoundedParallelIterator for Weight<M> {
    fn upper_bound(&mut self) -> usize {
        self.base.upper_bound()
    }
}

unsafe impl<M: ExactParallelIterator> ExactParallelIterator for Weight<M> {
    fn len(&mut self) -> usize {
        self.base.len()
    }
}

pub struct WeightState<M>
    where M: ParallelIterator
{
    base: M::State,
}

pub struct WeightShared<M>
    where M: ParallelIterator
{
    base: M::Shared,
    weight: f64,
}

unsafe impl<M> ParallelIteratorState for WeightState<M>
    where M: ParallelIterator,
{
    type Item = M::Item;
    type Shared = WeightShared<M>;

    fn len(&mut self, shared: &Self::Shared) -> ParallelLen {
        let mut l = self.base.len(&shared.base);
        l.cost *= shared.weight;
        l
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.base.split_at(index);
        (WeightState { base: left }, WeightState { base: right })
    }

    fn next(&mut self, shared: &Self::Shared) -> Option<Self::Item> {
        self.base.next(&shared.base)
    }
}

///////////////////////////////////////////////////////////////////////////

pub struct WeightProducer
 {
    base: P
}

impl
 Producer for WeightProducer

{
    type Item = P::Item;
    type Shared = P::Shared;

    unsafe fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.base.split_at(index);
        (WeightProducer { base: left }, WeightProducer { base: right })
    }

    unsafe fn produce(&mut self, shared: &P::Shared) -> P::Item {
        self.base.produce(shared)
    }
}

///////////////////////////////////////////////////////////////////////////
// Consumer implementation

struct WeightConsumer<C>
    where C: Consumer,
{
    base: C,
}

impl<C> WeightConsumer<C>
    where C: Consumer,
{
    fn new(base: C) -> WeightConsumer<C> {
        WeightConsumer { base: base, }
    }
}

impl<C> Consumer for WeightConsumer<C>
    where C: Consumer,
{
    type Item = C::Item;
    type Shared = C::Shared;
    type SeqState = C::SeqState;
    type Result = C::Result;

    unsafe fn split_at(self, index: usize) -> (Self, Self) {
        let (left, right) = self.base.split_at(index);
        (WeightConsumer::new(left), WeightConsumer::new(right))
    }

    unsafe fn start(&mut self, shared: &Self::Shared) -> C::SeqState {
        self.base.start(shared)
    }

    unsafe fn consume(&mut self,
                      shared: &Self::Shared,
                      state: C::SeqState,
                      item: Self::Item)
                      -> C::SeqState
    {
        self.base.consume(shared, state, item)
    }

    unsafe fn complete(self, shared: &Self::Shared, state: C::SeqState) -> C::Result {
        self.base.complete(shared, state)
    }

    unsafe fn reduce(shared: &Self::Shared, left: C::Result, right: C::Result) -> C::Result {
        C::reduce(shared, left, right)
    }
}
<|endoftext|>


<commit_before>//!
//! Interpreter Compiler for Expressions
//!

use std::boxed::Box;
use std::ops;
use std::fmt::Display;

use common::constant::VECTOR_SIZE;
use common::err::{Error, TResult, Void, void_ok};
use eval::{Eval, MapEval};
use eval::primitives::*;
use expr::{ArithmOp, Datum, Expr, Visitor};
use rows::RowBlock;
use rows::vector::{Vector, ArrayVector};
use schema::{Column, Schema};
use types::*;

// Unary Expressions
pub struct Not {child: Box<Eval>}
pub struct IsNull {child: Box<Eval>}

// Binary Comparison Expressions
pub struct And {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct Or {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct Equal {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct NotEqual {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct LessThan {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct LessThanOrEqual {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct GreaterThan {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct GreaterThanOrEqual {lhs: Box<Eval>, rhs: Box<Eval>}

// Binary Arithmetic Evalessions
pub struct ArithmMapEval<'a> {
  pub op: ArithmOp,
  pub data_ty: Option<DataTy>,
  pub lhs: Box<MapEval>,
  pub rhs: Box<MapEval>,
  pub result: ArrayVector<'a>,
  pub f: Option<fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)>
}

// String operators or pattern matching predicates
pub struct Concatenate {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct Like {pattern: String, child: Box<Eval>}
pub struct SimilarTo {pattern: String, child: Box<Eval>}
pub struct RegexMatch {pattern: String, child: Box<Eval>}

pub struct Between {pred: Box<Eval>, begin: Box<Eval>, end: Box<Eval>}
pub struct In {pred: Box<Eval>, row: Box<Row>}

pub struct Row {values: Vec<Box<Eval>>}

impl<'a> Eval for ArithmMapEval<'a> {

  fn bind(&mut self, schema: &Schema) -> Void {
    self.data_ty = Some(result_data_ty(self.lhs.data_ty(), self.rhs.data_ty()));
    try!(self.lhs.bind(schema));
    try!(self.rhs.bind(schema));
    void_ok()
  }

  fn is_const(&self) -> bool { false }
}

impl<'a> HasDataTy for ArithmMapEval<'a> {
  fn data_ty(&self) -> &DataTy {
    self.data_ty.as_ref().unwrap()
  }
}

impl<'a> MapEval for ArithmMapEval<'a> {
  fn eval<'r>(&'r mut self, r: &'r RowBlock) -> &'r Vector {
    self.f.unwrap()(&mut self.result,
                    self.lhs.eval(r),
                    self.rhs.eval(r),
                    None);
    &self.result
  }
}

impl Field {
  pub fn new(column: &Column) -> Field {
    Field {
      column: column.clone(),
      field_id: 0
    }
  }
}

impl HasDataTy for Field {
  fn data_ty(&self) -> &DataTy {
    &self.column.data_ty
  }
}

pub struct Field {column: Column, field_id: usize}

impl Eval for Field {

  fn bind(&mut self, schema: &Schema) -> Void {

    match schema.column_id(&self.column.name) {

     Some(id) => {
      self.field_id = id;
      void_ok()
     },

     None => Err(Error::UndefinedColumn)
    }
  }

  fn is_const(&self) -> bool { false }
}

impl MapEval for Field {
  fn eval<'r>(&'r mut self, r: &'r RowBlock) -> &'r Vector {
    r.vector(self.field_id)
  }
}

pub struct Const {datum: Datum, res_type: DataTy}

impl Const {
  fn new(datum: &Datum) -> Const {
    Const {
        datum: datum.clone(),
        res_type: DataTy::new(datum.ty())
    }
  }
}

impl HasDataTy for Const {
  fn data_ty(&self) -> &DataTy {
    &self.res_type
  }
}

impl Eval for Const {

  fn bind(&mut self, schema: &Schema) -> Void {
    self.res_type = DataTy::new(self.datum.ty());
    void_ok()
  }

  fn is_const(&self) -> bool { true }
}

pub struct InterpreterCompiler {
  tree: Option<Box<Eval>>,
  err: Option<Error>,
  node_num: u32
}

impl<'v> Visitor<'v> for InterpreterCompiler {
  fn visit_field(&mut self, c: &'v Column) {
    println!("column: {}", c.name);
  }
}

fn get_arithm_prim(op: ArithmOp,
                   res_ty: &DataTy,
                   lhs_dty: &DataTy, lhs_vec: bool,
                   rhs_dty: &DataTy, rhs_vec: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>) {

  assert_eq!(lhs_dty, rhs_dty);

  match op {

    ArithmOp::Plus => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_plus_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_plus_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_plus_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_plus_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_plus_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_plus_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_plus_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_plus_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    },

    ArithmOp::Sub => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_sub_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_sub_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_sub_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_sub_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_sub_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_sub_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_sub_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_sub_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    },

    ArithmOp::Mul => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_mul_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_mul_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_mul_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_mul_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_mul_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_mul_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_mul_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_mul_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    },

    ArithmOp::Div => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_div_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_div_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_div_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_div_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_div_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_div_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_div_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_div_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    },

    ArithmOp::Rem => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_rem_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_rem_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_rem_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_rem_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_rem_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_rem_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_rem_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_rem_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    }
  }
}

fn get_arithm_plus_vec_or_const<T>(lhs_vec: bool, rhs_vec: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Add<T, Output=T> {

  match (lhs_vec, rhs_vec) {
    (true, true) => map_plus_vv::<T>,
    (true, false) => map_plus_vc::<T>,
    (false, true) => map_plus_cv::<T>,
    _ => panic!("plus operation between const and const is not supported yet.")
  }
}

fn get_arithm_sub_vec_or_const<T>(lhs_vec: bool, rhs_vec: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Sub<T, Output=T> {

  match (lhs_vec, rhs_vec) {
    (true, true) => map_sub_vv::<T>,
    (true, false) => map_sub_vc::<T>,
    (false, true) => map_sub_cv::<T>,
    _ => panic!("plus operation between const and const is not supported yet.")
  }
}

fn get_arithm_mul_vec_or_const<T>(lhs_vec: bool, rhs_vec: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Mul<T, Output=T> {

  match (lhs_vec, rhs_vec) {
    (true, true) => map_mul_vv::<T>,
    (true, false) => map_mul_vc::<T>,
    (false, true) => map_mul_cv::<T>,
    _ => panic!("plus operation between const and const is not supported yet.")
  }
}

fn get_arithm_div_vec_or_const<T>(lhs_vec: bool, rhs_vec: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Div<T, Output=T> {

  match (lhs_vec, rhs_vec) {
    (true, true) => map_div_vv::<T>,
    (true, false) => map_div_vc::<T>,
    (false, true) => map_div_cv::<T>,
    _ => panic!("plus operation between const and const is not supported yet.")
  }
}

fn get_arithm_rem_vec_or_const<T>(lhs_vec: bool, rhs_vec: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Rem<T, Output=T> {

  match (lhs_vec, rhs_vec) {
    (true, true) => map_rem_vv::<T>,
    (true, false) => map_rem_vc::<T>,
    (false, true) => map_rem_cv::<T>,
    _ => panic!("plus operation between const and const is not supported yet.")
  }
}<commit_msg>Applied vector or const parameter to get_arithm_prim().<commit_after>//!
//! Interpreter Compiler for Expressions
//!

use std::boxed::Box;
use std::ops;
use std::fmt::Display;

use common::constant::VECTOR_SIZE;
use common::err::{Error, TResult, Void, void_ok};
use eval::{Eval, MapEval};
use eval::primitives::*;
use expr::{ArithmOp, Datum, Expr, Visitor};
use rows::RowBlock;
use rows::vector::{Vector, ArrayVector};
use schema::{Column, Schema};
use types::*;

// Unary Expressions
pub struct Not {child: Box<Eval>}
pub struct IsNull {child: Box<Eval>}

// Binary Comparison Expressions
pub struct And {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct Or {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct Equal {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct NotEqual {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct LessThan {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct LessThanOrEqual {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct GreaterThan {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct GreaterThanOrEqual {lhs: Box<Eval>, rhs: Box<Eval>}

// Binary Arithmetic Evalessions
pub struct ArithmMapEval<'a> {
  pub op: ArithmOp,
  pub data_ty: Option<DataTy>,
  pub lhs: Box<MapEval>,
  pub rhs: Box<MapEval>,
  pub result: ArrayVector<'a>,
  pub f: Option<fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)>
}

// String operators or pattern matching predicates
pub struct Concatenate {lhs: Box<Eval>, rhs: Box<Eval>}
pub struct Like {pattern: String, child: Box<Eval>}
pub struct SimilarTo {pattern: String, child: Box<Eval>}
pub struct RegexMatch {pattern: String, child: Box<Eval>}

pub struct Between {pred: Box<Eval>, begin: Box<Eval>, end: Box<Eval>}
pub struct In {pred: Box<Eval>, row: Box<Row>}

pub struct Row {values: Vec<Box<Eval>>}

impl<'a> Eval for ArithmMapEval<'a> {

  fn bind(&mut self, schema: &Schema) -> Void {
    self.data_ty = Some(result_data_ty(self.lhs.data_ty(), self.rhs.data_ty()));
    try!(self.lhs.bind(schema));
    try!(self.rhs.bind(schema));

    self.f = Some(get_arithm_prim(&self.op,
                                  self.data_ty.as_ref().unwrap(),
                                  &self.lhs.data_ty(), self.lhs.is_const(),
                                  &self.rhs.data_ty(), self.rhs.is_const()));

    void_ok()
  }

  fn is_const(&self) -> bool { false }
}

impl<'a> HasDataTy for ArithmMapEval<'a> {
  fn data_ty(&self) -> &DataTy {
    self.data_ty.as_ref().unwrap()
  }
}

impl<'a> MapEval for ArithmMapEval<'a> {
  fn eval<'r>(&'r mut self, r: &'r RowBlock) -> &'r Vector {
    self.f.unwrap()(&mut self.result,
                    self.lhs.eval(r),
                    self.rhs.eval(r),
                    None);
    &self.result
  }
}

impl Field {
  pub fn new(column: &Column) -> Field {
    Field {
      column: column.clone(),
      field_id: 0
    }
  }
}

impl HasDataTy for Field {
  fn data_ty(&self) -> &DataTy {
    &self.column.data_ty
  }
}

pub struct Field {column: Column, field_id: usize}

impl Eval for Field {

  fn bind(&mut self, schema: &Schema) -> Void {

    match schema.column_id(&self.column.name) {

     Some(id) => {
      self.field_id = id;
      void_ok()
     },

     None => Err(Error::UndefinedColumn)
    }
  }

  fn is_const(&self) -> bool { false }
}

impl MapEval for Field {
  fn eval<'r>(&'r mut self, r: &'r RowBlock) -> &'r Vector {
    r.vector(self.field_id)
  }
}

pub struct Const {datum: Datum, res_type: DataTy}

impl Const {
  fn new(datum: &Datum) -> Const {
    Const {
        datum: datum.clone(),
        res_type: DataTy::new(datum.ty())
    }
  }
}

impl HasDataTy for Const {
  fn data_ty(&self) -> &DataTy {
    &self.res_type
  }
}

impl Eval for Const {

  fn bind(&mut self, schema: &Schema) -> Void {
    self.res_type = DataTy::new(self.datum.ty());
    void_ok()
  }

  fn is_const(&self) -> bool { true }
}

pub struct InterpreterCompiler {
  tree: Option<Box<Eval>>,
  err: Option<Error>,
  node_num: u32
}

impl<'v> Visitor<'v> for InterpreterCompiler {
  fn visit_field(&mut self, c: &'v Column) {
    println!("column: {}", c.name);
  }
}

fn get_arithm_prim(op: &ArithmOp,
                   res_ty: &DataTy,
                   lhs_dty: &DataTy, lhs_vec: bool,
                   rhs_dty: &DataTy, rhs_vec: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>) {

  assert_eq!(lhs_dty, rhs_dty);

  match *op {

    ArithmOp::Plus => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_plus_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_plus_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_plus_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_plus_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_plus_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_plus_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_plus_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_plus_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    },

    ArithmOp::Sub => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_sub_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_sub_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_sub_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_sub_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_sub_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_sub_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_sub_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_sub_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    },

    ArithmOp::Mul => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_mul_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_mul_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_mul_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_mul_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_mul_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_mul_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_mul_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_mul_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    },

    ArithmOp::Div => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_div_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_div_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_div_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_div_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_div_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_div_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_div_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_div_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    },

    ArithmOp::Rem => {
      match lhs_dty.ty() {
        Ty::Int2      => get_arithm_rem_vec_or_const::<INT2_T>(lhs_vec, rhs_vec),
        Ty::Int4      => get_arithm_rem_vec_or_const::<INT4_T>(lhs_vec, rhs_vec),
        Ty::Int8      => get_arithm_rem_vec_or_const::<INT8_T>(lhs_vec, rhs_vec),
        Ty::Float4    => get_arithm_rem_vec_or_const::<FLOAT4_T>(lhs_vec, rhs_vec),
        Ty::Float8    => get_arithm_rem_vec_or_const::<FLOAT8_T>(lhs_vec, rhs_vec),
        Ty::Time      => get_arithm_rem_vec_or_const::<TIME_T>(lhs_vec, rhs_vec),
        Ty::Date      => get_arithm_rem_vec_or_const::<DATE_T>(lhs_vec, rhs_vec),
        Ty::Timestamp => get_arithm_rem_vec_or_const::<TIMESTAMP_T>(lhs_vec, rhs_vec),
        _ => panic!("unsupported data type")
      }
    }
  }
}

fn get_arithm_plus_vec_or_const<T>(lhs_const: bool, rhs_const: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Add<T, Output=T> {

  match (lhs_const, rhs_const) {
    (true, false) => map_plus_cv::<T>,
    (false, true) => map_plus_vc::<T>,
    (false, false) => map_plus_vv::<T>,
    _ => panic!("plus operation between const and const is not supported yet.")
  }
}

fn get_arithm_sub_vec_or_const<T>(lhs_const: bool, rhs_const: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Sub<T, Output=T> {

  match (lhs_const, rhs_const) {
    (true, false) => map_sub_cv::<T>,
    (false, true) => map_sub_vc::<T>,
    (false, false) => map_sub_vv::<T>,
    _ => panic!("sub operation between const and const is not supported yet.")
  }
}

fn get_arithm_mul_vec_or_const<T>(lhs_const: bool, rhs_const: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Mul<T, Output=T> {

  match (lhs_const, rhs_const) {
    (true, false) => map_mul_cv::<T>,
    (false, true) => map_mul_vc::<T>,
    (false, false) => map_mul_vv::<T>,
    _ => panic!("mul operation between const and const is not supported yet.")
  }
}

fn get_arithm_div_vec_or_const<T>(lhs_const: bool, rhs_const: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Div<T, Output=T> {

  match (lhs_const, rhs_const) {
    (true, false) => map_div_cv::<T>,
    (false, true) => map_div_vc::<T>,
    (false, false) => map_div_vv::<T>,
    _ => panic!("div operation between const and const is not supported yet.")
  }
}

fn get_arithm_rem_vec_or_const<T>(lhs_const: bool, rhs_const: bool)
    -> fn(&mut Vector, &Vector, &Vector, Option<&[usize]>)
    where T : Copy + Display + ops::Rem<T, Output=T> {

  match (lhs_const, rhs_const) {
    (true, false) => map_rem_cv::<T>,
    (false, true) => map_rem_vc::<T>,
    (false, false) => map_rem_vv::<T>,
    _ => panic!("rem operation between const and const is not supported yet.")
  }
}<|endoftext|>


<commit_before>use super::ease::Easing;
pub struct Bounce;

impl Easing for Bounce {
    fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 {
        c - Bounce::ease_out(d - t, 0.0, c, d) + b
    }

    fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let mut inner_t = t / d;
        if inner_t < 1.0 / 2.75 {
            c * (7.5625 * inner_t * inner_t) + b
        } else if inner_t < 2.0 / 2.75 {
            inner_t -= 1.5 / 2.75;
            c * (7.5625 * inner_t * inner_t + 0.75) + b
        } else if inner_t < 2.5 / 2.75 {
            inner_t -= 2.25 / 2.75;
            c * (7.5625 * inner_t * inner_t + 0.9375) + b
        } else {
            inner_t -= 2.625 / 2.75;
            c * (7.5625 * inner_t * inner_t + 0.984375) + b
        }
    }

    fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t < (d / 2.0) {
            Bounce::ease_in(t * 2.0, 0.0, c, d) * 0.5 + b
        } else {
            Bounce::ease_out(t * 2.0 - d, 0.0, c, d) * 0.5 + c * 0.5 + b
        }

    }
}

mod test {
    use functions::ease::Easing;
    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 4.0), 3.4179688);
        assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 2.0), 4.296875);
    }

    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Bounce::ease_in(1.0, 2.0, 3.0, 4.0), 2.082031);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Bounce::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.3515625);
    }
}
<commit_msg>more bounce functions added<commit_after>use super::ease::Easing;
pub struct Bounce;

impl Easing for Bounce {
    fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 {
        c - Bounce::ease_out(d - t, 0.0, c, d) + b
    }

    fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let mut inner_t = t / d;
        if inner_t < 1.0 / 2.75 {
            c * (7.5625 * inner_t * inner_t) + b
        } else if inner_t < 2.0 / 2.75 {
            inner_t -= 1.5 / 2.75;
            c * (7.5625 * inner_t * inner_t + 0.75) + b
        } else if inner_t < 2.5 / 2.75 {
            inner_t -= 2.25 / 2.75;
            c * (7.5625 * inner_t * inner_t + 0.9375) + b
        } else {
            inner_t -= 2.625 / 2.75;
            c * (7.5625 * inner_t * inner_t + 0.984375) + b
        }
    }

    fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t < (d / 2.0) {
            Bounce::ease_in(t * 2.0, 0.0, c, d) * 0.5 + b
        } else {
            Bounce::ease_out(t * 2.0 - d, 0.0, c, d) * 0.5 + c * 0.5 + b
        }

    }
}

mod test {
    use functions::ease::Easing;
    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 4.0), 3.4179688);
        assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 2.0), 4.296875);
        assert_relative_eq!(super::Bounce::ease_out(100.0, 1.0, 100.0, 100.0),
                            101.000000);
    }

    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Bounce::ease_in(1.0, 2.0, 3.0, 4.0), 2.082031);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Bounce::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.3515625);
        assert_relative_eq!(super::Bounce::ease_in_out(51.0, 1.0, 100.0, 100.0),
                            51.151250);
    }
}
<|endoftext|>


<commit_before>use std::collections::{VecDeque, HashMap};

use memory::{StaticAllocator, MemoryBlock};

use super::item_type::ItemType;

/// Represents a single level of scope
pub type Scope = HashMap<String, MemoryBlock>;

pub struct ScopeStack {
    stack: VecDeque<Scope>,
    allocator: StaticAllocator,
}

impl ScopeStack {
    pub fn new() -> ScopeStack {
        ScopeStack {
            stack: {
                let mut queue = VecDeque::new();
                queue.push_back(Scope::new());
                queue
            },
            allocator: StaticAllocator::new(),
        }
    }

    /// Declares a name with the given type, allocates enough space for that type
    /// The name is declared in the "current" scope which is at the top of the stack
    /// Returns the allocated memory block
    pub fn declare(&mut self, name: String, typ: ItemType) -> MemoryBlock {
        unimplemented!();
    }

    /// Allocate a memory block that is large enough for the given type
    /// Does not associate memory block with a name which means it cannot be looked up later
    /// Returns the allocated memory block
    pub fn allocate(&mut self, typ: ItemType) -> MemoryBlock {
        let size = typ.required_size();
        self.allocator.allocate(size)
    }
}
<commit_msg>Implemented remaining scope stack including ability to push/pop scopes and lookup values in all scopes<commit_after>use std::collections::{VecDeque, HashMap};

use memory::{StaticAllocator, MemoryBlock};

use super::item_type::ItemType;

/// Represents a single level of scope
pub type Scope = HashMap<String, (ItemType, MemoryBlock)>;

pub struct ScopeStack {
    stack: VecDeque<Scope>,
    allocator: StaticAllocator,
}

impl ScopeStack {
    pub fn new() -> ScopeStack {
        ScopeStack {
            stack: {
                let mut queue = VecDeque::new();
                queue.push_back(Scope::new());
                queue
            },
            allocator: StaticAllocator::new(),
        }
    }

    /// Pushes a new level of scope onto the stack
    /// This scope will become the current scope
    pub fn push_scope(&mut self) {
        self.stack.push_back(Scope::new());
    }

    /// Removes and returns the top level scope (current scope)
    ///
    /// # Panics
    /// Panics if there is no scope in the stack
    pub fn pop_scope(&mut self) -> Scope {
        self.stack.pop_back().unwrap()
    }

    /// Looks up a name starting at the current scope
    pub fn lookup(&self, name: &str) -> Option<&(ItemType, MemoryBlock)> {
        self.stack.iter().rev().map(|sc| sc.get(name)).find(|r| r.is_some()).unwrap_or(None)
    }

    /// Declares a name with the given type, allocates enough space for that type
    /// The name is declared in the "current" scope which is at the top of the stack
    /// Returns the allocated memory block
    pub fn declare(&mut self, name: String, typ: ItemType) -> MemoryBlock {
        let mem = self.allocate(&typ);
        // It's OK to overwrite existing names because we support rebinding
        if let Some(scope) = self.stack.back_mut() {
            scope.insert(name, (typ, mem));
        }
        else {
            panic!("Attempt to declare name despite having no current scope");
        }

        mem
    }

    /// Allocate a memory block that is large enough for the given type
    /// Does not associate memory block with a name which means it cannot be looked up later
    /// Returns the allocated memory block
    pub fn allocate(&mut self, typ: &ItemType) -> MemoryBlock {
        let size = typ.required_size();
        self.allocator.allocate(size)
    }
}
<|endoftext|>