<commit_before>use rustwlc::{Point, Size, ResizeEdge,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM};

static MIN_SIZE: Size = Size { w: 80u32, h: 40u32 };

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType};
use uuid::Uuid;

#[derive(Debug, Clone, Copy)]
pub enum ResizeErr {
    /// Expected the node associated with the UUID to be floating.
    ExpectedFloating(Uuid),
    /// Expected the node associated with the UUID to not be floating
    ExpectedNotFloating(Uuid)
}

impl LayoutTree {
    /// Resizes a floating container. If the container was not floating, an Err is returned.
    pub fn resize_floating(&mut self, id: Uuid, edges: ResizeEdge, pointer: Point,
                           action: &mut Action) -> CommandResult {
        let container = try!(self.lookup_mut(id));
        if !container.floating() {
            return Err(TreeError::Resize(ResizeErr::ExpectedFloating(container.get_id())))
        }
        match container.get_type() {
            ContainerType::View | ContainerType::Container => {},
            _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                     vec!(ContainerType::View)))
        }
        let mut geo = container.get_geometry()
            .expect("Could not get geometry of the container");
        let mut new_geo = geo.clone();

        let grab = action.grab;
        action.grab = pointer;
        let dx = pointer.x - grab.x;
        let dy = pointer.y - grab.y;
        if edges.contains(RESIZE_LEFT) {
            if dx < 0 {
                new_geo.size.w += dx.abs() as u32;
            } else {
                new_geo.size.w -= dx.abs() as u32;
            }
            new_geo.origin.x += dx;
        }
        else if edges.contains(RESIZE_RIGHT) {
            if dx < 0 {
                new_geo.size.w -= dx.abs() as u32;
            } else {
                new_geo.size.w += dx.abs() as u32;
            }
        }

        if edges.contains(RESIZE_TOP) {
            if dy < 0 {
                new_geo.size.h += dy.abs() as u32;
            } else {
                new_geo.size.h -= dy.abs() as u32;
            }
            new_geo.origin.y += dy;
        }
        else if edges.contains(RESIZE_BOTTOM) {
            if dy < 0 {
                new_geo.size.h -= dy.abs() as u32;
            } else {
                new_geo.size.h += dy.abs() as u32;
            }
        }

        if new_geo.size.w >= MIN_SIZE.w {
            geo.origin.x = new_geo.origin.x;
            geo.size.w = new_geo.size.w;
        }

        if new_geo.size.h >= MIN_SIZE.h {
            geo.origin.y = new_geo.origin.y;
            geo.size.h = new_geo.size.h;
        }

        container.set_geometry(edges, geo);
        Ok(())
    }

    pub fn resize_tiled(&mut self, id: Uuid, edges: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // There can be multiple directions we are moving in, e.g up and left.
        let dirs_moving_in = Direction::from_edge(edges);
        let siblings: Vec<Uuid> = dirs_moving_in.iter().map(|dir| self.sibling_in_dir(id, *dir)).collect();

        // Because we can't have multiple mutable references active in the tree at once,
        // first we modify the one the user is resizing and then adjust the siblings.
        {
            let container = try!(self.lookup_mut(id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let mut cur_geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let mut cur_new_geo = cur_geo.clone();

            let grab = action.grab;
            action.grab = pointer;
            let dx = pointer.x - grab.x;
            let dy = pointer.y - grab.y;
            if edges.contains(RESIZE_LEFT) {
                if dx < 0 {
                    cur_new_geo.size.w += dx.abs() as u32;
                } else {
                    cur_new_geo.size.w -= dx.abs() as u32;
                }
                cur_new_geo.origin.x += dx;
            }
            else if edges.contains(RESIZE_RIGHT) {
                if dx < 0 {
                    cur_new_geo.size.w -= dx.abs() as u32;
                } else {
                    cur_new_geo.size.w += dx.abs() as u32;
                }
            }

            if edges.contains(RESIZE_TOP) {
                if dy < 0 {
                    cur_new_geo.size.h += dy.abs() as u32;
                } else {
                    cur_new_geo.size.h -= dy.abs() as u32;
                }
                cur_new_geo.origin.y += dy;
            }
            else if edges.contains(RESIZE_BOTTOM) {
                if dy < 0 {
                    cur_new_geo.size.h -= dy.abs() as u32;
                } else {
                    cur_new_geo.size.h += dy.abs() as u32;
                }
            }

            if cur_new_geo.size.w >= MIN_SIZE.w {
                cur_geo.origin.x = cur_new_geo.origin.x;
                cur_geo.size.w = cur_new_geo.size.w;
            }

            if cur_new_geo.size.h >= MIN_SIZE.h {
                cur_geo.origin.y = cur_new_geo.origin.y;
                cur_geo.size.h = cur_new_geo.size.h;
            }
        }
        // and now we mutate the siblings
        for sibling in siblings {
            // Do the same thing here as we do above, but reverse the directions
        }
        Ok(())
    }
}
<commit_msg>Abstracted resize calculation into seperate method<commit_after>use rustwlc::{Point, Size, ResizeEdge, Geometry,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM};

static MIN_SIZE: Size = Size { w: 80u32, h: 40u32 };

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType};
use uuid::Uuid;

#[derive(Debug, Clone, Copy)]
pub enum ResizeErr {
    /// Expected the node associated with the UUID to be floating.
    ExpectedFloating(Uuid),
    /// Expected the node associated with the UUID to not be floating
    ExpectedNotFloating(Uuid)
}

impl LayoutTree {
    /// Resizes a floating container. If the container was not floating, an Err is returned.
    pub fn resize_floating(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                           action: &mut Action) -> CommandResult {
        let container = try!(self.lookup_mut(id));
        if !container.floating() {
            return Err(TreeError::Resize(ResizeErr::ExpectedFloating(container.get_id())))
        }
        match container.get_type() {
            ContainerType::View | ContainerType::Container => {},
            _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                     vec!(ContainerType::View)))
        }
        let geo = container.get_geometry()
            .expect("Could not get geometry of the container");

        let new_geo = calculate_resize(geo, edge, pointer, action.grab);
        action.grab = pointer;

        container.set_geometry(edge, new_geo);
        Ok(())
    }

    pub fn resize_tiled(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // There can be multiple directions we are moving in, e.g up and left.
        let dirs_moving_in = Direction::from_edge(edge);
        let siblings: Vec<Uuid> = dirs_moving_in.iter().map(|dir| self.sibling_in_dir(id, *dir)).collect();

        // Because we can't have multiple mutable references active in the tree at once,
        // first we modify the one the user is resizing and then adjust the siblings.
        {
            let container = try!(self.lookup_mut(id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(edge, new_geo);
        }
        // and now we mutate the siblings
        for sibling in siblings {
            // Do the same thing here as we do above, but reverse the directions
        }
        Ok(())
    }
}

/// Calculates what the new geometry is of a window.
/// Needs the geometry of the window, the edge direction the pointer is moving in,
/// the current position of the pointer, and the previous place the pointer was at.
fn calculate_resize(geo: Geometry, edge: ResizeEdge,
                    cur_pointer: Point, prev_pointer: Point) -> Geometry {
    let mut new_geo = geo.clone();
    let dx = cur_pointer.x - prev_pointer.x;
    let dy = cur_pointer.y - prev_pointer.y;
    if edge.contains(RESIZE_LEFT) {
        if dx < 0 {
            new_geo.size.w += dx.abs() as u32;
        } else {
            new_geo.size.w -= dx.abs() as u32;
        }
        new_geo.origin.x += dx;
    }
    else if edge.contains(RESIZE_RIGHT) {
        if dx < 0 {
            new_geo.size.w -= dx.abs() as u32;
        } else {
            new_geo.size.w += dx.abs() as u32;
        }
    }

    if edge.contains(RESIZE_TOP) {
        if dy < 0 {
            new_geo.size.h += dy.abs() as u32;
        } else {
            new_geo.size.h -= dy.abs() as u32;
        }
        new_geo.origin.y += dy;
    }
    else if edge.contains(RESIZE_BOTTOM) {
        if dy < 0 {
            new_geo.size.h -= dy.abs() as u32;
        } else {
            new_geo.size.h += dy.abs() as u32;
        }
    }

    if new_geo.size.w <= MIN_SIZE.w {
        new_geo.origin.x = geo.origin.x;
        new_geo.size.w = geo.size.w;
    }

    if new_geo.size.h <= MIN_SIZE.h {
        new_geo.origin.y = geo.origin.y;
        new_geo.size.h = geo.size.h;
    }
    new_geo
}
<|endoftext|>


<commit_before>use crate::ptr;
use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback};
use crate::alloc::{GlobalAlloc, Layout, System};

#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
    #[inline]
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
            libc::malloc(layout.size()) as *mut u8
        } else {
            #[cfg(target_os = "macos")]
            {
                if layout.align() > (1 << 31) {
                    return ptr::null_mut()
                }
            }
            aligned_malloc(&layout)
        }
    }

    #[inline]
    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
            libc::calloc(layout.size(), 1) as *mut u8
        } else {
            let ptr = self.alloc(layout.clone());
            if !ptr.is_null() {
                ptr::write_bytes(ptr, 0, layout.size());
            }
            ptr
        }
    }

    #[inline]
    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
        libc::free(ptr as *mut libc::c_void)
    }

    #[inline]
    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
            libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
        } else {
            realloc_fallback(self, ptr, layout, new_size)
        }
    }
}

#[cfg(any(target_os = "android",
          target_os = "hermit",
          target_os = "redox",
          target_os = "solaris"))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
    // On android we currently target API level 9 which unfortunately
    // doesn't have the `posix_memalign` API used below. Instead we use
    // `memalign`, but this unfortunately has the property on some systems
    // where the memory returned cannot be deallocated by `free`!
    //
    // Upon closer inspection, however, this appears to work just fine with
    // Android, so for this platform we should be fine to call `memalign`
    // (which is present in API level 9). Some helpful references could
    // possibly be chromium using memalign [1], attempts at documenting that
    // memalign + free is ok [2] [3], or the current source of chromium
    // which still uses memalign on android [4].
    //
    // [1]: https://codereview.chromium.org/10796020/
    // [2]: https://code.google.com/p/android/issues/detail?id=35391
    // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
    // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
    //                                       /memory/aligned_memory.cc
    libc::memalign(layout.align(), layout.size()) as *mut u8
}

#[cfg(not(any(target_os = "android",
              target_os = "hermit",
              target_os = "redox",
              target_os = "solaris")))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
    let mut out = ptr::null_mut();
    let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
    if ret != 0 {
        ptr::null_mut()
    } else {
        out as *mut u8
    }
}
<commit_msg>request at least ptr-size alignment from posix_memalign<commit_after>use crate::ptr;
use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback};
use crate::alloc::{GlobalAlloc, Layout, System};
use crate::mem;

#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
    #[inline]
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        // jemalloc provides alignment less than MIN_ALIGN for small allocations.
        // So only rely on MIN_ALIGN if size >= align.
        // Also see <https://github.com/rust-lang/rust/issues/45955>.
        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
            libc::malloc(layout.size()) as *mut u8
        } else {
            #[cfg(target_os = "macos")]
            {
                if layout.align() > (1 << 31) {
                    return ptr::null_mut()
                }
            }
            aligned_malloc(&layout)
        }
    }

    #[inline]
    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        // jemalloc provides alignment less than MIN_ALIGN for small allocations.
        // So only rely on MIN_ALIGN if size >= align.
        // Also see <https://github.com/rust-lang/rust/issues/45955>.
        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
            libc::calloc(layout.size(), 1) as *mut u8
        } else {
            let ptr = self.alloc(layout.clone());
            if !ptr.is_null() {
                ptr::write_bytes(ptr, 0, layout.size());
            }
            ptr
        }
    }

    #[inline]
    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
        libc::free(ptr as *mut libc::c_void)
    }

    #[inline]
    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
            libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
        } else {
            realloc_fallback(self, ptr, layout, new_size)
        }
    }
}

#[cfg(any(target_os = "android",
          target_os = "hermit",
          target_os = "redox",
          target_os = "solaris"))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
    // On android we currently target API level 9 which unfortunately
    // doesn't have the `posix_memalign` API used below. Instead we use
    // `memalign`, but this unfortunately has the property on some systems
    // where the memory returned cannot be deallocated by `free`!
    //
    // Upon closer inspection, however, this appears to work just fine with
    // Android, so for this platform we should be fine to call `memalign`
    // (which is present in API level 9). Some helpful references could
    // possibly be chromium using memalign [1], attempts at documenting that
    // memalign + free is ok [2] [3], or the current source of chromium
    // which still uses memalign on android [4].
    //
    // [1]: https://codereview.chromium.org/10796020/
    // [2]: https://code.google.com/p/android/issues/detail?id=35391
    // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
    // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
    //                                       /memory/aligned_memory.cc
    libc::memalign(layout.align(), layout.size()) as *mut u8
}

#[cfg(not(any(target_os = "android",
              target_os = "hermit",
              target_os = "redox",
              target_os = "solaris")))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
    let mut out = ptr::null_mut();
    // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
    // Since these are all powers of 2, we can just use max.
    let align = layout.align().max(mem::size_of::<usize>());
    let ret = libc::posix_memalign(&mut out, align, layout.size());
    if ret != 0 {
        ptr::null_mut()
    } else {
        out as *mut u8
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate env_logger;
extern crate futures_mio;
extern crate futures_tls;

#[macro_use]
extern crate cfg_if;

use std::io::Error;
use std::net::ToSocketAddrs;

use futures::Future;
use futures_tls::ClientContext;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

cfg_if! {
    if #[cfg(any(feature = "force-openssl",
                 all(not(target_os = "macos"),
                     not(target_os = "windows"))))] {
        extern crate openssl;

        use openssl::ssl;

        fn get(err: &Error) -> &openssl::error::ErrorStack {
            let err = err.get_ref().unwrap();
            match *err.downcast_ref::<ssl::error::Error>().unwrap() {
                ssl::Error::Ssl(ref v) => v,
                ref e => panic!("not an ssl eror: {:?}", e),
            }
        }

        fn verify_failed(err: &Error) {
            assert!(get(err).errors().iter().any(|e| {
                e.reason() == "certificate verify failed"
            }), "bad errors: {:?}", err);
        }

        use verify_failed as assert_expired_error;
        use verify_failed as assert_wrong_host;
        use verify_failed as assert_self_signed;
        use verify_failed as assert_untrusted_root;
    } else if #[cfg(target_os = "macos")] {
        extern crate security_framework;

        use security_framework::base::Error as SfError;

        fn assert_invalid_cert_chain(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }

        use assert_invalid_cert_chain as assert_expired_error;
        use assert_invalid_cert_chain as assert_wrong_host;
        use assert_invalid_cert_chain as assert_self_signed;
        use assert_invalid_cert_chain as assert_untrusted_root;
    } else {
        extern crate winapi;

        fn assert_expired_error(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_EXPIRED as usize);
        }

        fn assert_wrong_host(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }

        fn assert_self_signed(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_UNTRUSTEDROOT as usize);
        }

        fn assert_untrusted_root(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_UNTRUSTEDROOT as usize);
        }
    }
}

fn get_host(host: &'static str) -> Error {
    drop(env_logger::init());

    let addr = format!("{}:443", host);
    let addr = t!(addr.to_socket_addrs()).next().unwrap();

    let mut l = t!(futures_mio::Loop::new());
    let client = l.handle().tcp_connect(&addr);
    let data = client.and_then(move |socket| {
        t!(ClientContext::new()).handshake(host, socket)
    });

    let res = l.run(data);
    assert!(res.is_err());
    res.err().unwrap()
}

#[test]
fn expired() {
    assert_expired_error(&get_host("expired.badssl.com"))
}

// TODO: the OSX builders on Travis apparently fail this tests spuriously?
//       passes locally though? Seems... bad!
#[test]
#[cfg_attr(all(target_os = "macos", feature = "force-openssl"), ignore)]
fn wrong_host() {
    assert_wrong_host(&get_host("wrong.host.badssl.com"))
}

#[test]
fn self_signed() {
    assert_self_signed(&get_host("self-signed.badssl.com"))
}

#[test]
fn untrusted_root() {
    assert_untrusted_root(&get_host("untrusted-root.badssl.com"))
}
<commit_msg>Fix a test on Windows<commit_after>extern crate futures;
extern crate env_logger;
extern crate futures_mio;
extern crate futures_tls;

#[macro_use]
extern crate cfg_if;

use std::io::Error;
use std::net::ToSocketAddrs;

use futures::Future;
use futures_tls::ClientContext;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

cfg_if! {
    if #[cfg(any(feature = "force-openssl",
                 all(not(target_os = "macos"),
                     not(target_os = "windows"))))] {
        extern crate openssl;

        use openssl::ssl;

        fn get(err: &Error) -> &openssl::error::ErrorStack {
            let err = err.get_ref().unwrap();
            match *err.downcast_ref::<ssl::error::Error>().unwrap() {
                ssl::Error::Ssl(ref v) => v,
                ref e => panic!("not an ssl eror: {:?}", e),
            }
        }

        fn verify_failed(err: &Error) {
            assert!(get(err).errors().iter().any(|e| {
                e.reason() == "certificate verify failed"
            }), "bad errors: {:?}", err);
        }

        use verify_failed as assert_expired_error;
        use verify_failed as assert_wrong_host;
        use verify_failed as assert_self_signed;
        use verify_failed as assert_untrusted_root;
    } else if #[cfg(target_os = "macos")] {
        extern crate security_framework;

        use security_framework::base::Error as SfError;

        fn assert_invalid_cert_chain(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }

        use assert_invalid_cert_chain as assert_expired_error;
        use assert_invalid_cert_chain as assert_wrong_host;
        use assert_invalid_cert_chain as assert_self_signed;
        use assert_invalid_cert_chain as assert_untrusted_root;
    } else {
        extern crate winapi;

        fn assert_expired_error(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_EXPIRED as usize);
        }

        fn assert_wrong_host(err: &Error) {
            let code = err.raw_os_error().unwrap() as usize;
            // TODO: this... may be a bug in schannel-rs
            assert!(code == winapi::CERT_E_CN_NO_MATCH as usize ||
                    code == winapi::SEC_E_MESSAGE_ALTERED as usize,
                    "bad error code: {:x}", code);
        }

        fn assert_self_signed(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_UNTRUSTEDROOT as usize);
        }

        fn assert_untrusted_root(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_UNTRUSTEDROOT as usize);
        }
    }
}

fn get_host(host: &'static str) -> Error {
    drop(env_logger::init());

    let addr = format!("{}:443", host);
    let addr = t!(addr.to_socket_addrs()).next().unwrap();

    let mut l = t!(futures_mio::Loop::new());
    let client = l.handle().tcp_connect(&addr);
    let data = client.and_then(move |socket| {
        t!(ClientContext::new()).handshake(host, socket)
    });

    let res = l.run(data);
    assert!(res.is_err());
    res.err().unwrap()
}

#[test]
fn expired() {
    assert_expired_error(&get_host("expired.badssl.com"))
}

// TODO: the OSX builders on Travis apparently fail this tests spuriously?
//       passes locally though? Seems... bad!
#[test]
#[cfg_attr(all(target_os = "macos", feature = "force-openssl"), ignore)]
fn wrong_host() {
    assert_wrong_host(&get_host("wrong.host.badssl.com"))
}

#[test]
fn self_signed() {
    assert_self_signed(&get_host("self-signed.badssl.com"))
}

#[test]
fn untrusted_root() {
    assert_untrusted_root(&get_host("untrusted-root.badssl.com"))
}
<|endoftext|>


<commit_before>use memory::MemSegment;
use cart::{Cart, ScreenMode};
use std::rc::Rc;
use std::cell::RefCell;
use super::Color;
use super::PaletteIndex;
use super::TilePattern;

/// Represents the PPU's memory map.
pub struct PPUMemory {
    cart: Rc<RefCell<Cart>>,
    vram: [u8; 0x0F00],
    palette: [Color; 0x20],
}

fn get_nametable_addrs(mode: ScreenMode) -> [u16; 4] {
    match mode {
        ScreenMode::Vertical => [0x2000, 0x2400, 0x2000, 0x2400],
        ScreenMode::Horizontal => [0x2000, 0x2000, 0x2400, 0x2400],
        ScreenMode::OneScreenLow => [0x2000, 0x2000, 0x2000, 0x2000],
        ScreenMode::OneScreenHigh => [0x2400, 0x2400, 0x2400, 0x2400],
        ScreenMode::FourScreen => [0x2000, 0x2400, 0x2800, 0x2C00],
    }
}

impl PPUMemory {
    pub fn new(cart: Rc<RefCell<Cart>>) -> PPUMemory {
        PPUMemory {
            cart: cart,
            vram: [0u8; 0x0F00],
            palette: [Color::from_bits_truncate(0); 0x20],
        }
    }
}

fn get_tile_addr(tile_id: u8, plane: u8, fine_y_scroll: u16, tile_table: u16) -> u16 {
    let mut tile_addr = 0u16;
    tile_addr |= fine_y_scroll;
    tile_addr |= plane as u16; //Plane must be 0 for low or 8 for high
    tile_addr |= (tile_id as u16) << 4;
    tile_addr |= tile_table; //Table must be 0x0000 or 0x1000
    tile_addr
}

impl PPUMemory {
    pub fn read_bypass_palette(&mut self, idx: u16) -> u8 {
        let idx = self.translate_vram_address(idx);
        self.vram[idx]
    }

    fn translate_vram_address(&self, idx: u16) -> usize {
        let idx = idx & 0x0FFF;
        let nametable_num = (idx / 0x0400) as usize;
        let idx_in_nametable = idx % 0x400;
        let mode = self.cart.borrow().get_mirroring_mode();
        let translated = get_nametable_addrs(mode)[nametable_num] + idx_in_nametable;
        translated as usize % self.vram.len()
    }

    pub fn read_palette(&mut self, idx: PaletteIndex) -> Color {
        self.read_palette_mem(idx.to_addr() as usize)
    }

    fn read_palette_mem(&self, idx: usize) -> Color {
        match (idx & 0x1F) as usize {
            0x10 => self.palette[0x00],
            0x14 => self.palette[0x04],
            0x18 => self.palette[0x08],
            0x1C => self.palette[0x0C],
            x => self.palette[x],
        }
    }

    pub fn read_tile_pattern(&mut self,
                             tile_id: u8,
                             fine_y_scroll: u16,
                             tile_table: u16)
                             -> TilePattern {
        let lo_addr = get_tile_addr(tile_id, 0, fine_y_scroll, tile_table);
        let hi_addr = get_tile_addr(tile_id, 8, fine_y_scroll, tile_table);
        TilePattern {
            lo: self.read(lo_addr),
            hi: self.read(hi_addr),
        }
    }

    #[allow(dead_code)]
    pub fn dump_nametable(&mut self, idx: u16) {
        let start_idx = 0x2000 + (idx * 0x400);
        println!("Nametable {}:", idx);
        self.print_columns(start_idx..(start_idx + 0x3C0), 32)
    }

    #[allow(dead_code)]
    pub fn dump_attribute_table(&mut self, idx: u16) {
        let start_idx = 0x2000 + (idx * 0x400);
        println!("Attribute table {}:", idx);
        self.print_columns((start_idx + 0x3C0)..(start_idx + 0x400), 32);
    }
}

impl MemSegment for PPUMemory {
    fn read(&mut self, idx: u16) -> u8 {
        match idx {
            0x0000...0x1FFF => {
                let mut cart = self.cart.borrow_mut();
                cart.chr_read(idx)
            }
            0x2000...0x3EFF => self.read_bypass_palette(idx),
            0x3F00...0x3FFF => self.read_palette_mem(idx as usize).bits(),
            x => invalid_address!(x),
        }
    }

    fn write(&mut self, idx: u16, val: u8) {
        match idx {
            0x0000...0x1FFF => {
                let mut cart = self.cart.borrow_mut();
                cart.chr_write(idx, val)
            }
            0x2000...0x3EFF => {
                let idx = self.translate_vram_address(idx);
                self.vram[idx] = val;
            }
            0x3F00...0x3FFF => {
                let val = Color::from_bits_truncate(val);
                match (idx & 0x001F) as usize {
                    0x10 => self.palette[0x00] = val,
                    0x14 => self.palette[0x04] = val,
                    0x18 => self.palette[0x08] = val,
                    0x1C => self.palette[0x0C] = val,
                    x => self.palette[x] = val,
                }
            }
            x => invalid_address!(x),
        }
    }
}

#[cfg(test)]
mod tests {
    use memory::MemSegment;
    use ppu::tests::*;
    use ppu::{Color, PPU};
    use cart::ScreenMode;

    #[test]
    fn ppu_can_read_write_palette() {
        let mut ppu = create_test_ppu();

        ppu.reg.v = 0x3F00;
        ppu.write(0x2007, 12);
        ppu.reg.v = 0x3F00;
        assert_eq!(ppu.ppu_mem.palette[0], Color::from_bits_truncate(12));

        ppu.reg.v = 0x3F01;
        ppu.write(0x2007, 212);
        ppu.reg.v = 0x3F01;
        assert_eq!(ppu.read(0x2007), 212 & 0x3F);
    }

    #[test]
    fn test_palette_mirroring() {
        let mut ppu = create_test_ppu();

        let mirrors = [0x3F10, 0x3F14, 0x3F18, 0x3F1C];
        let targets = [0x3F00, 0x3F04, 0x3F08, 0x3F0C];
        for x in 0..4 {

            ppu.reg.v = targets[x];
            ppu.write(0x2007, 12);
            ppu.reg.v = mirrors[x];
            assert_eq!(ppu.read(0x2007), 12);

            ppu.reg.v = mirrors[x];
            ppu.write(0x2007, 12);
            ppu.reg.v = targets[x];
            assert_eq!(ppu.read(0x2007), 12);
        }
    }

    fn to_nametable_idx(idx: u16, tbl: u16) -> u16 {
        0x2000 + (0x0400 * tbl) + idx
    }

    fn assert_mirrored(ppu: &mut PPU, tbl1: u16, tbl2: u16) {
        for idx in 0x0000..0x0400 {
            let tbl1_idx = to_nametable_idx(idx, tbl1);
            let tbl2_idx = to_nametable_idx(idx, tbl2);

            println!("Translated: tbl1: {:04X}, tbl2: {:04X}",
                ppu.ppu_mem.translate_vram_address(tbl1_idx),
                ppu.ppu_mem.translate_vram_address(tbl2_idx),
            );

            ppu.ppu_mem.write(tbl1_idx, 0xFF);
            assert_eq!(0xFF, ppu.ppu_mem.read(tbl2_idx));

            ppu.ppu_mem.write(tbl2_idx, 0x61);
            assert_eq!(0x61, ppu.ppu_mem.read(tbl1_idx));
        }
    }

    fn assert_not_mirrored(ppu: &mut PPU, tbl1: u16, tbl2: u16) {
        for idx in 0x0000..0x0400 {
            let tbl1_idx = to_nametable_idx(idx, tbl1);
            let tbl2_idx = to_nametable_idx(idx, tbl2);

            println!("Translated: tbl1: {:04X}, tbl2: {:04X}",
                ppu.ppu_mem.translate_vram_address(tbl1_idx),
                ppu.ppu_mem.translate_vram_address(tbl2_idx),
            );

            ppu.ppu_mem.write(tbl1_idx, 0x00);
            ppu.ppu_mem.write(tbl2_idx, 0x00);

            ppu.ppu_mem.write(tbl1_idx, 0xFF);
            assert_eq!(0x00, ppu.ppu_mem.read(tbl2_idx));

            ppu.ppu_mem.write(tbl2_idx, 0x61);
            assert_eq!(0xFF, ppu.ppu_mem.read(tbl1_idx));
        }
    }

    #[test]
    fn single_screen_mirroring_mirrors_both_ways() {
        let mut ppu = create_test_ppu_with_mirroring(ScreenMode::OneScreenLow);

        assert_mirrored(&mut ppu, 0, 1);
        assert_mirrored(&mut ppu, 1, 2);
        assert_mirrored(&mut ppu, 2, 3);
    }

    #[test]
    fn four_screen_mirroring_mirrors_both_ways() {
        let mut ppu = create_test_ppu_with_mirroring(ScreenMode::FourScreen);

        assert_not_mirrored(&mut ppu, 0, 1);
        assert_not_mirrored(&mut ppu, 1, 2);
        assert_not_mirrored(&mut ppu, 2, 3);
    }

    #[test]
    fn horizontal_mirroring_mirrors_horizontally() {
        let mut ppu = create_test_ppu_with_mirroring(ScreenMode::Horizontal);

        assert_mirrored(&mut ppu, 0, 1);
        assert_mirrored(&mut ppu, 2, 3);
        assert_not_mirrored(&mut ppu, 0, 2);
        assert_not_mirrored(&mut ppu, 1, 3);
    }

    #[test]
    fn vertical_mirroring_mirrors_vertically() {
        let mut ppu = create_test_ppu_with_mirroring(ScreenMode::Vertical);

        assert_not_mirrored(&mut ppu, 0, 1);
        assert_not_mirrored(&mut ppu, 2, 3);
        assert_mirrored(&mut ppu, 0, 2);
        assert_mirrored(&mut ppu, 1, 3);
    }
}
<commit_msg>Do palette mirroring on write rather than read.<commit_after>use memory::MemSegment;
use cart::{Cart, ScreenMode};
use std::rc::Rc;
use std::cell::RefCell;
use super::Color;
use super::PaletteIndex;
use super::TilePattern;

/// Represents the PPU's memory map.
pub struct PPUMemory {
    cart: Rc<RefCell<Cart>>,
    vram: [u8; 0x0F00],
    palette: [Color; 0x20],
}

fn get_nametable_addrs(mode: ScreenMode) -> [u16; 4] {
    match mode {
        ScreenMode::Vertical => [0x2000, 0x2400, 0x2000, 0x2400],
        ScreenMode::Horizontal => [0x2000, 0x2000, 0x2400, 0x2400],
        ScreenMode::OneScreenLow => [0x2000, 0x2000, 0x2000, 0x2000],
        ScreenMode::OneScreenHigh => [0x2400, 0x2400, 0x2400, 0x2400],
        ScreenMode::FourScreen => [0x2000, 0x2400, 0x2800, 0x2C00],
    }
}

impl PPUMemory {
    pub fn new(cart: Rc<RefCell<Cart>>) -> PPUMemory {
        PPUMemory {
            cart: cart,
            vram: [0u8; 0x0F00],
            palette: [Color::from_bits_truncate(0); 0x20],
        }
    }
}

fn get_tile_addr(tile_id: u8, plane: u8, fine_y_scroll: u16, tile_table: u16) -> u16 {
    let mut tile_addr = 0u16;
    tile_addr |= fine_y_scroll;
    tile_addr |= plane as u16; //Plane must be 0 for low or 8 for high
    tile_addr |= (tile_id as u16) << 4;
    tile_addr |= tile_table; //Table must be 0x0000 or 0x1000
    tile_addr
}

impl PPUMemory {
    pub fn read_bypass_palette(&mut self, idx: u16) -> u8 {
        let idx = self.translate_vram_address(idx);
        self.vram[idx]
    }

    fn translate_vram_address(&self, idx: u16) -> usize {
        let idx = idx & 0x0FFF;
        let nametable_num = (idx / 0x0400) as usize;
        let idx_in_nametable = idx % 0x400;
        let mode = self.cart.borrow().get_mirroring_mode();
        let translated = get_nametable_addrs(mode)[nametable_num] + idx_in_nametable;
        translated as usize % self.vram.len()
    }

    pub fn read_palette(&mut self, idx: PaletteIndex) -> Color {
        self.read_palette_mem(idx.to_addr() as usize)
    }

    fn read_palette_mem(&self, idx: usize) -> Color {
        self.palette[idx & 0x1F]
    }

    pub fn read_tile_pattern(&mut self,
                             tile_id: u8,
                             fine_y_scroll: u16,
                             tile_table: u16)
                             -> TilePattern {
        let lo_addr = get_tile_addr(tile_id, 0, fine_y_scroll, tile_table);
        let hi_addr = get_tile_addr(tile_id, 8, fine_y_scroll, tile_table);
        TilePattern {
            lo: self.read(lo_addr),
            hi: self.read(hi_addr),
        }
    }

    #[allow(dead_code)]
    pub fn dump_nametable(&mut self, idx: u16) {
        let start_idx = 0x2000 + (idx * 0x400);
        println!("Nametable {}:", idx);
        self.print_columns(start_idx..(start_idx + 0x3C0), 32)
    }

    #[allow(dead_code)]
    pub fn dump_attribute_table(&mut self, idx: u16) {
        let start_idx = 0x2000 + (idx * 0x400);
        println!("Attribute table {}:", idx);
        self.print_columns((start_idx + 0x3C0)..(start_idx + 0x400), 32);
    }
}

impl MemSegment for PPUMemory {
    fn read(&mut self, idx: u16) -> u8 {
        match idx {
            0x0000...0x1FFF => {
                let mut cart = self.cart.borrow_mut();
                cart.chr_read(idx)
            }
            0x2000...0x3EFF => self.read_bypass_palette(idx),
            0x3F00...0x3FFF => self.read_palette_mem(idx as usize).bits(),
            x => invalid_address!(x),
        }
    }

    fn write(&mut self, idx: u16, val: u8) {
        match idx {
            0x0000...0x1FFF => {
                let mut cart = self.cart.borrow_mut();
                cart.chr_write(idx, val)
            }
            0x2000...0x3EFF => {
                let idx = self.translate_vram_address(idx);
                self.vram[idx] = val;
            }
            0x3F00...0x3FFF => {
                let val = Color::from_bits_truncate(val);
                let idx = (idx & 0x001F) as usize;
                // Do the palette mirroring on write since we read a lot more than we write.
                // This is not strictly accurate - the PPU can actually render these colors
                // in certain rare circumstances - but it's good enough.
                match idx {
                    0x10 => self.palette[0x00] = val,
                    0x00 => self.palette[0x10] = val,

                    0x14 => self.palette[0x04] = val,
                    0x04 => self.palette[0x14] = val,

                    0x18 => self.palette[0x08] = val,
                    0x08 => self.palette[0x18] = val,

                    0x1C => self.palette[0x0C] = val,
                    0x0C => self.palette[0x1C] = val,

                    _ => (),
                };
                self.palette[idx] = val;
            }
            x => invalid_address!(x),
        }
    }
}

#[cfg(test)]
mod tests {
    use memory::MemSegment;
    use ppu::tests::*;
    use ppu::{Color, PPU};
    use cart::ScreenMode;

    #[test]
    fn ppu_can_read_write_palette() {
        let mut ppu = create_test_ppu();

        ppu.reg.v = 0x3F00;
        ppu.write(0x2007, 12);
        ppu.reg.v = 0x3F00;
        assert_eq!(ppu.ppu_mem.palette[0], Color::from_bits_truncate(12));

        ppu.reg.v = 0x3F01;
        ppu.write(0x2007, 212);
        ppu.reg.v = 0x3F01;
        assert_eq!(ppu.read(0x2007), 212 & 0x3F);
    }

    #[test]
    fn test_palette_mirroring() {
        let mut ppu = create_test_ppu();

        let mirrors = [0x3F10, 0x3F14, 0x3F18, 0x3F1C];
        let targets = [0x3F00, 0x3F04, 0x3F08, 0x3F0C];
        for x in 0..4 {

            ppu.reg.v = targets[x];
            ppu.write(0x2007, 12);
            ppu.reg.v = mirrors[x];
            assert_eq!(ppu.read(0x2007), 12);

            ppu.reg.v = mirrors[x];
            ppu.write(0x2007, 12);
            ppu.reg.v = targets[x];
            assert_eq!(ppu.read(0x2007), 12);
        }
    }

    fn to_nametable_idx(idx: u16, tbl: u16) -> u16 {
        0x2000 + (0x0400 * tbl) + idx
    }

    fn assert_mirrored(ppu: &mut PPU, tbl1: u16, tbl2: u16) {
        for idx in 0x0000..0x0400 {
            let tbl1_idx = to_nametable_idx(idx, tbl1);
            let tbl2_idx = to_nametable_idx(idx, tbl2);

            println!("Translated: tbl1: {:04X}, tbl2: {:04X}",
                ppu.ppu_mem.translate_vram_address(tbl1_idx),
                ppu.ppu_mem.translate_vram_address(tbl2_idx),
            );

            ppu.ppu_mem.write(tbl1_idx, 0xFF);
            assert_eq!(0xFF, ppu.ppu_mem.read(tbl2_idx));

            ppu.ppu_mem.write(tbl2_idx, 0x61);
            assert_eq!(0x61, ppu.ppu_mem.read(tbl1_idx));
        }
    }

    fn assert_not_mirrored(ppu: &mut PPU, tbl1: u16, tbl2: u16) {
        for idx in 0x0000..0x0400 {
            let tbl1_idx = to_nametable_idx(idx, tbl1);
            let tbl2_idx = to_nametable_idx(idx, tbl2);

            println!("Translated: tbl1: {:04X}, tbl2: {:04X}",
                ppu.ppu_mem.translate_vram_address(tbl1_idx),
                ppu.ppu_mem.translate_vram_address(tbl2_idx),
            );

            ppu.ppu_mem.write(tbl1_idx, 0x00);
            ppu.ppu_mem.write(tbl2_idx, 0x00);

            ppu.ppu_mem.write(tbl1_idx, 0xFF);
            assert_eq!(0x00, ppu.ppu_mem.read(tbl2_idx));

            ppu.ppu_mem.write(tbl2_idx, 0x61);
            assert_eq!(0xFF, ppu.ppu_mem.read(tbl1_idx));
        }
    }

    #[test]
    fn single_screen_mirroring_mirrors_both_ways() {
        let mut ppu = create_test_ppu_with_mirroring(ScreenMode::OneScreenLow);

        assert_mirrored(&mut ppu, 0, 1);
        assert_mirrored(&mut ppu, 1, 2);
        assert_mirrored(&mut ppu, 2, 3);
    }

    #[test]
    fn four_screen_mirroring_mirrors_both_ways() {
        let mut ppu = create_test_ppu_with_mirroring(ScreenMode::FourScreen);

        assert_not_mirrored(&mut ppu, 0, 1);
        assert_not_mirrored(&mut ppu, 1, 2);
        assert_not_mirrored(&mut ppu, 2, 3);
    }

    #[test]
    fn horizontal_mirroring_mirrors_horizontally() {
        let mut ppu = create_test_ppu_with_mirroring(ScreenMode::Horizontal);

        assert_mirrored(&mut ppu, 0, 1);
        assert_mirrored(&mut ppu, 2, 3);
        assert_not_mirrored(&mut ppu, 0, 2);
        assert_not_mirrored(&mut ppu, 1, 3);
    }

    #[test]
    fn vertical_mirroring_mirrors_vertically() {
        let mut ppu = create_test_ppu_with_mirroring(ScreenMode::Vertical);

        assert_not_mirrored(&mut ppu, 0, 1);
        assert_not_mirrored(&mut ppu, 2, 3);
        assert_mirrored(&mut ppu, 0, 2);
        assert_mirrored(&mut ppu, 1, 3);
    }
}
<|endoftext|>


<commit_before>use std::os::raw::c_void;
use std::ptr::null_mut;
use raw::{FunctionCallbackInfo, Env, Local};

use nodejs_sys as napi;

#[repr(C)]
pub struct CCallback {
    pub static_callback: *mut c_void,
    pub dynamic_callback: *mut c_void
}

impl Default for CCallback {
    fn default() -> Self {
        CCallback {
            static_callback: null_mut(),
            dynamic_callback: null_mut()
        }
    }
}

pub unsafe extern "C" fn set_return(_info: FunctionCallbackInfo, _value: Local) {

}

pub unsafe extern "C" fn get_isolate(info: FunctionCallbackInfo) -> Env { unimplemented!() }

// FIXME: Remove. This will never be implemented
pub unsafe extern "C" fn current_isolate() -> Env { panic!("current_isolate won't be implemented in n-api") }

pub unsafe extern "C" fn is_construct(_info: FunctionCallbackInfo) -> bool { unimplemented!() }

pub unsafe extern "C" fn this(env: Env, info: FunctionCallbackInfo, out: &mut Local) {
    let status = napi::napi_get_cb_info(
        env,
        info,
        null_mut(),
        null_mut(),
        out as *mut _,
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
}

/// Mutates the `out` argument provided to refer to the associated data value of the
/// `napi_callback_info`.
pub unsafe extern "C" fn data(env: Env, info: FunctionCallbackInfo, out: &mut *mut c_void) {
    let mut data = null_mut();
    let status = napi::napi_get_cb_info(
        env,
        info,
        null_mut(),
        null_mut(),
        null_mut(),
        &mut data as *mut _,
    );
    if status == napi::napi_status::napi_ok {
        *out = data;
    }
}

/// Gets the number of arguments passed to the function.
pub unsafe extern "C" fn len(env: Env, info: FunctionCallbackInfo) -> i32 {
    let mut argc = 0usize;
    let status = napi::napi_get_cb_info(
        env,
        info,
        &mut argc as *mut _,
        null_mut(),
        null_mut(),
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
    argc as i32
}

/// Mutates the `out` argument provided to refer to the `napi_value` of the `i`th argument
/// passed to the function.
pub unsafe extern "C" fn get(env: Env, info: FunctionCallbackInfo, i: i32, out: &mut Local) {
    // TODO make this not allocate
    // Instead, we can probably get all the arguments at once in `neon` itself?
    let mut args = vec![null_mut(); (i + 1) as usize];
    let mut num_args = args.len();

    let status = napi::napi_get_cb_info(
        env,
        info,
        &mut num_args as *mut _,
        args.as_mut_ptr(),
        null_mut(),
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
    assert!(num_args > i as usize);
    *out = args[i as usize];
}
<commit_msg>reference TODO issue<commit_after>use std::os::raw::c_void;
use std::ptr::null_mut;
use raw::{FunctionCallbackInfo, Env, Local};

use nodejs_sys as napi;

#[repr(C)]
pub struct CCallback {
    pub static_callback: *mut c_void,
    pub dynamic_callback: *mut c_void
}

impl Default for CCallback {
    fn default() -> Self {
        CCallback {
            static_callback: null_mut(),
            dynamic_callback: null_mut()
        }
    }
}

pub unsafe extern "C" fn set_return(_info: FunctionCallbackInfo, _value: Local) {

}

pub unsafe extern "C" fn get_isolate(info: FunctionCallbackInfo) -> Env { unimplemented!() }

// FIXME: Remove. This will never be implemented
pub unsafe extern "C" fn current_isolate() -> Env { panic!("current_isolate won't be implemented in n-api") }

pub unsafe extern "C" fn is_construct(_info: FunctionCallbackInfo) -> bool { unimplemented!() }

pub unsafe extern "C" fn this(env: Env, info: FunctionCallbackInfo, out: &mut Local) {
    let status = napi::napi_get_cb_info(
        env,
        info,
        null_mut(),
        null_mut(),
        out as *mut _,
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
}

/// Mutates the `out` argument provided to refer to the associated data value of the
/// `napi_callback_info`.
pub unsafe extern "C" fn data(env: Env, info: FunctionCallbackInfo, out: &mut *mut c_void) {
    let mut data = null_mut();
    let status = napi::napi_get_cb_info(
        env,
        info,
        null_mut(),
        null_mut(),
        null_mut(),
        &mut data as *mut _,
    );
    if status == napi::napi_status::napi_ok {
        *out = data;
    }
}

/// Gets the number of arguments passed to the function.
pub unsafe extern "C" fn len(env: Env, info: FunctionCallbackInfo) -> i32 {
    let mut argc = 0usize;
    let status = napi::napi_get_cb_info(
        env,
        info,
        &mut argc as *mut _,
        null_mut(),
        null_mut(),
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
    argc as i32
}

/// Mutates the `out` argument provided to refer to the `napi_value` of the `i`th argument
/// passed to the function.
pub unsafe extern "C" fn get(env: Env, info: FunctionCallbackInfo, i: i32, out: &mut Local) {
    // TODO make this not allocate: https://github.com/neon-bindings/neon/issues/530
    // Instead, we can probably get all the arguments at once in `neon` itself?
    let mut args = vec![null_mut(); (i + 1) as usize];
    let mut num_args = args.len();

    let status = napi::napi_get_cb_info(
        env,
        info,
        &mut num_args as *mut _,
        args.as_mut_ptr(),
        null_mut(),
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
    assert!(num_args > i as usize);
    *out = args[i as usize];
}
<|endoftext|>


<commit_before>#[path="../src/grammar.rs"]
mod grammar;
#[path="../src/parser.rs"]
mod parser;
#[path="../src/codegen.rs"]
mod codegen;
#[path="../src/lexicon.rs"]
mod lexicon;
#[path="../src/tokenizer.rs"]
mod tokenizer;

fn output_program(input_program: &str) -> Result<String, Vec<String>> {
    let program = parser::parse(input_program.into());
    codegen::generate_code(program)
}

#[test]
fn convert_const_str_to_var() {
    assert_eq!(output_program("const foo = \"bar\";"), Ok("var foo = \"bar\";".into()));
}

#[test]
fn convert_var_str_to_var() {
    assert_eq!(output_program("var foo = \"bar\";"), Ok("var foo = \"bar\";".into()));
}
<commit_msg>add tests for more literal values<commit_after>#[path="../src/grammar.rs"]
mod grammar;
#[path="../src/parser.rs"]
mod parser;
#[path="../src/codegen.rs"]
mod codegen;
#[path="../src/lexicon.rs"]
mod lexicon;
#[path="../src/tokenizer.rs"]
mod tokenizer;

fn output_program(input_program: &str) -> Result<String, Vec<String>> {
    let program = parser::parse(input_program.into());
    codegen::generate_code(program)
}

#[test]
fn convert_const_str_to_var() {
    assert_eq!(output_program("const foo = \"bar\";"), Ok("var foo = \"bar\";".into()));
}

#[test]
fn convert_var_str_to_var() {
    assert_eq!(output_program("var foo = \"bar\";"), Ok("var foo = \"bar\";".into()));
}

#[test]
fn convert_const_number_to_var() {
    assert_eq!(output_program("const foo = 435;"), Ok("var foo = 435;".into()));
}

#[test]
fn convert_const_true_to_var() {
    assert_eq!(output_program("const foo = true;"), Ok("var foo = true;".into()));
}

#[test]
fn convert_const_false_to_var() {
    assert_eq!(output_program("const foo = false;"), Ok("var foo = false;".into()));
}

#[test]
fn convert_const_null_to_var() {
    assert_eq!(output_program("const foo = null;"), Ok("var foo = null;".into()));
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

extern crate clap;
extern crate clippy_dev;
extern crate regex;

use clap::{App, Arg, SubCommand};
use clippy_dev::*;

fn main() {
    let matches = App::new("Clippy developer tooling")
        .subcommand(
            SubCommand::with_name("update_lints")
                .about("Makes sure that:\n \
                       * the lint count in README.md is correct\n \
                       * the changelog contains markdown link references at the bottom\n \
                       * all lints groups include the correct lints\n \
                       * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
                       * all lints are registered in the lint store")
                .arg(
                    Arg::with_name("print-only")
                        .long("print-only")
                        .short("p")
                        .help("Print a table of lints to STDOUT. This does not include deprecated and internal lints. (Does not modify any files)"),
                )
        )
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("update_lints") {
        if matches.is_present("print-only") {
            print_lints();
        } else {
            update_lints();
        }
    }
}

fn print_lints() {
    let lint_list = gather_all();
    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list).collect();
    let lint_count = usable_lints.len();
    let grouped_by_lint_group = Lint::by_lint_group(&usable_lints);

    for (lint_group, mut lints) in grouped_by_lint_group {
        if lint_group == "Deprecated" { continue; }
        println!("\n## {}", lint_group);

        lints.sort_by_key(|l| l.name.clone());

        for lint in lints {
            println!("* [{}]({}#{}) ({})", lint.name, clippy_dev::DOCS_LINK.clone(), lint.name, lint.desc);
        }
    }

    println!("there are {} lints", lint_count);
}

fn update_lints() {
    let lint_list: Vec<Lint> = gather_all().collect();
    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
    let lint_count = usable_lints.len();

    replace_region_in_file(
        "../README.md",
        r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang-nursery.github.io/rust-clippy/master/index.html\)"#,
        "",
        true,
        || {
            vec![
                format!("[There are {} lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)", lint_count)
            ]
        }
    );

    replace_region_in_file(
        "../CHANGELOG.md",
        "<!-- begin autogenerated links to lint list -->",
        "<!-- end autogenerated links to lint list -->",
        false,
        || { gen_changelog_lint_list(lint_list.clone()) }
    );

    replace_region_in_file(
        "../clippy_lints/src/lib.rs",
        "begin deprecated lints",
        "end deprecated lints",
        false,
        || { gen_deprecated(&lint_list) }
    );

    replace_region_in_file(
        "../clippy_lints/src/lib.rs",
        "begin lints modules",
        "end lints modules",
        false,
        || { gen_modules_list(lint_list.clone()) }
    );

    // Generate lists of lints in the clippy::all lint group
    replace_region_in_file(
        "../clippy_lints/src/lib.rs",
        r#"reg.register_lint_group\("clippy::all""#,
        r#"\]\);"#,
        false,
        || {
            // clippy::all should only include the following lint groups:
            let all_group_lints = usable_lints.clone().into_iter().filter(|l| {
                l.group == "correctness" ||
                  l.group == "style" ||
                  l.group == "complexity" ||
                  l.group == "perf"
            }).collect();

            gen_lint_group_list(all_group_lints)
        }
    );

    // Generate the list of lints for all other lint groups
    for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
        replace_region_in_file(
            "../clippy_lints/src/lib.rs",
            &format!("reg.register_lint_group\\(\"clippy::{}\"", lint_group),
            r#"\]\);"#,
            false,
            || { gen_lint_group_list(lints.clone()) }
        );
    }
}
<commit_msg>Fix typo<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

extern crate clap;
extern crate clippy_dev;
extern crate regex;

use clap::{App, Arg, SubCommand};
use clippy_dev::*;

fn main() {
    let matches = App::new("Clippy developer tooling")
        .subcommand(
            SubCommand::with_name("update_lints")
                .about("Makes sure that:\n \
                       * the lint count in README.md is correct\n \
                       * the changelog contains markdown link references at the bottom\n \
                       * all lint groups include the correct lints\n \
                       * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
                       * all lints are registered in the lint store")
                .arg(
                    Arg::with_name("print-only")
                        .long("print-only")
                        .short("p")
                        .help("Print a table of lints to STDOUT. This does not include deprecated and internal lints. (Does not modify any files)"),
                )
        )
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("update_lints") {
        if matches.is_present("print-only") {
            print_lints();
        } else {
            update_lints();
        }
    }
}

fn print_lints() {
    let lint_list = gather_all();
    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list).collect();
    let lint_count = usable_lints.len();
    let grouped_by_lint_group = Lint::by_lint_group(&usable_lints);

    for (lint_group, mut lints) in grouped_by_lint_group {
        if lint_group == "Deprecated" { continue; }
        println!("\n## {}", lint_group);

        lints.sort_by_key(|l| l.name.clone());

        for lint in lints {
            println!("* [{}]({}#{}) ({})", lint.name, clippy_dev::DOCS_LINK.clone(), lint.name, lint.desc);
        }
    }

    println!("there are {} lints", lint_count);
}

fn update_lints() {
    let lint_list: Vec<Lint> = gather_all().collect();
    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
    let lint_count = usable_lints.len();

    replace_region_in_file(
        "../README.md",
        r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang-nursery.github.io/rust-clippy/master/index.html\)"#,
        "",
        true,
        || {
            vec![
                format!("[There are {} lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)", lint_count)
            ]
        }
    );

    replace_region_in_file(
        "../CHANGELOG.md",
        "<!-- begin autogenerated links to lint list -->",
        "<!-- end autogenerated links to lint list -->",
        false,
        || { gen_changelog_lint_list(lint_list.clone()) }
    );

    replace_region_in_file(
        "../clippy_lints/src/lib.rs",
        "begin deprecated lints",
        "end deprecated lints",
        false,
        || { gen_deprecated(&lint_list) }
    );

    replace_region_in_file(
        "../clippy_lints/src/lib.rs",
        "begin lints modules",
        "end lints modules",
        false,
        || { gen_modules_list(lint_list.clone()) }
    );

    // Generate lists of lints in the clippy::all lint group
    replace_region_in_file(
        "../clippy_lints/src/lib.rs",
        r#"reg.register_lint_group\("clippy::all""#,
        r#"\]\);"#,
        false,
        || {
            // clippy::all should only include the following lint groups:
            let all_group_lints = usable_lints.clone().into_iter().filter(|l| {
                l.group == "correctness" ||
                  l.group == "style" ||
                  l.group == "complexity" ||
                  l.group == "perf"
            }).collect();

            gen_lint_group_list(all_group_lints)
        }
    );

    // Generate the list of lints for all other lint groups
    for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
        replace_region_in_file(
            "../clippy_lints/src/lib.rs",
            &format!("reg.register_lint_group\\(\"clippy::{}\"", lint_group),
            r#"\]\);"#,
            false,
            || { gen_lint_group_list(lints.clone()) }
        );
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;

use collections::*;

#[derive(Clone,Copy,Hash,Eq,PartialEq,Debug)]
pub enum Op { Plus, Minus, Times, Divide }

#[derive(Clone,Copy,Hash,Eq,PartialEq,Debug)]
pub enum Tok {
  Num(isize),
  Op(Op)
}

pub enum Precedence { Higher, Lower, Equal }

fn pop<X:Clone+Copy+Hash+Eq+PartialEq+Debug>
  (stack:List<X>) -> (X, List<X>) {
    List::elim_arg(stack, (),
                   |_,_|    panic!("cannot pop an empty stack"),
                   |h,t, _| (h, t),
                   |_,t, _| pop(t))
}

fn push<X:Clone+Copy+Hash+Eq+PartialEq+Debug>
  (stack:List<X>, elm:X) -> List<X>
{
  List::cons(elm, stack)
}

fn precedence_check (top_op:&Op, next_op:&Op) -> Precedence {
  match (*top_op, *next_op) {
    (Op::Plus, Op::Plus) => Precedence::Equal,
    (Op::Plus, Op::Minus) => Precedence::Equal,
    (Op::Minus, Op::Plus) => Precedence::Equal,
    (Op::Minus, Op::Minus) => Precedence::Equal,

    (Op::Times, Op::Times) => Precedence::Equal,
    (Op::Divide, Op::Divide) => Precedence::Equal,

    (Op::Times, Op::Plus)   => Precedence::Higher,
    (Op::Times, Op::Minus)  => Precedence::Higher,
    (Op::Times, Op::Divide) => Precedence::Higher,

    (Op::Divide, Op::Plus)  => Precedence::Higher,
    (Op::Divide, Op::Minus) => Precedence::Higher,
    (Op::Divide, Op::Times) => Precedence::Higher,
    _ => Precedence::Lower
  }
}

pub fn check_ops_rec (ops:List<Op>, op:Op) -> bool {
  if List::is_empty(&ops) { true }
  else {
    let (top_op, popped_ops) = pop(ops);
    match precedence_check(&op, &top_op) {
      Precedence::Higher => check_ops_rec(popped_ops, top_op),
      _ => false
    }
  }
}

pub fn check_ops (ops:List<Op>) -> bool {
  if List::is_empty(&ops) { true }
  else {
    let (top_op, popped_ops) = pop(ops);
    check_ops_rec(popped_ops, top_op)
  }
}

pub fn postfix_of_infix(infix: Tree<Tok>) -> List<Tok> {
  let (ops, postfix) : (List<Op>, List<Tok>) =
    tree_fold_seq
    (infix, Dir2::Left, (List::Nil, List::Nil),
     Rc::new(|tok, (ops, postfix) : (List<Op>, List<Tok>)| {
       assert!(check_ops(ops.clone()));
       match tok {
         Tok::Num(n) => (ops, push(postfix, Tok::Num(n))),
         Tok::Op(op) => {
           if List::is_empty(&ops) { (push(ops, op), postfix) }
           else {
             fn myloop (op:Op, ops:List<Op>, postfix:List<Tok>) -> (List<Op>, List<Tok>) {
               if List::is_empty(&ops) { (ops, postfix) } else {
                 let (top_op, popped_ops) = pop(ops);
                 match precedence_check (&top_op, &op) {
                   Precedence::Higher => { myloop (op, popped_ops, push(postfix, Tok::Op(top_op)))},
		   Precedence::Equal => {(popped_ops, push(postfix, Tok::Op(top_op)))},
                   _ => {(push(popped_ops, top_op), postfix)}
                 }
               }};
             let (ops, postfix) = myloop(op, ops, postfix) ;
             (push(ops, op), postfix)
           }
         }
       }}),
     Rc::new(|_, a|   a),
     Rc::new(|_,_, a| a),
     );
  fn myloop (ops:List<Op>, postfix:List<Tok>) -> (List<Tok>) {
    if List::is_empty(&ops) { postfix } else {
      let (top_op, popped_ops) = pop(ops);
      myloop (popped_ops, push(postfix, Tok::Op(top_op)))
    }};
  myloop(ops, postfix)
}

#[test]
fn test_postfix_of_infix () {

  // 1 * 2 + 3
  let input = vec![
    NameElse::Else( Tok::Num(1) ),
    NameElse::Else( Tok::Op(Op::Times) ),
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Num(3) ),
    ];
  let input : List<Tok> = list_of_vec(&input);
  let tree  : Tree<Tok> = tree_of_list(Dir2::Left, input);
  let ans = postfix_of_infix(tree);
  println!("{:?}", ans)
}

pub fn evaluate_postfix(input: Tree<Tok>) -> isize {
  let stack =
    tree_fold_seq
    (input, Dir2::Left, List::Nil,
     Rc::new(|tok, stack| {
       match tok {
         Tok::Op(op) => {
           let (x,stack) = pop(stack);
           let (y,stack) = pop(stack);
           let z = match op {
             Op::Plus   => y + x,
             Op::Minus  => y - x,
             Op::Times  => y * x,
             Op::Divide => y / x,
           };
           push(stack, z)
         },
         Tok::Num(n) => {
           push(stack, n)
         }
       }}),
     Rc::new(|_, stack|   stack),
     Rc::new(|_,_, stack| stack),
     );
  let (x, stack) = pop(stack);
  assert!(List::is_empty(&stack));
  x
}

#[test]
fn test_eval_postfix () {
  let input = vec![
    NameElse::Else( Tok::Num(1) ),
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Num(3) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Num(22) ),
    NameElse::Else( Tok::Num(33) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Num(12) ),
    NameElse::Else( Tok::Num(13) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    ];
  let input : List<Tok> = list_of_vec(&input);
  let tree  : Tree<Tok> = tree_of_list(Dir2::Left, input);
  let ans = evaluate_postfix(tree);
  assert_eq!(ans, 86)
}

#[test]
fn test_arith_eval () {

  // 1 * 2 + 3
  let input = vec![
    NameElse::Else( Tok::Num(1) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Op(Op::Minus) ),
    NameElse::Else( Tok::Num(3) ),
    NameElse::Else( Tok::Op(Op::Minus) ),
    NameElse::Else( Tok::Num(1) ),
    NameElse::Else( Tok::Op(Op::Minus) ),
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Op(Op::Times) ),
    NameElse::Else( Tok::Num(2) ),
    // NameElse::Else( Tok::Op(Op::Divide) ),
    // NameElse::Else( Tok::Num(2) ),
    // NameElse::Else( Tok::Op(Op::Minus) ),
    // NameElse::Else( Tok::Num(3) ),
    ];
  println!("{:?}", &input);
  let input : List<Tok> = list_of_vec(&input);
  let tree  : Tree<Tok> = tree_of_list(Dir2::Left, input);
  let list  : List<Tok> = postfix_of_infix(tree);
  println!("{:?}", &list);
  //let input : List<Tok> = list_of_vec(&input);
  let tree  : Tree<Tok> = tree_of_list(Dir2::Right, list);
  let ans = evaluate_postfix(tree);
  println!("{:?}", ans)
}

// fn infix_to_postfix(input: List<char>) -> List<List<char>> {
//   let mut postfix = List::Nil;
//   let mut operators = List::Nil;
//   let mut temp_operand = List::Nil;

//   //'''
//   // Match all chars in 'input'
//   //     If c is a digit, then push onto a Digit list temporarily until all digits in an operand are read (after which add the operand to the Postfix list)
//   //     If c is an operator, pop everything of higher predence and add it to postfix list, then add c to list of Operators
//   //'''
//   postfix
// }

// fn evaluate_postfix(input: List<List<char>>) -> i32 {

//   //'''
//   // Convert list to number and apply operation on two at a time
//   //'''

// }

// fn test_arith_parse() {
//   println!("Enter expression in infix format");
//   let mut input = String::new();
//   io::stdin().read_line(&mut input).ok().expect("Failed to parse input");

//   // '''
//   // Convert string to List<char> (reverse order)
//   // '''
//   let input_list = panic!("");

//   let postfix_expr = infix_to_postfix(input_list);
//   let result = evaluate_postfix(postfix_expr);
// }

<commit_msg>Add ParanOpen and ParenClose ops, test_paren_eval, comment out invariant check<commit_after>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;

use collections::*;

#[derive(Clone,Copy,Hash,Eq,PartialEq,Debug)]
pub enum Op { Plus, Minus, Times, Divide, ParanOpen, ParanClose }

#[derive(Clone,Copy,Hash,Eq,PartialEq,Debug)]
pub enum Tok {
  Num(isize),
  Op(Op)
}

pub enum Precedence { Higher, Lower, Equal }

fn pop<X:Clone+Copy+Hash+Eq+PartialEq+Debug>
  (stack:List<X>) -> (X, List<X>) {
    List::elim_arg(stack, (),
                   |_,_|    panic!("cannot pop an empty stack"),
                   |h,t, _| (h, t),
                   |_,t, _| pop(t))
}

fn push<X:Clone+Copy+Hash+Eq+PartialEq+Debug>
  (stack:List<X>, elm:X) -> List<X>
{
  List::cons(elm, stack)
}

fn precedence_check (top_op:&Op, next_op:&Op) -> Precedence {
  match (*top_op, *next_op) {
    (Op::Plus, Op::Plus) => Precedence::Equal,
    (Op::Plus, Op::Minus) => Precedence::Equal,
    (Op::Minus, Op::Plus) => Precedence::Equal,
    (Op::Minus, Op::Minus) => Precedence::Equal,

    (Op::Times, Op::Times) => Precedence::Equal,
    (Op::Divide, Op::Divide) => Precedence::Equal,

    (Op::Times, Op::Plus)   => Precedence::Higher,
    (Op::Times, Op::Minus)  => Precedence::Higher,
    (Op::Times, Op::Divide) => Precedence::Higher,

    (Op::Divide, Op::Plus)  => Precedence::Higher,
    (Op::Divide, Op::Minus) => Precedence::Higher,
    (Op::Divide, Op::Times) => Precedence::Higher,
    _ => Precedence::Lower
  }
}

pub fn check_ops_rec (ops:List<Op>, op:Op) -> bool {
  if List::is_empty(&ops) { true }
  else {
    let (top_op, popped_ops) = pop(ops);
    match precedence_check(&op, &top_op) {
      Precedence::Higher => check_ops_rec(popped_ops, top_op),
      _ => false
    }
  }
}

pub fn check_ops (ops:List<Op>) -> bool {
  if List::is_empty(&ops) { true }
  else {
    let (top_op, popped_ops) = pop(ops);
    check_ops_rec(popped_ops, top_op)
  }
}

pub fn postfix_of_infix(infix: Tree<Tok>) -> List<Tok> {
  let (ops, postfix) : (List<Op>, List<Tok>) =
    tree_fold_seq
    (infix, Dir2::Left, (List::Nil, List::Nil),
     Rc::new(|tok, (ops, postfix) : (List<Op>, List<Tok>)| {
       //assert!(check_ops(ops.clone()));
       match tok {
         Tok::Num(n) => (ops, push(postfix, Tok::Num(n))),
         Tok::Op(op) => {
           match op {
	    Op::ParanOpen => {(push(ops, op), postfix)}
            Op::ParanClose => {
              fn myloop (op:Op, ops:List<Op>, postfix:List<Tok>) -> (List<Op>, List<Tok>) {
                let (top_op, popped_ops) = pop(ops);
		match top_op {
		  Op::ParanOpen => {print!("hello");(popped_ops, postfix)},
                  _ => {myloop(op, popped_ops, push(postfix, Tok::Op(top_op)))},
                }
	      };
              myloop(op, ops, postfix)
	    }
	    _ => {
             if List::is_empty(&ops) { (push(ops, op), postfix) }
             else {
               fn myloop (op:Op, ops:List<Op>, postfix:List<Tok>) -> (List<Op>, List<Tok>) {
                 if List::is_empty(&ops) { (ops, postfix) } else {
                   let (top_op, popped_ops) = pop(ops);
                   match precedence_check (&top_op, &op) {
                     Precedence::Higher => { myloop (op, popped_ops, push(postfix, Tok::Op(top_op)))},
	             Precedence::Equal => {(popped_ops, push(postfix, Tok::Op(top_op)))},
                     _ => {(push(popped_ops, top_op), postfix)}
                   }
                 }};
               let (ops, postfix) = myloop(op, ops, postfix) ;
               (push(ops, op), postfix)
             }
           }}
         }
       }}),
     Rc::new(|_, a|   a),
     Rc::new(|_,_, a| a),
     );
  fn myloop (ops:List<Op>, postfix:List<Tok>) -> (List<Tok>) {
    if List::is_empty(&ops) { postfix } else {
      let (top_op, popped_ops) = pop(ops);
      myloop (popped_ops, push(postfix, Tok::Op(top_op)))
    }};
  myloop(ops, postfix)
}

#[test]
fn test_postfix_of_infix () {

  // 1 * 2 + 3
  let input = vec![
    NameElse::Else( Tok::Num(1) ),
    NameElse::Else( Tok::Op(Op::Times) ),
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Num(3) ),
    ];
  let input : List<Tok> = list_of_vec(&input);
  let tree  : Tree<Tok> = tree_of_list(Dir2::Left, input);
  let ans = postfix_of_infix(tree);
  println!("{:?}", ans)
}

pub fn evaluate_postfix(input: Tree<Tok>) -> isize {
  let stack =
    tree_fold_seq
    (input, Dir2::Left, List::Nil,
     Rc::new(|tok, stack| {
       match tok {
         Tok::Op(op) => {
           let (x,stack) = pop(stack);
           let (y,stack) = pop(stack);
           let z = match op {
             Op::Plus   => y + x,
             Op::Minus  => y - x,
             Op::Times  => y * x,
             Op::Divide => y / x,
	     _ => panic!(),
           };
           push(stack, z)
         },
         Tok::Num(n) => {
           push(stack, n)
         }
       }}),
     Rc::new(|_, stack|   stack),
     Rc::new(|_,_, stack| stack),
     );
  let (x, stack) = pop(stack);
  assert!(List::is_empty(&stack));
  x
}

#[test]
fn test_eval_postfix () {
  let input = vec![
    NameElse::Else( Tok::Num(1) ),
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Num(3) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Num(22) ),
    NameElse::Else( Tok::Num(33) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Num(12) ),
    NameElse::Else( Tok::Num(13) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    ];
  let input : List<Tok> = list_of_vec(&input);
  let tree  : Tree<Tok> = tree_of_list(Dir2::Left, input);
  let ans = evaluate_postfix(tree);
  assert_eq!(ans, 86)
}

#[test]
fn test_arith_eval () {

  // 1 * 2 + 3
  let input = vec![
    NameElse::Else( Tok::Num(1) ),
    NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Op(Op::Minus) ),
    NameElse::Else( Tok::Num(3) ),
    NameElse::Else( Tok::Op(Op::Minus) ),
    NameElse::Else( Tok::Num(1) ),
    NameElse::Else( Tok::Op(Op::Minus) ),
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Op(Op::Times) ),
    NameElse::Else( Tok::Num(2) ),
    // NameElse::Else( Tok::Op(Op::Divide) ),
    // NameElse::Else( Tok::Num(2) ),
    // NameElse::Else( Tok::Op(Op::Minus) ),
    // NameElse::Else( Tok::Num(3) ),
    ];
  println!("{:?}", &input);
  let input : List<Tok> = list_of_vec(&input);
  let tree  : Tree<Tok> = tree_of_list(Dir2::Left, input);
  let list  : List<Tok> = postfix_of_infix(tree);
  println!("{:?}", &list);
  //let input : List<Tok> = list_of_vec(&input);
  let tree  : Tree<Tok> = tree_of_list(Dir2::Right, list);
  let ans = evaluate_postfix(tree);
  println!("{:?}", ans)
}

#[test]
fn test_paran_eval () {

  // 1 * 2 + 3
  let input = vec![
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Op(Op::Times) ),
    NameElse::Else( Tok::Op(Op::ParanOpen) ),
    //NameElse::Else( Tok::Num(1) ),
    //NameElse::Else( Tok::Op(Op::Plus) ),
    NameElse::Else( Tok::Num(2) ),
    NameElse::Else( Tok::Op(Op::Minus) ),
    NameElse::Else( Tok::Num(3) ),
    NameElse::Else( Tok::Op(Op::ParanClose) ),
    ];

    println!("{:?}", &input);
    let input : List<Tok> = list_of_vec(&input);
    let tree  : Tree<Tok> = tree_of_list(Dir2::Left, input);
    let list  : List<Tok> = postfix_of_infix(tree);
    println!("{:?}", &list);
    //let input : List<Tok> = list_of_vec(&input);
    let tree  : Tree<Tok> = tree_of_list(Dir2::Right, list);
    let ans = evaluate_postfix(tree);
    println!("{:?}", ans)
}

// fn infix_to_postfix(input: List<char>) -> List<List<char>> {
//   let mut postfix = List::Nil;
//   let mut operators = List::Nil;
//   let mut temp_operand = List::Nil;

//   //'''
//   // Match all chars in 'input'
//   //     If c is a digit, then push onto a Digit list temporarily until all digits in an operand are read (after which add the operand to the Postfix list)
//   //     If c is an operator, pop everything of higher predence and add it to postfix list, then add c to list of Operators
//   //'''
//   postfix
// }

// fn evaluate_postfix(input: List<List<char>>) -> i32 {

//   //'''
//   // Convert list to number and apply operation on two at a time
//   //'''

// }

// fn test_arith_parse() {
//   println!("Enter expression in infix format");
//   let mut input = String::new();
//   io::stdin().read_line(&mut input).ok().expect("Failed to parse input");

//   // '''
//   // Convert string to List<char> (reverse order)
//   // '''
//   let input_list = panic!("");

//   let postfix_expr = infix_to_postfix(input_list);
//   let result = evaluate_postfix(postfix_expr);
// }

<|endoftext|>


<commit_before>#[doc = "Interface for running tree-based traversals over layout boxes"]

import base::{Box, BTree, NodeMethods};
import intrinsic::tydesc;

export full_traversal;
export top_down_traversal;
export bottom_up_traversal;

// The underlying representation of an @T.  We don't actually care
// what it is, just that we can transform to and from this
// representation to send boxes across task boundaries.
type shared_box<T> = {
    mut refcount : uint,
    // These are generic unsafe pointers, not just *ints
    foo : *int,
    bar : *int,
    baz : *int,
    payload : T
};

#[doc="Transform and @ into its underlying representation.  The reference count stays constant."]
fn unwrap_box(-b : @Box) -> *shared_box<Box> unsafe {
    let new_box : *shared_box<Box> = unsafe::transmute(b);
    return new_box;
}

#[doc="Transform an underlying representation back to an @.  The reference count stays constant."]
fn rewrap_box(-b : *shared_box<Box>) -> @Box unsafe {
    let new_box : @Box = unsafe::transmute(b);
    return new_box;
}

#[doc="

Iterate down and then up a tree of layout boxes in parallel and apply
the given functions to each box.  Each box applies the first function,
spawns a task to complete all of its children in parallel, waits for
them to finish, and then applies the second function.

# Arguments

* `root` - The current top of the tree, the functions will be applied to it and its children.
* `top-down` - A function that is applied to each node after it is applied to that node's parent.
* `bottom-up` - A function that is applied to each node after it is applied to that node's
                children
"]
fn traverse_helper(-root : @Box, -top_down : fn~(@Box), -bottom_up : fn~(@Box)) {
    top_down(root);

    do listen |ack_chan| {
        let mut count = 0;

        // For each child we will send it off to another task and then
        // recurse.  It is safe to send these boxes across tasks
        // because root still holds a reference to the children so
        // they will not be destroyed from the other task.  Also the
        // current task will block until all of it's children return,
        // so the original owner of the @-box will not exit while the
        // children are still live.
        for BTree.each_child(root) |kid| {
            count += 1;

            // Unwrap the box so we can send it out of this task
            let unwrapped = unwrap_box(copy kid);
            // Hide the box in an option so we can get it across the
            // task boundary without copying it
            let swappable : ~mut option<*shared_box<Box>> = ~mut some(unwrapped);

            do task::spawn || {
                // Get the box out of the option and into the new task
                let mut swapped_in = none;
                swapped_in <-> *swappable;

                // Retrieve the original @Box and recurse
                let new_kid = rewrap_box(option::unwrap(swapped_in));
                traverse_helper(new_kid, copy top_down, copy bottom_up);

                ack_chan.send(());
            }
        }

        // wait for all the children to finish before preceding
        for count.times() { ack_chan.recv(); }
    }

    bottom_up(root);
}

#[doc="A noneffectful function to be used if only one pass is required."]
fn nop(_box : @Box) {
    return;
}

#[doc="
   Iterate in parallel over the boxes in a tree, applying one function
   to a parent before recursing on its children and one after.
"]

fn full_traversal(+root : @Box, -top_down : fn~(@Box), -bottom_up : fn~(@Box)) {
    traverse_helper(root, top_down, bottom_up);
}

#[doc="
   Iterate in parallel over the boxes in a tree, applying the given
   function to a parent before its children.
"]
fn top_down_traversal(+root : @Box, -top_down : fn~(@Box)) {
    traverse_helper(root, top_down, nop);
}

#[doc="
   Iterate in parallel over the boxes in a tree, applying the given
   function to a parent after its children.
"]
fn bottom_up_traversal(+root : @Box, -bottom_up : fn~(@Box)) {
    traverse_helper(root, nop, bottom_up);
}
<commit_msg>Extend the traversal interface to support passing a value from parents to children.<commit_after>#[doc = "Interface for running tree-based traversals over layout boxes"]

import base::{Box, BTree, NodeMethods};
import intrinsic::tydesc;

export full_traversal;
export top_down_traversal;
export bottom_up_traversal;
export extended_full_traversal;
export extended_top_down_traversal;

// The underlying representation of an @T.  We don't actually care
// what it is, just that we can transform to and from this
// representation to send boxes across task boundaries.
type shared_box<T> = {
    mut refcount : uint,
    // These are generic unsafe pointers, not just *ints
    foo : *int,
    bar : *int,
    baz : *int,
    payload : T
};

#[doc="Transform and @ into its underlying representation.  The reference count stays constant."]
fn unwrap_box(-b : @Box) -> *shared_box<Box> unsafe {
    let new_box : *shared_box<Box> = unsafe::transmute(b);
    return new_box;
}

#[doc="Transform an underlying representation back to an @.  The reference count stays constant."]
fn rewrap_box(-b : *shared_box<Box>) -> @Box unsafe {
    let new_box : @Box = unsafe::transmute(b);
    return new_box;
}

#[doc="

Iterate down and then up a tree of layout boxes in parallel and apply
the given functions to each box.  Each box applies the first function,
spawns a task to complete all of its children in parallel, passing
each child the result of the ifrst funciton. It waits for them to
finish, and then applies the second function to the current box.

# Arguments

* `root` - The current top of the tree, the functions will be applied
           to it and its children.
* `returned` - The value returned by applying top_down to the parent
               of the current box, or a passed in default
* `top_down` - A function that is applied to each node after it is
              applied to that node's parent.
* `bottom_up` - A function that is applied to each node after it is
                applied to that node's children

"]
fn traverse_helper<T : copy send>(-root : @Box, returned : T, -top_down : fn~(+T, @Box) -> T,
                      -bottom_up : fn~(@Box)) {
    let returned = top_down(returned, root);

    do listen |ack_chan| {
        let mut count = 0;

        // For each child we will send it off to another task and then
        // recurse.  It is safe to send these boxes across tasks
        // because root still holds a reference to the children so
        // they will not be destroyed from the other task.  Also the
        // current task will block until all of it's children return,
        // so the original owner of the @-box will not exit while the
        // children are still live.
        for BTree.each_child(root) |kid| {
            count += 1;

            // Unwrap the box so we can send it out of this task
            let unwrapped = unwrap_box(copy kid);
            // Hide the box in an option so we can get it across the
            // task boundary without copying it
            let swappable : ~mut option<*shared_box<Box>> = ~mut some(unwrapped);

            do task::spawn || {
                // Get the box out of the option and into the new task
                let mut swapped_in = none;
                swapped_in <-> *swappable;

                // Retrieve the original @Box and recurse
                let new_kid = rewrap_box(option::unwrap(swapped_in));
                traverse_helper(new_kid, copy returned, copy top_down, copy bottom_up);

                ack_chan.send(());
            }
        }

        // wait for all the children to finish before preceding
        for count.times() { ack_chan.recv(); }
    }

    bottom_up(root);
}

#[doc="A noneffectful function to be used if only one pass is required."]
fn nop(_box : @Box) {
    return;
}

#[doc= "
   A wrapper to change a function that only acts on a box to one that
   threasds a unit through to match travserse_helper
"]
fn unit_wrapper(-fun : fn~(@Box)) -> fn~(+(), @Box) {
    fn~(+_u : (), box : @Box) { fun(box); }
}

#[doc="
   Iterate in parallel over the boxes in a tree, applying one function
   to a parent before recursing on its children and one after.
"]
fn full_traversal(+root : @Box, -top_down : fn~(@Box), -bottom_up : fn~(@Box)) {
    traverse_helper(root, (), unit_wrapper(top_down), bottom_up);
}

#[doc="
   Iterate in parallel over the boxes in a tree, applying the given
   function to a parent before its children.
"]
fn top_down_traversal(+root : @Box, -top_down : fn~(@Box)) {
    traverse_helper(root, (), unit_wrapper(top_down), nop);
}

#[doc="
   Iterate in parallel over the boxes in a tree, applying the given
   function to a parent after its children.
"]
fn bottom_up_traversal(+root : @Box, -bottom_up : fn~(@Box)) {
    traverse_helper(root, (), unit_wrapper(nop), bottom_up);
}

#[doc="
   Iterate in parallel over the boxes in a tree, applying the given
   function to a parent before its children, the value returned by the
   function is passed to each child when they are recursed upon.  As
   the recursion unwinds, the second function is applied to first the
   children in parallel, and then the parent.
"]
fn extended_full_traversal<T : copy send>(+root : @Box, first_val : T,
                                          -top_down : fn~(+T, @Box) -> T,
                                          -bottom_up : fn~(@Box)) {
    traverse_helper(root, first_val, top_down, bottom_up);
}

#[doc="
   Iterate in parallel over the boxes in a tree, applying the given
   function to a parent before its children, the value returned by the
   function is passed to each child when they are recursed upon.
"]
fn extended_top_down_traversal<T : copy send>(+root : @Box, first_val : T,
                                              -top_down : fn~(+T, @Box) -> T) {
    traverse_helper(root, first_val, top_down, nop);
}
<|endoftext|>


<commit_before>use value::Value;

fn compiler_schema() -> Vec<(&'static str, Vec<&'static str>, Vec<&'static str>)> {
    // the schema is arranged as (table name, unique key fields, other fields)

    vec![
    // all state lives in a view of some kind
    // `kind` is one of:
    // "table" - a view which can depend on the past
    // "join" - take the product of multiple views and filter the results
    // "union" - take the union of multiple views
    // "aggregate" - group one view by the contents of another and run reducing functions on the groups
    // "primitive" - a built-in function, represented as a view with one or more non-Data fields
    ("view", vec!["view"], vec!["kind"]),

    // views have fields
    // some fields have constraints on how they can be queried
    // `kind` is one of:
    // "output" - a normal field
    // "scalar input" - a field that must be constrained to a single scalar value
    // "vector input" - a field that must be constrained to a single vector value (in an aggregate)
    ("field", vec!["view", "field"], vec!["kind"]),

    // sources uniquely identify a copy of a child view inside a parent join or union
    // a table has an "insert" source and a "remove" source
    // a join or union can query multiple copies of some child view, with different source ids
    // an aggregate has an "outer" source, an "inner" source and a "reducer" source
    ("source", vec!["parent view", "source"], vec!["child view"]),

    // every view also has an implicit "constant" source
    // anywhere source-field is expected, you can instead use "constant"-id
    // `value` may be any valid eve value
    ("constant", vec!["constant"], vec!["value"]),

    // constraints belong to a join view
    // the left and right fields are compared using the operation
    // `operation` is one of "==", "/=", "<", "<=", ">", ">="
    ("constraint parent", vec!["constraint"], vec!["parent view"]),
    ("constraint left", vec!["constraint"], vec!["left source", "left field"]),
    ("constraint right", vec!["constraint"], vec!["right source", "right field"]),
    ("constraint operation", vec!["constraint"], vec!["operation"]),

    // aggregates group an "inner" source by the rows of an "outer" source
    // the grouping is determined by binding inner fields to outer fields or constants
    ("aggregate grouping", vec!["aggregate", "inner field"], vec!["group source", "group field"]),
    // before aggregation the groups are sorted
    // `order` is an f64
    ("aggregate sorting", vec!["aggregate", "inner field"], vec!["order"]),
    // groups may optionally be limited by an inner field or constant
    ("aggregate limit from", vec!["aggregate"], vec!["from source", "from field"]),
    ("aggregate limit to", vec!["aggregate"], vec!["to source", "to field"]),
    // the groups are reduced by binding against the "reducer" source
    // constants and inner fields which are bound to outer fields may both be used as ScalarInput arguments
    // inner fields which are not bound to outer fields may be used as VectorInput arguments
    ("aggregate arguments", vec!["aggregate", "reducer field"], vec!["argument source", "argument field"]),

    // views produce output by binding fields from sources
    // each table or join field must be bound exactly once
    // each aggregate field must be bound exactly once and can only bind constants, inner fields or reducer outputs
    // each union field must be bound exactly once per source
    // (the unique key is different for union than for other kinds, so I don't give a key at all)
    ("select", vec![], vec!["view", "view field", "source", "source field"]),

    // things that live in an ordered list are sorted by some f64 (ties are broken by Id)
    // `order` is an f64
    ("display order", vec!["id"], vec!["order"]),
    // things can have human readable names
    // `name` is a string
    ("display name", vec!["id"], vec!["name"]),
    ]
}<commit_msg>Fix schema problems that Josh brought up<commit_after>use value::Value;

fn compiler_schema() -> Vec<(&'static str, Vec<&'static str>, Vec<&'static str>)> {
    // the schema is arranged as (table name, unique key fields, other fields)

    vec![
    // all state lives in a view of some kind
    // `kind` is one of:
    // "table" - a view which can depend on the past
    // "join" - take the product of multiple views and filter the results
    // "union" - take the union of multiple views
    // "aggregate" - group one view by the contents of another and run reducing functions on the groups
    // "primitive" - a built-in function, represented as a view with one or more non-Data fields
    ("view", vec!["view"], vec!["kind"]),

    // views have fields
    // some fields have constraints on how they can be queried
    // `kind` is one of:
    // "output" - a normal field
    // "scalar input" - a field that must be constrained to a single scalar value
    // "vector input" - a field that must be constrained to a single vector value (in an aggregate)
    ("field", vec!["view", "field"], vec!["kind"]),

    // source ids have two purposes
    // a) uniquely generated ids to disambiguate multiple uses of the same view
    // (eg when joining a view with itself)
    // b) fixed ids to identify views which are used for some specific purpose
    // (these are "insert" and "remove" in tables and "inner" and "outer" in aggregates)
    ("source", vec!["view", "source"], vec!["source view"]),

    // every view also has an implicit "constant" source
    // anywhere source-field is expected, you can instead use "constant"-id
    // `value` may be any valid eve value
    ("constant", vec!["constant"], vec!["value"]),

    // constraints belong to a join view
    // the left and right fields are compared using the operation
    // `operation` is one of "==", "/=", "<", "<=", ">", ">="
    ("constraint", vec!["constraint"], vec!["view"]),
    ("constraint left", vec!["constraint"], vec!["left source", "left field"]),
    ("constraint right", vec!["constraint"], vec!["right source", "right field"]),
    ("constraint operation", vec!["constraint"], vec!["operation"]),

    // aggregates group an "inner" source by the rows of an "outer" source
    // the grouping is determined by binding inner fields to outer fields or constants
    ("aggregate grouping", vec!["aggregate", "inner field"], vec!["group source", "group field"]),
    // before aggregation the groups are sorted
    // `priority` is an f64. higher priority fields are compared first. ties are broken by field id
    // `direction` is one of "ascending" or "descending"
    // fields which have no entry default to 0, "ascending"
    ("aggregate sorting", vec!["aggregate", "inner field"], vec!["priority", "direction"]),
    // groups may optionally be limited by an inner field or constant
    ("aggregate limit from", vec!["aggregate"], vec!["from source", "from field"]),
    ("aggregate limit to", vec!["aggregate"], vec!["to source", "to field"]),
    // the groups may be reduced by binding against reducer sources
    // constants and grouped inner fields may both be used as ScalarInput arguments
    // ungrouped inner fields which are not bound to outer fields may be used as VectorInput arguments
    ("aggregate argument", vec!["aggregate", "reducer source", "reducer field"], vec!["argument source", "argument field"]),

    // views produce output by binding fields from sources
    // each table or join field must be bound exactly once
    // each aggregate field must be bound exactly once and can only bind constants, inner fields or reducer outputs
    // each union field must be bound exactly once per source
    // (the unique key is different for union than for other kinds, so I don't give a key at all)
    ("select", vec![], vec!["view", "view field", "source", "source field"]),

    // things that live in an ordered list are sorted by some f64 (ties are broken by Id)
    // `priority` is an f64. higher priority things are displayed first. ties are broken by field id
    // things which have no entry default to 0
    ("display order", vec!["id"], vec!["priority"]),
    // things can have human readable names
    // `name` is a string
    ("display name", vec!["id"], vec!["name"]),
    ]
}<|endoftext|>