<commit_before>#![feature(box_syntax,box_patterns)]
#![feature(compile)]
#![feature(scheme)]

/// Scheme compiler integration tests
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd).
/// And from http://webdocs.cs.ualberta.ca/%7Eyou/courses/325/Mynotes/Fun/SECD-slides.html

#[macro_use]
extern crate seax_svm as svm;
extern crate seax_scheme as scheme;

use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn compile_list_creation() {
    assert_eq!(
        scheme::compile("(cons 10 (cons 20 nil))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn  compile_list_car() {
    assert_eq!(
        scheme::compile("(car (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn compile_list_cdr() {
    assert_eq!(
        scheme::compile("(cdr (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn compile_simple_add(){
    assert_eq!(
        scheme::compile("(+ 10 10)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn compile_nested_arith() {
     assert_eq!(
        scheme::compile("(- 20 (+ 5 5))"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// (if (= 0 (- 1 1)) #t #f)
/// ```
#[test]
fn compile_basic_branching_1() {
    assert_eq!(
        scheme::compile("(if (= 0 (- 1 1)) #t #f)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ))
    );
}
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn compile_basic_branching_2() {
    assert_eq!(
        scheme::compile("(+ 10 (if (nil? nil) 10 20))"),
        Ok(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Lambda
///
/// ```lisp
/// (lambda (x y) (+ x y))
/// ```
///
/// (LDF (LD (1.2) LD (1.1) + RTN))
#[test]
fn compile_lambda() {
    assert_eq!(
        scheme::compile("(lambda (x y) (+ x y))"),
        Ok(list!(
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(2))
                    )),
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(1))
                    )),
                InstCell(ADD),
                InstCell(RTN)
            ))
        ))
    )
}

/// Lambda application
///
/// ```lisp
/// ((lambda (x y) (+ x y)) 2 3)
/// ```
///
/// (NIL LDC 3 CONS LDC 2 CONS LDF (LD (1.2) LD (1.1) + RTN) AP)
#[test]
fn compile_lambda_ap() {
    assert_eq!(
        scheme::compile("((lambda (x y) (+ x y)) 2 3)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(3)),
            InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(2)),
            InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(2))
                    ))
                )),
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(1))
                    ))
                )),
                InstCell(ADD),
                InstCell(RTN)
            )),
            InstCell(AP)
        )
}

/// Nested lambdas
///
/// ```lisp
/// ((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)
/// ```
#[test]
fn compile_nested_lambda() {
    assert_eq!(
        scheme::compile("((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(6)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(NIL),
                InstCell(LDC), AtomCell(SInt(5)), InstCell(CONS),
                InstCell(LDC), AtomCell(SInt(3)), InstCell(CONS),
                InstCell(LDF),
                ListCell(box list!(
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(2)),AtomCell(SInt(1))
                        ))
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(1)),AtomCell(SInt(2))
                        ))
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(1)),AtomCell(SInt(1))
                        ))
                    InstCell(SUB),
                    InstCell(ADD),
                    InstCell(RTN)
                ))
                InstCell(AP),
                InstCell(RTN)
            ))
            InstCell(AP)
        ))
    )
}<commit_msg>More fixes to lambda integration targets<commit_after>#![feature(box_syntax,box_patterns)]
#![feature(compile)]
#![feature(scheme)]

/// Scheme compiler integration tests
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd).
/// And from http://webdocs.cs.ualberta.ca/%7Eyou/courses/325/Mynotes/Fun/SECD-slides.html

#[macro_use]
extern crate seax_svm as svm;
extern crate seax_scheme as scheme;

use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn compile_list_creation() {
    assert_eq!(
        scheme::compile("(cons 10 (cons 20 nil))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn  compile_list_car() {
    assert_eq!(
        scheme::compile("(car (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn compile_list_cdr() {
    assert_eq!(
        scheme::compile("(cdr (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn compile_simple_add(){
    assert_eq!(
        scheme::compile("(+ 10 10)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn compile_nested_arith() {
     assert_eq!(
        scheme::compile("(- 20 (+ 5 5))"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// (if (= 0 (- 1 1)) #t #f)
/// ```
#[test]
fn compile_basic_branching_1() {
    assert_eq!(
        scheme::compile("(if (= 0 (- 1 1)) #t #f)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ))
    );
}
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn compile_basic_branching_2() {
    assert_eq!(
        scheme::compile("(+ 10 (if (nil? nil) 10 20))"),
        Ok(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Lambda
///
/// ```lisp
/// (lambda (x y) (+ x y))
/// ```
///
/// (LDF (LD (1.2) LD (1.1) + RTN))
#[test]
fn compile_lambda() {
    assert_eq!(
        scheme::compile("(lambda (x y) (+ x y))"),
        Ok(list!(
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(2))
                    )),
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(1))
                    )),
                InstCell(ADD),
                InstCell(RET)
            ))
        ))
    )
}

/// Lambda application
///
/// ```lisp
/// ((lambda (x y) (+ x y)) 2 3)
/// ```
///
/// (NIL LDC 3 CONS LDC 2 CONS LDF (LD (1.2) LD (1.1) + RTN) AP)
#[test]
fn compile_lambda_ap() {
    assert_eq!(
        scheme::compile("((lambda (x y) (+ x y)) 2 3)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(3)),
            InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(2)),
            InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD), ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(2))
                    )),
                InstCell(LD), ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(1))
                    )),
                InstCell(ADD),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    )
}

/// Nested lambdas
///
/// ```lisp
/// ((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)
/// ```
#[test]
fn compile_nested_lambda() {
    assert_eq!(
        scheme::compile("((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(6)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(NIL),
                InstCell(LDC), AtomCell(SInt(5)), InstCell(CONS),
                InstCell(LDC), AtomCell(SInt(3)), InstCell(CONS),
                InstCell(LDF),
                ListCell(box list!(
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(2)),AtomCell(SInt(1))
                        )),
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(1)),AtomCell(SInt(2))
                        )),
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(1)),AtomCell(SInt(1))
                        )),
                    InstCell(SUB),
                    InstCell(ADD),
                    InstCell(RET)
                )),
                InstCell(AP),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    )
}<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![allow(unstable)]

#[cfg(target_os="android")]
extern crate libc;

extern crate servo;
extern crate time;
extern crate util;
extern crate net;

#[cfg(not(test))]
extern crate "glutin_app" as app;

#[cfg(not(test))]
extern crate compositing;

#[cfg(target_os="android")]
#[macro_use]
extern crate android_glue;

#[cfg(target_os="android")]
use libc::c_int;

#[cfg(not(test))]
use util::opts;

#[cfg(not(test))]
use net::resource_task;

#[cfg(not(test))]
use servo::Browser;
#[cfg(not(test))]
use compositing::windowing::WindowEvent;

#[cfg(target_os="android")]
use std::borrow::ToOwned;

#[cfg(not(any(test,target_os="android")))]
use std::os;

#[cfg(not(test))]
struct BrowserWrapper {
    browser: Browser<app::window::Window>,
}

#[cfg(target_os="android")]
android_start!(main);

#[cfg(target_os="android")]
fn get_args() -> Vec<String> {
    vec![
        "servo".to_owned(),
        "http://en.wikipedia.org/wiki/Rust".to_owned()
    ]
}

#[cfg(not(target_os="android"))]
fn get_args() -> Vec<String> {
    os::args()
}

#[cfg(target_os="android")]
struct FilePtr(*mut libc::types::common::c95::FILE);

#[cfg(target_os="android")]
unsafe impl Send for FilePtr {}

#[cfg(target_os="android")]
fn redirect_output(file_no: c_int) {
    use libc::funcs::posix88::unistd::{pipe, dup2};
    use libc::funcs::posix88::stdio::fdopen;
    use libc::funcs::c95::stdio::fgets;
    use util::task::spawn_named;
    use std::mem;
    use std::ffi::CString;
    use std::str::from_utf8;

    unsafe {
        let mut pipes: [c_int; 2] = [ 0, 0 ];
        pipe(pipes.as_mut_ptr());
        dup2(pipes[1], file_no);
        let mode = CString::from_slice("r".as_bytes());
        let input_file = FilePtr(fdopen(pipes[0], mode.as_ptr()));
        spawn_named("android-logger".to_owned(), move || {
            loop {
                let mut read_buffer: [u8; 1024] = mem::zeroed();
                let FilePtr(input_file) = input_file;
                fgets(read_buffer.as_mut_ptr() as *mut i8, read_buffer.len() as i32, input_file);
                let cs = CString::from_slice(&read_buffer);
                match from_utf8(cs.as_bytes()) {
                    Ok(s) => android_glue::write_log(s),
                    _ => {}
                }
            }
        });
    }
}

#[cfg(target_os="android")]
fn setup_logging() {
    use libc::consts::os::posix88::{STDERR_FILENO, STDOUT_FILENO};
    //os::setenv("RUST_LOG", "servo,gfx,msg,util,layers,js,std,rt,extra");
    redirect_output(STDERR_FILENO);
    redirect_output(STDOUT_FILENO);
}

#[cfg(not(target_os="android"))]
fn setup_logging() {
}

fn main() {
    if opts::from_cmdline_args(get_args().as_slice()) {
        setup_logging();
        resource_task::global_init();

        let window = if opts::get().headless {
            None
        } else {
            Some(app::create_window())
        };

        let mut browser = BrowserWrapper {
            browser: Browser::new(window.clone()),
        };

        match window {
            None => {}
            Some(ref window) => {
                unsafe {
                    window.set_nested_event_loop_listener(&mut browser);
                }
            }
        }

        browser.browser.handle_event(WindowEvent::InitializeCompositing);

        loop {
            let should_continue = match window {
                None => browser.browser.handle_event(WindowEvent::Idle),
                Some(ref window) => {
                    let event = window.wait_events();
                    browser.browser.handle_event(event)
                }
            };
            if !should_continue {
                break
            }
        };

        match window {
            None => {}
            Some(ref window) => {
                unsafe {
                    window.remove_nested_event_loop_listener();
                }
            }
        }

        let BrowserWrapper {
            browser
        } = browser;
        browser.shutdown();
    }
}

impl app::NestedEventLoopListener for BrowserWrapper {
    fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool {
        let is_resize = match event {
            WindowEvent::Resize(..) => true,
            _ => false,
        };
        if !self.browser.handle_event(event) {
            return false
        }
        if is_resize {
            self.browser.repaint_synchronously()
        }
        true
    }
}

<commit_msg>Fix some warnings in servo/main.rs.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(env, os)]

#[cfg(target_os="android")]
extern crate libc;

extern crate servo;
extern crate time;
extern crate util;
extern crate net;

#[cfg(not(test))]
extern crate "glutin_app" as app;

#[cfg(not(test))]
extern crate compositing;

#[cfg(target_os="android")]
#[macro_use]
extern crate android_glue;

#[cfg(target_os="android")]
use libc::c_int;

#[cfg(not(test))]
use util::opts;

#[cfg(not(test))]
use net::resource_task;

#[cfg(not(test))]
use servo::Browser;
#[cfg(not(test))]
use compositing::windowing::WindowEvent;

#[cfg(target_os="android")]
use std::borrow::ToOwned;

#[cfg(not(test))]
struct BrowserWrapper {
    browser: Browser<app::window::Window>,
}

#[cfg(target_os="android")]
android_start!(main);

#[cfg(target_os="android")]
fn get_args() -> Vec<String> {
    vec![
        "servo".to_owned(),
        "http://en.wikipedia.org/wiki/Rust".to_owned()
    ]
}

#[cfg(not(target_os="android"))]
fn get_args() -> Vec<String> {
    use std::env;
    env::args().map(|s| s.into_string().unwrap()).collect()
}

#[cfg(target_os="android")]
struct FilePtr(*mut libc::types::common::c95::FILE);

#[cfg(target_os="android")]
unsafe impl Send for FilePtr {}

#[cfg(target_os="android")]
fn redirect_output(file_no: c_int) {
    use libc::funcs::posix88::unistd::{pipe, dup2};
    use libc::funcs::posix88::stdio::fdopen;
    use libc::funcs::c95::stdio::fgets;
    use util::task::spawn_named;
    use std::mem;
    use std::ffi::CString;
    use std::str::from_utf8;

    unsafe {
        let mut pipes: [c_int; 2] = [ 0, 0 ];
        pipe(pipes.as_mut_ptr());
        dup2(pipes[1], file_no);
        let mode = CString::from_slice("r".as_bytes());
        let input_file = FilePtr(fdopen(pipes[0], mode.as_ptr()));
        spawn_named("android-logger".to_owned(), move || {
            loop {
                let mut read_buffer: [u8; 1024] = mem::zeroed();
                let FilePtr(input_file) = input_file;
                fgets(read_buffer.as_mut_ptr() as *mut i8, read_buffer.len() as i32, input_file);
                let cs = CString::from_slice(&read_buffer);
                match from_utf8(cs.as_bytes()) {
                    Ok(s) => android_glue::write_log(s),
                    _ => {}
                }
            }
        });
    }
}

#[cfg(target_os="android")]
fn setup_logging() {
    use libc::consts::os::posix88::{STDERR_FILENO, STDOUT_FILENO};
    //os::setenv("RUST_LOG", "servo,gfx,msg,util,layers,js,std,rt,extra");
    redirect_output(STDERR_FILENO);
    redirect_output(STDOUT_FILENO);
}

#[cfg(not(target_os="android"))]
fn setup_logging() {
}

fn main() {
    if opts::from_cmdline_args(&*get_args()) {
        setup_logging();
        resource_task::global_init();

        let window = if opts::get().headless {
            None
        } else {
            Some(app::create_window())
        };

        let mut browser = BrowserWrapper {
            browser: Browser::new(window.clone()),
        };

        match window {
            None => {}
            Some(ref window) => {
                unsafe {
                    window.set_nested_event_loop_listener(&mut browser);
                }
            }
        }

        browser.browser.handle_event(WindowEvent::InitializeCompositing);

        loop {
            let should_continue = match window {
                None => browser.browser.handle_event(WindowEvent::Idle),
                Some(ref window) => {
                    let event = window.wait_events();
                    browser.browser.handle_event(event)
                }
            };
            if !should_continue {
                break
            }
        };

        match window {
            None => {}
            Some(ref window) => {
                unsafe {
                    window.remove_nested_event_loop_listener();
                }
            }
        }

        let BrowserWrapper {
            browser
        } = browser;
        browser.shutdown();
    }
}

impl app::NestedEventLoopListener for BrowserWrapper {
    fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool {
        let is_resize = match event {
            WindowEvent::Resize(..) => true,
            _ => false,
        };
        if !self.browser.handle_event(event) {
            return false
        }
        if is_resize {
            self.browser.repaint_synchronously()
        }
        true
    }
}

<|endoftext|>


<commit_before>//
// base32.rs - base32 implementation
//
// The Base32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A             9 J            18 S            27 3
//     1 B            10 K            19 T            28 4
//     2 C            11 L            20 U            29 5
//     3 D            12 M            21 V            30 6
//     4 E            13 N            22 W            31 7
//     5 F            14 O            23 X
//     6 G            15 P            24 Y         (pad) =
//     7 H            16 Q            25 Z
//     8 I            17 R            26 2
//

use std;

export mk;

const padd: u8 = 61u8;

iface base32 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn hex_encode(src: [u8]) -> [u8];
    fn hex_decode(src: [u8]) -> [u8];
}

fn mk() -> base32 {
    type _base32 = {table: [u8], table_hex: [u8]};

    impl of base32 for _base32 {
        fn encode(src: [u8]) -> [u8] {
            b32encode(self.table, src)
        }
        fn decode(src: [u8]) -> [u8] {
            b32decode(self.table, src)
        }
        fn hex_encode(src: [u8]) -> [u8] {
            b32encode(self.table_hex, src)
        }
        fn hex_decode(src: [u8]) -> [u8] {
            b32decode(self.table_hex, src)
        }
    }

    let table = vec::init_elt_mut(32u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(50u8, 56u8)  { |j| table[i] = j; i += 1u8; }

    let table_hex = vec::init_elt_mut(32u, 0u8), i = 0u8;
    u8::range(48u8, 58u8)  { |j| table_hex[i] = j; i += 1u8; }
    u8::range(65u8, 87u8)  { |j| table_hex[i] = j; i += 1u8; }

    {table: vec::from_mut(table),
     table_hex: vec::from_mut(table_hex)} as base32
}

fn b32encode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);
    let targ = if srclen % 5u == 0u {
        vec::init_elt_mut(srclen / 5u * 8u, 0u8)
    } else {
        vec::init_elt_mut((srclen / 5u + 1u) * 8u, 0u8)
    };
    let input = vec::init_elt_mut(5u, 0u8);
    let output = vec::init_elt_mut(8u, 0u8);
    let curr = 0u, src_curr = 0u;

    while srclen > 4u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];
        input[4] = src[src_curr + 4u];
        srclen -= 5u; src_curr += 5u;

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;
        output[7] = input[4] & 0x1f_u8;

        targ[curr] = table[output[0]]; curr += 1u;
        targ[curr] = table[output[1]]; curr += 1u;
        targ[curr] = table[output[2]]; curr += 1u;
        targ[curr] = table[output[3]]; curr += 1u;
        targ[curr] = table[output[4]]; curr += 1u;
        targ[curr] = table[output[5]]; curr += 1u;
        targ[curr] = table[output[6]]; curr += 1u;
        targ[curr] = table[output[7]]; curr += 1u;
    }

    if srclen != 0u {
        input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;
        input[3] = 0u8; input[4] = 0u8;

        alt srclen {
          1u {input[0] = src[src_curr];}
          2u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];}
          3u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];}
          4u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];
              input[3] = src[src_curr + 3u];}
          _ { }
        }

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;

        targ[curr] = table[output[0]]; curr += 1u;
        targ[curr] = table[output[1]]; curr += 1u;
        targ[curr] =
            if srclen > 1u { table[output[2]] } else { padd }; curr += 1u;
        targ[curr] =
            if srclen > 1u { table[output[3]] } else { padd }; curr += 1u;
        targ[curr] =
            if srclen > 2u { table[output[4]] } else { padd }; curr += 1u;
        targ[curr] =
            if srclen > 3u { table[output[5]] } else { padd }; curr += 1u;
        targ[curr] =
            if srclen > 3u { table[output[6]] } else { padd }; curr += 1u;
        targ[curr] = padd;
    }

    vec::from_mut(targ)
}

fn b32decode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);

    if srclen % 8u != 0u { fail "malformed base32 string"; }
    if srclen == 0u { ret []; }

    []
}

mod tests {
    import std::map;
    import core::str::{bytes, from_bytes};
    enum mode {
        t_encode,
        t_decode,
        t_hex_encode,
        t_hex_decode,
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        alt t {
          t_decode { }
          t_encode {
            m.insert("fooba", "MZXW6YTB");
            m.insert("foob",  "MZXW6YQ=");
            m.insert("foo",   "MZXW6===");
            m.insert("fo",    "MZXQ====");
            m.insert("f",     "MY======");
          }
          t_hex_decode { }
          t_hex_encode {
            m.insert("fooba", "CPNMUOJ1");
            m.insert("foob",  "CPNMUOG=");
            m.insert("foo",   "CPNMU===");
            m.insert("fo",    "CPNG====");
            m.insert("f",     "CO======");
          }
        }
        m.insert("", "");
        m
    }
    fn do_test(t: mode) {
        let b32 = mk();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b32.decode(bytes(k))) }
              t_encode { from_bytes(b32.encode(bytes(k))) }
              t_hex_decode { from_bytes(b32.hex_decode(bytes(k))) }
              t_hex_encode { from_bytes(b32.hex_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn hex_encode() { do_test(t_hex_encode); }
    #[test]
    fn decode() { do_test(t_decode); }
}
<commit_msg>wip: base32.rs<commit_after>//
// base32.rs - base32 implementation
//
// The Base32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A             9 J            18 S            27 3
//     1 B            10 K            19 T            28 4
//     2 C            11 L            20 U            29 5
//     3 D            12 M            21 V            30 6
//     4 E            13 N            22 W            31 7
//     5 F            14 O            23 X
//     6 G            15 P            24 Y         (pad) =
//     7 H            16 Q            25 Z
//     8 I            17 R            26 2
//
// The "Extended Hex" Base 32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 0             9 9            18 I            27 R
//     1 1            10 A            19 J            28 S
//     2 2            11 B            20 K            29 T
//     3 3            12 C            21 L            30 U
//     4 4            13 D            22 M            31 V
//     5 5            14 E            23 N
//     6 6            15 F            24 O         (pad) =
//     7 7            16 G            25 P
//     8 8            17 H            26 Q
//

use std;

export mk;

const padd: u8 = 61u8;

iface base32 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn hex_encode(src: [u8]) -> [u8];
    fn hex_decode(src: [u8]) -> [u8];
}

fn mk() -> base32 {
    type _base32 = {table: [u8], table_hex: [u8]};

    impl of base32 for _base32 {
        fn encode(src: [u8]) -> [u8] {
            b32encode(self.table, src)
        }
        fn decode(src: [u8]) -> [u8] {
            b32decode(self.table, src)
        }
        fn hex_encode(src: [u8]) -> [u8] {
            b32encode(self.table_hex, src)
        }
        fn hex_decode(src: [u8]) -> [u8] {
            b32decode(self.table_hex, src)
        }
    }

    let table = vec::init_elt_mut(32u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(50u8, 56u8)  { |j| table[i] = j; i += 1u8; }

    let table_hex = vec::init_elt_mut(32u, 0u8), i = 0u8;
    u8::range(48u8, 58u8)  { |j| table_hex[i] = j; i += 1u8; }
    u8::range(65u8, 87u8)  { |j| table_hex[i] = j; i += 1u8; }

    {table: vec::from_mut(table),
     table_hex: vec::from_mut(table_hex)} as base32
}

fn b32encode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);
    let targ = if srclen % 5u == 0u {
        vec::init_elt_mut(srclen / 5u * 8u, 0u8)
    } else {
        vec::init_elt_mut((srclen / 5u + 1u) * 8u, 0u8)
    };
    let input = vec::init_elt_mut(5u, 0u8);
    let output = vec::init_elt_mut(8u, 0u8);
    let curr = 0u, src_curr = 0u;

    while srclen > 4u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];
        input[4] = src[src_curr + 4u];
        srclen -= 5u; src_curr += 5u;

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;
        output[7] = input[4] & 0x1f_u8;

        targ[curr] = table[output[0]]; curr += 1u;
        targ[curr] = table[output[1]]; curr += 1u;
        targ[curr] = table[output[2]]; curr += 1u;
        targ[curr] = table[output[3]]; curr += 1u;
        targ[curr] = table[output[4]]; curr += 1u;
        targ[curr] = table[output[5]]; curr += 1u;
        targ[curr] = table[output[6]]; curr += 1u;
        targ[curr] = table[output[7]]; curr += 1u;
    }

    if srclen != 0u {
        input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;
        input[3] = 0u8; input[4] = 0u8;

        alt srclen {
          1u {input[0] = src[src_curr];}
          2u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];}
          3u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];}
          4u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];
              input[3] = src[src_curr + 3u];}
          _ { }
        }

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;

        targ[curr] = table[output[0]]; curr += 1u;
        targ[curr] = table[output[1]]; curr += 1u;
        targ[curr] =
            if srclen > 1u { table[output[2]] } else { padd }; curr += 1u;
        targ[curr] =
            if srclen > 1u { table[output[3]] } else { padd }; curr += 1u;
        targ[curr] =
            if srclen > 2u { table[output[4]] } else { padd }; curr += 1u;
        targ[curr] =
            if srclen > 3u { table[output[5]] } else { padd }; curr += 1u;
        targ[curr] =
            if srclen > 3u { table[output[6]] } else { padd }; curr += 1u;
        targ[curr] = padd;
    }

    vec::from_mut(targ)
}

fn b32decode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);

    if srclen % 8u != 0u { fail "malformed base32 string"; }
    if srclen == 0u { ret []; }

    []
}

mod tests {
    import std::map;
    import core::str::{bytes, from_bytes};
    enum mode {
        t_encode,
        t_decode,
        t_hex_encode,
        t_hex_decode,
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        alt t {
          t_decode { }
          t_encode {
            m.insert("fooba", "MZXW6YTB");
            m.insert("foob",  "MZXW6YQ=");
            m.insert("foo",   "MZXW6===");
            m.insert("fo",    "MZXQ====");
            m.insert("f",     "MY======");
          }
          t_hex_decode { }
          t_hex_encode {
            m.insert("fooba", "CPNMUOJ1");
            m.insert("foob",  "CPNMUOG=");
            m.insert("foo",   "CPNMU===");
            m.insert("fo",    "CPNG====");
            m.insert("f",     "CO======");
          }
        }
        m.insert("", "");
        m
    }
    fn do_test(t: mode) {
        let b32 = mk();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b32.decode(bytes(k))) }
              t_encode { from_bytes(b32.encode(bytes(k))) }
              t_hex_decode { from_bytes(b32.hex_decode(bytes(k))) }
              t_hex_encode { from_bytes(b32.hex_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn hex_encode() { do_test(t_hex_encode); }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn hex_decode() { do_test(t_hex_decode); }
}
<|endoftext|>


<commit_before>use std::ops::Mul;
use std::sync::Arc;
use na::{Translate, Cross, Translation, Rotation};
use math::{Scalar, Point, Vect, Isometry};
use utils::data::uid_remap::{UidRemap, FastKey};
use entities::inspection::Repr;
use entities::bounding_volume::{self, AABB};
use queries::geometry::Contact;
use queries::ray::{RayCast, Ray, RayIntersection};
use queries::point::PointQuery;
use narrow_phase::{BasicCollisionDispatcher, ContactSignalHandler, CollisionAlgorithm};
use broad_phase::{BroadPhase, DBVTBroadPhase};
use world::{CollisionObjectsDispatcher, CollisionObject, CollisionGroups};

use na::{Pnt2, Pnt3, Iso2, Iso3};

// FIXME: be generic wrt the BV?
/// Type of the broad phase trait-object used by the collision world.
pub type BroadPhaseObject<P> = Box<BroadPhase<P, AABB<P>, FastKey> + 'static>;

/// A world that handles collision objects.
pub struct CollisionWorld<P, M, T> {
    objects:       UidRemap<CollisionObject<P, M, T>>,
    broad_phase:   BroadPhaseObject<P>,
    narrow_phase:  CollisionObjectsDispatcher<P, M, T>,
    pos_to_update: Vec<(FastKey, M)>,
    timestamp:     usize
    // FIXME: allow modification of the other properties too.
}

impl<P, M, T> CollisionWorld<P, M, T>
    where P: Point,
          P::Vect: Translate<P> + Cross,
          <P::Vect as Cross>::CrossProductType: Vect<Scalar = <P::Vect as Vect>::Scalar> +
                                                Mul<<P::Vect as Vect>::Scalar, Output = <P::Vect as Cross>::CrossProductType>, // FIXME: why do we need this?
          M:  Isometry<P, P::Vect> + Translation<P::Vect> + Rotation<<P::Vect as Cross>::CrossProductType> {
    /// Creates a new collision world.
    // FIXME: use default values for `margin` and `prediction` and allow their modification by the
    // user ?
    pub fn new(margin:     <P::Vect as Vect>::Scalar,
               prediction: <P::Vect as Vect>::Scalar,
               small_uids: bool)
               -> CollisionWorld<P, M, T> {
        let objects = UidRemap::new(small_uids);
        let sdispatcher = Box::new(BasicCollisionDispatcher::new(prediction));
        let broad_phase = Box::new(DBVTBroadPhase::<P, AABB<P>, FastKey>::new(margin, true));
        let narrow_phase = CollisionObjectsDispatcher::new(sdispatcher);

        CollisionWorld {
            objects:       objects,
            broad_phase:   broad_phase,
            narrow_phase:  narrow_phase,
            pos_to_update: Vec::new(),
            timestamp:     0
        }
    }

    /// Adds a collision object to the world.
    pub fn add(&mut self,
               uid: usize,
               position: M,
               shape: Arc<Box<Repr<P, M>>>,
               collision_groups: CollisionGroups,
               data: T) {
        // FIXME: test that we did not add this object already ?

        let mut collision_object = CollisionObject::new(position, shape, collision_groups, data);
        collision_object.timestamp = self.timestamp;
        let aabb = bounding_volume::aabb(&**collision_object.shape, &collision_object.position);
        let fk = self.objects.insert(uid, collision_object).0;
        self.broad_phase.defered_add(fk.uid(), aabb, fk)
    }

    /// Remove a collision object from the world.
    pub fn remove(&mut self, uid: usize) {
        if let Some((fk, _)) = self.objects.remove(uid) {
            self.broad_phase.defered_remove(fk.uid());
        }
    }

    /// Updates the collision world.
    ///
    /// This executes the whole collision detection pipeline: the broad phase first, then the
    /// narrow phase.
    pub fn update(&mut self) {
        self.perform_position_update();
        self.perform_broad_phase();
        self.perform_narrow_phase();
    }

    /// Sets the position the collision object attached to the specified object will have during
    /// the next update.
    pub fn defered_set_position(&mut self, uid: usize, pos: M) {
        if let Some(fk) = self.objects.get_fast_key(uid) {
            self.pos_to_update.push((fk, pos))
        }
    }

    /// Registers a handler for contact start/stop events.
    pub fn register_contact_signal_handler<H>(&mut self, name: &str, handler: H)
        where H: ContactSignalHandler<T> + 'static {
        self.narrow_phase.register_contact_signal_handler(name, Box::new(handler))
    }

    /// Unregisters a handler for contact start/stop events.
    pub fn unregister_contact_signal_handler(&mut self, name: &str) {
        self.narrow_phase.unregister_contact_signal_handler(name)
    }

    /// Executes the position updates.
    pub fn perform_position_update(&mut self) {
        for &(ref fk, ref pos) in self.pos_to_update.iter() {
            if let Some(co) = self.objects.get_fast_mut(fk) {
                co.position = pos.clone();
                co.timestamp = self.timestamp;
                self.broad_phase.defered_set_bounding_volume(fk.uid(), bounding_volume::aabb(&**co.shape, pos));
            }
        }

        self.pos_to_update.clear();
    }

    /// Executes the broad phase of the collision detection pipeline.
    ///
    /// Not that this does not take in account the changes made to the collision updates after the
    /// last `.perform_position_update()` call.
    pub fn perform_broad_phase(&mut self) {
        let bf = &mut self.broad_phase;
        let nf = &mut self.narrow_phase;
        let objs = &self.objects;

        bf.update(
            &mut |b1, b2| CollisionObjectsDispatcher::is_proximity_allowed(objs, b1, b2),
            &mut |b1, b2, started| nf.handle_proximity(objs, b1, b2, started)
        );
    }

    /// Executes the narrow phase of the collision detection pipeline.
    pub fn perform_narrow_phase(&mut self) {
        self.narrow_phase.update(&self.objects, self.timestamp);
        self.timestamp = self.timestamp + 1;
    }

    /// Iterates through all the contact pairs.
    #[inline(always)]
    pub fn contact_pairs<F>(&self, f: F)
          where F: FnMut(&T, &T, &CollisionAlgorithm<P, M>) {
        self.narrow_phase.contact_pairs(&self.objects, f)
    }

    /// Collects every contact detected since the last update.
    #[inline(always)]
    pub fn contacts<F>(&self, f: F)
          where F: FnMut(&T, &T, &Contact<P>) {
        self.narrow_phase.contacts(&self.objects, f)
    }

    /// Computes the interferences between every rigid bodies on this world and a ray.
    #[inline(always)]
    pub fn interferences_with_ray<'a, F>(&'a mut self, ray: &Ray<P>, groups: &CollisionGroups, mut f: F)
          where F: FnMut(&T, RayIntersection<P::Vect>) {
        let mut bodies = Vec::new();

        self.broad_phase.interferences_with_ray(ray, &mut bodies);

        for b in bodies.into_iter() {
            let co = &self.objects[*b];

            if co.collision_groups.can_collide_with_groups(groups) {
                let inter = co.shape.toi_and_normal_with_ray(&co.position, ray, true);

                if let Some(inter) = inter {
                    f(&co.data, inter)
                }
            }
        }
    }

    /// Computes the interferences between every rigid bodies of a given broad phase, and a point.
    #[inline(always)]
    pub fn interferences_with_point<F>(&self, point: &P, groups: &CollisionGroups, mut f: F)
          where F: FnMut(&T) {
        let mut bodies = Vec::new();

        self.broad_phase.interferences_with_point(point, &mut bodies);

        for b in bodies.into_iter() {
            let co = &self.objects[*b];

            if co.collision_groups.can_collide_with_groups(groups) {
                if co.shape.contains_point(&co.position, point) {
                    f(&co.data)
                }
            }
        }
    }

    // FIXME: replace by iterators.
    /// Computes the interferences between every rigid bodies of a given broad phase, and a aabb.
    #[inline(always)]
    pub fn interferences_with_aabb<F>(&self, aabb: &AABB<P>, groups: &CollisionGroups, mut f: F)
          where F: FnMut(&T) {
        let mut fks = Vec::new();

        self.broad_phase.interferences_with_bounding_volume(aabb, &mut fks);

        for fk in fks.into_iter() {
            let co = &self.objects[*fk];

            if co.collision_groups.can_collide_with_groups(groups) {
                f(&co.data)
            }
        }
    }
}

/// 2D collision world containing objects of type `T`.
pub type CollisionWorld2<N, T> = CollisionWorld<Pnt2<N>, Iso2<N>, T>;
/// 3D collision world containing objects of type `T`.
pub type CollisionWorld3<N, T> = CollisionWorld<Pnt3<N>, Iso3<N>, T>;
<commit_msg>World interferences queries: return iterators instead of requiring a user-defined closure.<commit_after>use std::ops::Mul;
use std::sync::Arc;
use std::vec::IntoIter;
use na::{Translate, Cross, Translation, Rotation};
use math::{Scalar, Point, Vect, Isometry};
use utils::data::uid_remap::{UidRemap, FastKey};
use entities::inspection::Repr;
use entities::bounding_volume::{self, AABB};
use queries::geometry::Contact;
use queries::ray::{RayCast, Ray, RayIntersection};
use queries::point::PointQuery;
use narrow_phase::{BasicCollisionDispatcher, ContactSignalHandler, CollisionAlgorithm};
use broad_phase::{BroadPhase, DBVTBroadPhase};
use world::{CollisionObjectsDispatcher, CollisionObject, CollisionGroups};

use na::{Pnt2, Pnt3, Iso2, Iso3};

// FIXME: be generic wrt the BV?
/// Type of the broad phase trait-object used by the collision world.
pub type BroadPhaseObject<P> = Box<BroadPhase<P, AABB<P>, FastKey> + 'static>;

/// A world that handles collision objects.
pub struct CollisionWorld<P, M, T> {
    objects:       UidRemap<CollisionObject<P, M, T>>,
    broad_phase:   BroadPhaseObject<P>,
    narrow_phase:  CollisionObjectsDispatcher<P, M, T>,
    pos_to_update: Vec<(FastKey, M)>,
    timestamp:     usize
    // FIXME: allow modification of the other properties too.
}

impl<P, M, T> CollisionWorld<P, M, T>
    where P: Point,
          P::Vect: Translate<P> + Cross,
          <P::Vect as Cross>::CrossProductType: Vect<Scalar = <P::Vect as Vect>::Scalar> +
                                                Mul<<P::Vect as Vect>::Scalar, Output = <P::Vect as Cross>::CrossProductType>, // FIXME: why do we need this?
          M:  Isometry<P, P::Vect> + Translation<P::Vect> + Rotation<<P::Vect as Cross>::CrossProductType> {
    /// Creates a new collision world.
    // FIXME: use default values for `margin` and `prediction` and allow their modification by the
    // user ?
    pub fn new(margin:     <P::Vect as Vect>::Scalar,
               prediction: <P::Vect as Vect>::Scalar,
               small_uids: bool)
               -> CollisionWorld<P, M, T> {
        let objects = UidRemap::new(small_uids);
        let sdispatcher = Box::new(BasicCollisionDispatcher::new(prediction));
        let broad_phase = Box::new(DBVTBroadPhase::<P, AABB<P>, FastKey>::new(margin, true));
        let narrow_phase = CollisionObjectsDispatcher::new(sdispatcher);

        CollisionWorld {
            objects:       objects,
            broad_phase:   broad_phase,
            narrow_phase:  narrow_phase,
            pos_to_update: Vec::new(),
            timestamp:     0
        }
    }

    /// Adds a collision object to the world.
    pub fn add(&mut self,
               uid: usize,
               position: M,
               shape: Arc<Box<Repr<P, M>>>,
               collision_groups: CollisionGroups,
               data: T) {
        // FIXME: test that we did not add this object already ?

        let mut collision_object = CollisionObject::new(position, shape, collision_groups, data);
        collision_object.timestamp = self.timestamp;
        let aabb = bounding_volume::aabb(&**collision_object.shape, &collision_object.position);
        let fk = self.objects.insert(uid, collision_object).0;
        self.broad_phase.defered_add(fk.uid(), aabb, fk)
    }

    /// Remove a collision object from the world.
    pub fn remove(&mut self, uid: usize) {
        if let Some((fk, _)) = self.objects.remove(uid) {
            self.broad_phase.defered_remove(fk.uid());
        }
    }

    /// Updates the collision world.
    ///
    /// This executes the whole collision detection pipeline: the broad phase first, then the
    /// narrow phase.
    pub fn update(&mut self) {
        self.perform_position_update();
        self.perform_broad_phase();
        self.perform_narrow_phase();
    }

    /// Sets the position the collision object attached to the specified object will have during
    /// the next update.
    pub fn defered_set_position(&mut self, uid: usize, pos: M) {
        if let Some(fk) = self.objects.get_fast_key(uid) {
            self.pos_to_update.push((fk, pos))
        }
    }

    /// Registers a handler for contact start/stop events.
    pub fn register_contact_signal_handler<H>(&mut self, name: &str, handler: H)
        where H: ContactSignalHandler<T> + 'static {
        self.narrow_phase.register_contact_signal_handler(name, Box::new(handler))
    }

    /// Unregisters a handler for contact start/stop events.
    pub fn unregister_contact_signal_handler(&mut self, name: &str) {
        self.narrow_phase.unregister_contact_signal_handler(name)
    }

    /// Executes the position updates.
    pub fn perform_position_update(&mut self) {
        for &(ref fk, ref pos) in self.pos_to_update.iter() {
            if let Some(co) = self.objects.get_fast_mut(fk) {
                co.position = pos.clone();
                co.timestamp = self.timestamp;
                self.broad_phase.defered_set_bounding_volume(fk.uid(), bounding_volume::aabb(&**co.shape, pos));
            }
        }

        self.pos_to_update.clear();
    }

    /// Executes the broad phase of the collision detection pipeline.
    ///
    /// Not that this does not take in account the changes made to the collision updates after the
    /// last `.perform_position_update()` call.
    pub fn perform_broad_phase(&mut self) {
        let bf = &mut self.broad_phase;
        let nf = &mut self.narrow_phase;
        let objs = &self.objects;

        bf.update(
            &mut |b1, b2| CollisionObjectsDispatcher::is_proximity_allowed(objs, b1, b2),
            &mut |b1, b2, started| nf.handle_proximity(objs, b1, b2, started)
        );
    }

    /// Executes the narrow phase of the collision detection pipeline.
    pub fn perform_narrow_phase(&mut self) {
        self.narrow_phase.update(&self.objects, self.timestamp);
        self.timestamp = self.timestamp + 1;
    }

    /// Iterates through all the contact pairs.
    #[inline(always)]
    pub fn contact_pairs<F>(&self, f: F)
          where F: FnMut(&T, &T, &CollisionAlgorithm<P, M>) {
        self.narrow_phase.contact_pairs(&self.objects, f)
    }

    /// Collects every contact detected since the last update.
    #[inline(always)]
    pub fn contacts<F>(&self, f: F)
          where F: FnMut(&T, &T, &Contact<P>) {
        self.narrow_phase.contacts(&self.objects, f)
    }

    /// Computes the interferences between every rigid bodies on this world and a ray.
    #[inline(always)]
    pub fn interferences_with_ray<'a>(&'a mut self, ray: &'a Ray<P>, groups: &'a CollisionGroups)
        -> InterferencesWithRay<'a, P, M, T> {
        let mut fks = Vec::new();

        self.broad_phase.interferences_with_ray(ray, &mut fks);

        InterferencesWithRay {
            ray:     ray,
            groups:  groups,
            objects: &self.objects,
            idx:     fks.into_iter()
        }
    }

    /// Computes the interferences between every rigid bodies of a given broad phase, and a point.
    #[inline(always)]
    pub fn interferences_with_point<'a>(&'a self, point: &'a P, groups: &'a CollisionGroups)
        -> InterferencesWithPoint<'a, P, M, T> {
        let mut fks = Vec::new();

        self.broad_phase.interferences_with_point(point, &mut fks);

        InterferencesWithPoint {
            point:   point,
            groups:  groups,
            objects: &self.objects,
            idx:     fks.into_iter()
        }
    }

    /// Computes the interferences between every rigid bodies of a given broad phase, and a aabb.
    #[inline(always)]
    pub fn interferences_with_aabb<'a>(&'a self, aabb: &'a AABB<P>, groups: &'a CollisionGroups)
        -> InterferencesWithAABB<'a, P, M, T> {
        let mut fks = Vec::new();

        self.broad_phase.interferences_with_bounding_volume(aabb, &mut fks);

        InterferencesWithAABB {
            groups:  groups,
            objects: &self.objects,
            idx:     fks.into_iter()
        }
    }
}

/// Iterator through all the objects on the world that intersect a specific ray.
pub struct InterferencesWithRay<'a, P: 'a + Point, M: 'a, T: 'a> {
    ray:     &'a Ray<P>,
    objects: &'a UidRemap<CollisionObject<P, M, T>>,
    groups:  &'a CollisionGroups,
    idx:     IntoIter<&'a FastKey>,
}

impl<'a, P, M, T> Iterator for InterferencesWithRay<'a, P, M, T>
    where P: Point,
          M: Isometry<P, P::Vect> + Translation<P::Vect> {
    type Item = (&'a CollisionObject<P, M, T>, RayIntersection<P::Vect>);

    #[inline]
    fn next(&mut self) -> Option<(&'a CollisionObject<P, M, T>, RayIntersection<P::Vect>)> {
        match self.idx.next() {
            Some(id) => {
                let co = &self.objects[*id];

                if co.collision_groups.can_collide_with_groups(self.groups) {
                    let inter = co.shape.toi_and_normal_with_ray(&co.position, self.ray, true);

                    if let Some(inter) = inter {
                        return Some((co, inter))
                    }
                }
                None
            },
            None => None
        }
    }
}

/// Iterator through all the objects on the world that intersect a specific point.
pub struct InterferencesWithPoint<'a, P: 'a, M: 'a, T: 'a> {
    point:   &'a P,
    objects: &'a UidRemap<CollisionObject<P, M, T>>,
    groups:  &'a CollisionGroups,
    idx:     IntoIter<&'a FastKey>,
}

impl<'a, P, M, T> Iterator for InterferencesWithPoint<'a, P, M, T>
    where P: Point,
          M: Isometry<P, P::Vect> + Translation<P::Vect> {
    type Item = &'a CollisionObject<P, M, T>;

    #[inline]
    fn next(&mut self) -> Option<&'a CollisionObject<P, M, T>> {
        match self.idx.next() {
            Some(id) => {
                let co = &self.objects[*id];

                if co.collision_groups.can_collide_with_groups(self.groups) &&
                   co.shape.contains_point(&co.position, self.point) {
                    Some(co)
                }
                else {
                    None
                }
            },
            None => None
        }
    }
}

/// Iterator through all the objects on the world which bounding volume intersects a specific AABB.
pub struct InterferencesWithAABB<'a, P: 'a, M: 'a, T: 'a> {
    objects: &'a UidRemap<CollisionObject<P, M, T>>,
    groups:  &'a CollisionGroups,
    idx:     IntoIter<&'a FastKey>,
}

impl<'a, P, M, T> Iterator for InterferencesWithAABB<'a, P, M, T> {
    type Item = &'a CollisionObject<P, M, T>;

    #[inline]
    fn next(&mut self) -> Option<&'a CollisionObject<P, M, T>> {
        match self.idx.next() {
            Some(id) => {
                let co = &self.objects[*id];

                if co.collision_groups.can_collide_with_groups(self.groups) {
                    Some(co)
                }
                else {
                    None
                }
            },
            None => None
        }
    }
}

/// 2D collision world containing objects of type `T`.
pub type CollisionWorld2<N, T> = CollisionWorld<Pnt2<N>, Iso2<N>, T>;
/// 3D collision world containing objects of type `T`.
pub type CollisionWorld3<N, T> = CollisionWorld<Pnt3<N>, Iso3<N>, T>;
<|endoftext|>


<commit_before>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! The mmap module provides a safe interface to map memory and ensures UnmapViewOfFile is called when the
//! mmap object leaves scope.

use std::{
    io,
    slice::{from_raw_parts, from_raw_parts_mut},
};

use libc::{
    c_uint, c_void, {self},
};

use win_util::{allocation_granularity, get_high_order, get_low_order};
use winapi::um::memoryapi::{
    FlushViewOfFile, MapViewOfFile, MapViewOfFileEx, UnmapViewOfFile, FILE_MAP_READ, FILE_MAP_WRITE,
};

use super::{mmap::Error, mmap::Result, MappedRegion, MemoryMapping, Protection, RawDescriptor};
use crate::descriptor::AsRawDescriptor;
use crate::warn;

pub(super) const PROT_NONE: c_uint = 0;
pub(super) const PROT_READ: c_uint = FILE_MAP_READ;
pub(super) const PROT_WRITE: c_uint = FILE_MAP_WRITE;

impl MemoryMapping {
    /// Creates an anonymous shared mapping of `size` bytes with `prot` protection.
    ///
    /// # Arguments
    /// * `size` - Size of memory region in bytes.
    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
    pub fn new_protection(size: usize, prot: Protection) -> Result<MemoryMapping> {
        // This is safe because we are creating an anonymous mapping in a place not already used by
        // any other area in this process.
        unsafe { MemoryMapping::try_mmap(None, size, prot.into(), None) }
    }

    /// Create a Memory mapping from a raw address returned by
    /// the kernel.
    /// # Arguments
    /// * `addr` - Raw pointer to memory region.
    /// * `size` - Size of memory region in bytes.
    pub fn from_raw_ptr(addr: *mut c_void, size: usize) -> Result<MemoryMapping> {
        Ok(MemoryMapping { addr, size })
    }

    pub fn from_raw_handle_offset(
        file_handle: RawDescriptor,
        size: usize,
    ) -> Result<MemoryMapping> {
        // This is safe because we are creating an anonymous mapping in a place not already used by
        // any other area in this process.
        unsafe {
            MemoryMapping::try_mmap(
                None,
                size,
                Protection::read_write().into(),
                Some((file_handle, 0)),
            )
        }
    }

    /// Maps the `size` bytes starting at `offset` bytes of the given `descriptor` as read/write.
    ///
    /// # Arguments
    /// * `file_handle` - File handle to map from.
    /// * `size` - Size of memory region in bytes.
    /// * `offset` - Offset in bytes from the beginning of `descriptor` to start the mmap.
    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
    pub fn from_descriptor_offset_protection(
        file_handle: &dyn AsRawDescriptor,
        size: usize,
        offset: u64,
        prot: Protection,
    ) -> Result<MemoryMapping> {
        // This is safe because we are creating an anonymous mapping in a place not already used by
        // any other area in this process.
        unsafe {
            MemoryMapping::try_mmap(
                None,
                size,
                prot.into(),
                Some((file_handle.as_raw_descriptor(), offset)),
            )
        }
    }

    /// Creates an anonymous shared mapping of `size` bytes with `prot` protection.
    ///
    /// # Safety
    /// Unsafe: unmaps any mmap'd regions already present at (addr..addr+size).
    ///
    /// # Arguments
    /// * `addr` - Memory address to mmap at.
    /// * `size` - Size of memory region in bytes.
    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
    pub unsafe fn new_protection_fixed(
        addr: *mut u8,
        size: usize,
        prot: Protection,
    ) -> Result<MemoryMapping> {
        MemoryMapping::try_mmap(Some(addr), size, prot.into(), None)
    }

    /// Maps the `size` bytes starting at `offset` bytes of the given `descriptor` with
    /// `prot` protections.
    ///
    /// # Safety
    /// Unsafe: unmaps any mmap'd regions already present at (addr..addr+size).
    ///
    /// # Arguments
    /// * `addr` - Memory address to mmap at.
    /// * `descriptor` - File descriptor to mmap from.
    /// * `size` - Size of memory region in bytes.
    /// * `offset` - Offset in bytes from the beginning of `descriptor` to start the mmap.
    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
    pub unsafe fn from_descriptor_offset_protection_fixed(
        addr: *mut u8,
        descriptor: &dyn AsRawDescriptor,
        size: usize,
        offset: u64,
        prot: Protection,
    ) -> Result<MemoryMapping> {
        MemoryMapping::try_mmap(
            Some(addr),
            size,
            prot.into(),
            Some((descriptor.as_raw_descriptor(), offset)),
        )
    }

    /// Calls MapViewOfFile/MapViewOfFileEx with the parameters given
    unsafe fn try_mmap(
        addr: Option<*mut u8>,
        size: usize,
        access_flags: c_uint,
        file_handle: Option<(RawDescriptor, u64)>,
    ) -> Result<MemoryMapping> {
        if file_handle.is_none() {
            // TODO(mikehoyle): For now, do not allow the no-handle scenario. As per comments
            // in guest_memory, the no-handle case is for legacy support and shouldn't have
            // significant usage.
            return Err(Error::InvalidAddress);
        }
        let file_handle = file_handle.unwrap();

        // on windows, pages needed to be of fixed granular size, and the
        // maximum valid value is an i64.
        if file_handle.1 % allocation_granularity() != 0 || file_handle.1 > i64::max_value() as u64
        {
            return Err(Error::InvalidOffset);
        }

        let created_address = match addr {
            Some(addr) => MapViewOfFileEx(
                file_handle.0,
                access_flags,
                get_high_order(file_handle.1),
                get_low_order(file_handle.1),
                size,
                addr as *mut c_void,
            ),
            None => MapViewOfFile(
                file_handle.0,
                access_flags,
                get_high_order(file_handle.1),
                get_low_order(file_handle.1),
                size,
            ),
        };

        if created_address.is_null() {
            return Err(Error::SystemCallFailed(super::Error::last()));
        }

        Ok(MemoryMapping {
            addr: created_address,
            size,
        })
    }

    /// Calls FlushViewOfFile on the mapped memory range, ensuring all changes that would
    /// be written to disk are written immediately
    pub fn msync(&self) -> Result<()> {
        // Safe because self can only be created as a successful memory mapping
        unsafe {
            if FlushViewOfFile(self.addr, self.size) == 0 {
                return Err(Error::SystemCallFailed(super::Error::last()));
            }
        };
        Ok(())
    }

    /// Reads data from a file descriptor and writes it to guest memory.
    ///
    /// # Arguments
    /// * `mem_offset` - Begin writing memory at this offset.
    /// * `src` - Read from `src` to memory.
    /// * `count` - Read `count` bytes from `src` to memory.
    ///
    /// # Examples
    ///
    /// * Read bytes from /dev/urandom
    ///
    /// ```
    ///   use base::platform::MemoryMapping;
    ///   use base::platform::SharedMemory;
    ///   use std::ffi::CString;
    ///   use std::fs::File;
    ///   use std::path::Path;
    ///   fn test_read_random() -> Result<u32, ()> {
    ///       let mut mem_map = MemoryMapping::from_descriptor(
    ///         &SharedMemory::new(&CString::new("test").unwrap(), 1024).unwrap(), 1024).unwrap();
    ///       let mut file = File::open(Path::new("/dev/urandom")).map_err(|_| ())?;
    ///       mem_map.read_to_memory(32, &mut file, 128).map_err(|_| ())?;
    ///       let rand_val: u32 =  mem_map.read_obj(40).map_err(|_| ())?;
    ///       Ok(rand_val)
    ///   }
    /// ```
    pub fn read_to_memory<F: io::Read>(
        &self,
        mem_offset: usize,
        src: &mut F,
        count: usize,
    ) -> Result<()> {
        self.range_end(mem_offset, count)
            .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
        // Safe because the check above ensures that no memory outside this slice will get accessed
        // by this read call.
        let buf: &mut [u8] = unsafe { from_raw_parts_mut(self.as_ptr().add(mem_offset), count) };
        match src.read_exact(buf) {
            Err(e) => Err(Error::ReadToMemory(e)),
            Ok(()) => Ok(()),
        }
    }

    /// Writes data from memory to a file descriptor.
    ///
    /// # Arguments
    /// * `mem_offset` - Begin reading memory from this offset.
    /// * `dst` - Write from memory to `dst`.
    /// * `count` - Read `count` bytes from memory to `src`.
    ///
    /// # Examples
    ///
    /// * Write 128 bytes to /dev/null
    ///
    /// ```
    ///   use base::platform::MemoryMapping;
    ///   use base::platform::SharedMemory;
    ///   use std::ffi::CString;
    ///   use std::fs::File;
    ///   use std::path::Path;
    ///   fn test_write_null() -> Result<(), ()> {
    ///       let mut mem_map = MemoryMapping::from_descriptor(
    ///           &SharedMemory::new(&CString::new("test").unwrap(), 1024).unwrap(), 1024).unwrap();
    ///       let mut file = File::open(Path::new("/dev/null")).map_err(|_| ())?;
    ///       mem_map.write_from_memory(32, &mut file, 128).map_err(|_| ())?;
    ///       Ok(())
    ///   }
    /// ```
    pub fn write_from_memory<F: io::Write>(
        &self,
        mem_offset: usize,
        dst: &mut F,
        count: usize,
    ) -> Result<()> {
        self.range_end(mem_offset, count)
            .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
        // Safe because the check above ensures that no memory outside this slice will get accessed
        // by this write call.
        let buf: &[u8] = unsafe { from_raw_parts(self.as_ptr().add(mem_offset), count) };
        match dst.write_all(buf) {
            Err(e) => Err(Error::WriteFromMemory(e)),
            Ok(()) => Ok(()),
        }
    }
}

impl Drop for MemoryMapping {
    fn drop(&mut self) {
        // This is safe because we MapViewOfFile the area at addr ourselves, and nobody
        // else is holding a reference to it.
        unsafe {
            if UnmapViewOfFile(self.addr) == 0 {
                warn!("Unsuccessful unmap of file: {}", super::Error::last());
            }
        }
    }
}

/// TODO(b/150415526): This is currently an empty implementation to allow simple usages in
/// shared structs. Any attempts to use it will result in compiler errors. It will need
/// to be ported to actually be used on Windows.
pub struct MemoryMappingArena();

#[cfg(test)]
mod tests {
    use super::{
        super::{pagesize, SharedMemory},
        *,
    };
    use crate::descriptor::FromRawDescriptor;
    use data_model::{VolatileMemory, VolatileMemoryError};
    use std::{ffi::CString, ptr};
    use winapi::shared::winerror;

    #[test]
    fn basic_map() {
        let shm = SharedMemory::new(&CString::new("test").unwrap(), 1028).unwrap();
        let m = MemoryMapping::from_descriptor(&shm, 1024).unwrap();
        assert_eq!(1024, m.size());
    }

    #[test]
    fn map_invalid_fd() {
        let descriptor = unsafe { std::fs::File::from_raw_descriptor(ptr::null_mut()) };
        let res = MemoryMapping::from_descriptor(&descriptor, 1024).unwrap_err();
        if let Error::SystemCallFailed(e) = res {
            assert_eq!(e.errno(), winerror::ERROR_INVALID_HANDLE as i32);
        } else {
            panic!("unexpected error: {}", res);
        }
    }

    #[test]
    fn test_write_past_end() {
        let shm = SharedMemory::new(&CString::new("test").unwrap(), 1028).unwrap();
        let m = MemoryMapping::from_descriptor(&shm, 5).unwrap();
        let res = m.write_slice(&[1, 2, 3, 4, 5, 6], 0);
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), 5);
    }

    #[test]
    fn slice_size() {
        let shm = SharedMemory::new(&CString::new("test").unwrap(), 1028).unwrap();
        let m = MemoryMapping::from_descriptor(&shm, 5).unwrap();
        let s = m.get_slice(2, 3).unwrap();
        assert_eq!(s.size(), 3);
    }

    #[test]
    fn slice_addr() {
        let shm = SharedMemory::new(&CString::new("test").unwrap(), 1028).unwrap();
        let m = MemoryMapping::from_descriptor(&shm, 5).unwrap();
        let s = m.get_slice(2, 3).unwrap();
        assert_eq!(s.as_ptr(), unsafe { m.as_ptr().offset(2) });
    }

    #[test]
    fn slice_store() {
        let shm = SharedMemory::new(&CString::new("test").unwrap(), 1028).unwrap();
        let m = MemoryMapping::from_descriptor(&shm, 5).unwrap();
        let r = m.get_ref(2).unwrap();
        r.store(9u16);
        assert_eq!(m.read_obj::<u16>(2).unwrap(), 9);
    }

    #[test]
    fn slice_overflow_error() {
        let shm = SharedMemory::new(&CString::new("test").unwrap(), 1028).unwrap();
        let m = MemoryMapping::from_descriptor(&shm, 5).unwrap();
        let res = m.get_slice(std::usize::MAX, 3).unwrap_err();
        assert_eq!(
            res,
            VolatileMemoryError::Overflow {
                base: std::usize::MAX,
                offset: 3,
            }
        );
    }
    #[test]
    fn slice_oob_error() {
        let shm = SharedMemory::new(&CString::new("test").unwrap(), 1028).unwrap();
        let m = MemoryMapping::from_descriptor(&shm, 5).unwrap();
        let res = m.get_slice(3, 3).unwrap_err();
        assert_eq!(res, VolatileMemoryError::OutOfBounds { addr: 6 });
    }

    #[test]
    fn from_descriptor_offset_invalid() {
        let shm = SharedMemory::new(&CString::new("test").unwrap(), 1028).unwrap();
        let res = MemoryMapping::from_descriptor_offset(&shm, 4096, (i64::max_value() as u64) + 1)
            .unwrap_err();
        match res {
            Error::InvalidOffset => {}
            e => panic!("unexpected error: {}", e),
        }
    }

    #[test]
    fn arena_msync() {
        let size: usize = 0x40000;
        let shm = SharedMemory::new(&CString::new("test").unwrap(), size as u64).unwrap();
        let m = MemoryMapping::from_descriptor(&shm, size).unwrap();
        let ps = pagesize();
        <dyn MappedRegion>::msync(&m, 0, ps).unwrap();
        <dyn MappedRegion>::msync(&m, 0, size).unwrap();
        <dyn MappedRegion>::msync(&m, ps, size - ps).unwrap();
        let res = <dyn MappedRegion>::msync(&m, ps, size).unwrap_err();
        match res {
            Error::InvalidAddress => {}
            e => panic!("unexpected error: {}", e),
        }
    }
}
<commit_msg>base: windows: mmap: remove duplicate tests<commit_after>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! The mmap module provides a safe interface to map memory and ensures UnmapViewOfFile is called when the
//! mmap object leaves scope.

use std::{
    io,
    slice::{from_raw_parts, from_raw_parts_mut},
};

use libc::{
    c_uint, c_void, {self},
};

use win_util::{allocation_granularity, get_high_order, get_low_order};
use winapi::um::memoryapi::{
    FlushViewOfFile, MapViewOfFile, MapViewOfFileEx, UnmapViewOfFile, FILE_MAP_READ, FILE_MAP_WRITE,
};

use super::{mmap::Error, mmap::Result, MappedRegion, MemoryMapping, Protection, RawDescriptor};
use crate::descriptor::AsRawDescriptor;
use crate::warn;

pub(super) const PROT_NONE: c_uint = 0;
pub(super) const PROT_READ: c_uint = FILE_MAP_READ;
pub(super) const PROT_WRITE: c_uint = FILE_MAP_WRITE;

impl MemoryMapping {
    /// Creates an anonymous shared mapping of `size` bytes with `prot` protection.
    ///
    /// # Arguments
    /// * `size` - Size of memory region in bytes.
    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
    pub fn new_protection(size: usize, prot: Protection) -> Result<MemoryMapping> {
        // This is safe because we are creating an anonymous mapping in a place not already used by
        // any other area in this process.
        unsafe { MemoryMapping::try_mmap(None, size, prot.into(), None) }
    }

    /// Create a Memory mapping from a raw address returned by
    /// the kernel.
    /// # Arguments
    /// * `addr` - Raw pointer to memory region.
    /// * `size` - Size of memory region in bytes.
    pub fn from_raw_ptr(addr: *mut c_void, size: usize) -> Result<MemoryMapping> {
        Ok(MemoryMapping { addr, size })
    }

    pub fn from_raw_handle_offset(
        file_handle: RawDescriptor,
        size: usize,
    ) -> Result<MemoryMapping> {
        // This is safe because we are creating an anonymous mapping in a place not already used by
        // any other area in this process.
        unsafe {
            MemoryMapping::try_mmap(
                None,
                size,
                Protection::read_write().into(),
                Some((file_handle, 0)),
            )
        }
    }

    /// Maps the `size` bytes starting at `offset` bytes of the given `descriptor` as read/write.
    ///
    /// # Arguments
    /// * `file_handle` - File handle to map from.
    /// * `size` - Size of memory region in bytes.
    /// * `offset` - Offset in bytes from the beginning of `descriptor` to start the mmap.
    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
    pub fn from_descriptor_offset_protection(
        file_handle: &dyn AsRawDescriptor,
        size: usize,
        offset: u64,
        prot: Protection,
    ) -> Result<MemoryMapping> {
        // This is safe because we are creating an anonymous mapping in a place not already used by
        // any other area in this process.
        unsafe {
            MemoryMapping::try_mmap(
                None,
                size,
                prot.into(),
                Some((file_handle.as_raw_descriptor(), offset)),
            )
        }
    }

    /// Creates an anonymous shared mapping of `size` bytes with `prot` protection.
    ///
    /// # Safety
    /// Unsafe: unmaps any mmap'd regions already present at (addr..addr+size).
    ///
    /// # Arguments
    /// * `addr` - Memory address to mmap at.
    /// * `size` - Size of memory region in bytes.
    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
    pub unsafe fn new_protection_fixed(
        addr: *mut u8,
        size: usize,
        prot: Protection,
    ) -> Result<MemoryMapping> {
        MemoryMapping::try_mmap(Some(addr), size, prot.into(), None)
    }

    /// Maps the `size` bytes starting at `offset` bytes of the given `descriptor` with
    /// `prot` protections.
    ///
    /// # Safety
    /// Unsafe: unmaps any mmap'd regions already present at (addr..addr+size).
    ///
    /// # Arguments
    /// * `addr` - Memory address to mmap at.
    /// * `descriptor` - File descriptor to mmap from.
    /// * `size` - Size of memory region in bytes.
    /// * `offset` - Offset in bytes from the beginning of `descriptor` to start the mmap.
    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
    pub unsafe fn from_descriptor_offset_protection_fixed(
        addr: *mut u8,
        descriptor: &dyn AsRawDescriptor,
        size: usize,
        offset: u64,
        prot: Protection,
    ) -> Result<MemoryMapping> {
        MemoryMapping::try_mmap(
            Some(addr),
            size,
            prot.into(),
            Some((descriptor.as_raw_descriptor(), offset)),
        )
    }

    /// Calls MapViewOfFile/MapViewOfFileEx with the parameters given
    unsafe fn try_mmap(
        addr: Option<*mut u8>,
        size: usize,
        access_flags: c_uint,
        file_handle: Option<(RawDescriptor, u64)>,
    ) -> Result<MemoryMapping> {
        if file_handle.is_none() {
            // TODO(mikehoyle): For now, do not allow the no-handle scenario. As per comments
            // in guest_memory, the no-handle case is for legacy support and shouldn't have
            // significant usage.
            return Err(Error::InvalidAddress);
        }
        let file_handle = file_handle.unwrap();

        // on windows, pages needed to be of fixed granular size, and the
        // maximum valid value is an i64.
        if file_handle.1 % allocation_granularity() != 0 || file_handle.1 > i64::max_value() as u64
        {
            return Err(Error::InvalidOffset);
        }

        let created_address = match addr {
            Some(addr) => MapViewOfFileEx(
                file_handle.0,
                access_flags,
                get_high_order(file_handle.1),
                get_low_order(file_handle.1),
                size,
                addr as *mut c_void,
            ),
            None => MapViewOfFile(
                file_handle.0,
                access_flags,
                get_high_order(file_handle.1),
                get_low_order(file_handle.1),
                size,
            ),
        };

        if created_address.is_null() {
            return Err(Error::SystemCallFailed(super::Error::last()));
        }

        Ok(MemoryMapping {
            addr: created_address,
            size,
        })
    }

    /// Calls FlushViewOfFile on the mapped memory range, ensuring all changes that would
    /// be written to disk are written immediately
    pub fn msync(&self) -> Result<()> {
        // Safe because self can only be created as a successful memory mapping
        unsafe {
            if FlushViewOfFile(self.addr, self.size) == 0 {
                return Err(Error::SystemCallFailed(super::Error::last()));
            }
        };
        Ok(())
    }

    /// Reads data from a file descriptor and writes it to guest memory.
    ///
    /// # Arguments
    /// * `mem_offset` - Begin writing memory at this offset.
    /// * `src` - Read from `src` to memory.
    /// * `count` - Read `count` bytes from `src` to memory.
    ///
    /// # Examples
    ///
    /// * Read bytes from /dev/urandom
    ///
    /// ```
    ///   use base::platform::MemoryMapping;
    ///   use base::platform::SharedMemory;
    ///   use std::ffi::CString;
    ///   use std::fs::File;
    ///   use std::path::Path;
    ///   fn test_read_random() -> Result<u32, ()> {
    ///       let mut mem_map = MemoryMapping::from_descriptor(
    ///         &SharedMemory::new(&CString::new("test").unwrap(), 1024).unwrap(), 1024).unwrap();
    ///       let mut file = File::open(Path::new("/dev/urandom")).map_err(|_| ())?;
    ///       mem_map.read_to_memory(32, &mut file, 128).map_err(|_| ())?;
    ///       let rand_val: u32 =  mem_map.read_obj(40).map_err(|_| ())?;
    ///       Ok(rand_val)
    ///   }
    /// ```
    pub fn read_to_memory<F: io::Read>(
        &self,
        mem_offset: usize,
        src: &mut F,
        count: usize,
    ) -> Result<()> {
        self.range_end(mem_offset, count)
            .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
        // Safe because the check above ensures that no memory outside this slice will get accessed
        // by this read call.
        let buf: &mut [u8] = unsafe { from_raw_parts_mut(self.as_ptr().add(mem_offset), count) };
        match src.read_exact(buf) {
            Err(e) => Err(Error::ReadToMemory(e)),
            Ok(()) => Ok(()),
        }
    }

    /// Writes data from memory to a file descriptor.
    ///
    /// # Arguments
    /// * `mem_offset` - Begin reading memory from this offset.
    /// * `dst` - Write from memory to `dst`.
    /// * `count` - Read `count` bytes from memory to `src`.
    ///
    /// # Examples
    ///
    /// * Write 128 bytes to /dev/null
    ///
    /// ```
    ///   use base::platform::MemoryMapping;
    ///   use base::platform::SharedMemory;
    ///   use std::ffi::CString;
    ///   use std::fs::File;
    ///   use std::path::Path;
    ///   fn test_write_null() -> Result<(), ()> {
    ///       let mut mem_map = MemoryMapping::from_descriptor(
    ///           &SharedMemory::new(&CString::new("test").unwrap(), 1024).unwrap(), 1024).unwrap();
    ///       let mut file = File::open(Path::new("/dev/null")).map_err(|_| ())?;
    ///       mem_map.write_from_memory(32, &mut file, 128).map_err(|_| ())?;
    ///       Ok(())
    ///   }
    /// ```
    pub fn write_from_memory<F: io::Write>(
        &self,
        mem_offset: usize,
        dst: &mut F,
        count: usize,
    ) -> Result<()> {
        self.range_end(mem_offset, count)
            .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
        // Safe because the check above ensures that no memory outside this slice will get accessed
        // by this write call.
        let buf: &[u8] = unsafe { from_raw_parts(self.as_ptr().add(mem_offset), count) };
        match dst.write_all(buf) {
            Err(e) => Err(Error::WriteFromMemory(e)),
            Ok(()) => Ok(()),
        }
    }
}

impl Drop for MemoryMapping {
    fn drop(&mut self) {
        // This is safe because we MapViewOfFile the area at addr ourselves, and nobody
        // else is holding a reference to it.
        unsafe {
            if UnmapViewOfFile(self.addr) == 0 {
                warn!("Unsuccessful unmap of file: {}", super::Error::last());
            }
        }
    }
}

/// TODO(b/150415526): This is currently an empty implementation to allow simple usages in
/// shared structs. Any attempts to use it will result in compiler errors. It will need
/// to be ported to actually be used on Windows.
pub struct MemoryMappingArena();

#[cfg(test)]
mod tests {
    use super::{
        super::{pagesize, SharedMemory},
        *,
    };
    use crate::descriptor::FromRawDescriptor;
    use std::{ffi::CString, ptr};
    use winapi::shared::winerror;

    #[test]
    fn map_invalid_fd() {
        let descriptor = unsafe { std::fs::File::from_raw_descriptor(ptr::null_mut()) };
        let res = MemoryMapping::from_descriptor(&descriptor, 1024).unwrap_err();
        if let Error::SystemCallFailed(e) = res {
            assert_eq!(e.errno(), winerror::ERROR_INVALID_HANDLE as i32);
        } else {
            panic!("unexpected error: {}", res);
        }
    }

    #[test]
    fn from_descriptor_offset_invalid() {
        let shm = SharedMemory::new(&CString::new("test").unwrap(), 1028).unwrap();
        let res = MemoryMapping::from_descriptor_offset(&shm, 4096, (i64::max_value() as u64) + 1)
            .unwrap_err();
        match res {
            Error::InvalidOffset => {}
            e => panic!("unexpected error: {}", e),
        }
    }

    #[test]
    fn arena_msync() {
        let size: usize = 0x40000;
        let shm = SharedMemory::new(&CString::new("test").unwrap(), size as u64).unwrap();
        let m = MemoryMapping::from_descriptor(&shm, size).unwrap();
        let ps = pagesize();
        <dyn MappedRegion>::msync(&m, 0, ps).unwrap();
        <dyn MappedRegion>::msync(&m, 0, size).unwrap();
        <dyn MappedRegion>::msync(&m, ps, size - ps).unwrap();
        let res = <dyn MappedRegion>::msync(&m, ps, size).unwrap_err();
        match res {
            Error::InvalidAddress => {}
            e => panic!("unexpected error: {}", e),
        }
    }
}
<|endoftext|>


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

#![macro_escape]

/// Entry point of failure, for details, see std::macros
#[macro_export]
macro_rules! fail(
    () => (
        fail!("{}", "explicit failure")
    );
    ($msg:expr) => (
        fail!("{}", $msg)
    );
    ($fmt:expr, $($arg:tt)*) => ({
        // a closure can't have return type !, so we need a full
        // function to pass to format_args!, *and* we need the
        // file and line numbers right here; so an inner bare fn
        // is our only choice.
        //
        // LLVM doesn't tend to inline this, presumably because begin_unwind_fmt
        // is #[cold] and #[inline(never)] and because this is flagged as cold
        // as returning !. We really do want this to be inlined, however,
        // because it's just a tiny wrapper. Small wins (156K to 149K in size)
        // were seen when forcing this to be inlined, and that number just goes
        // up with the number of calls to fail!()
        #[inline(always)]
        fn run_fmt(fmt: &::std::fmt::Arguments) -> ! {
            static file_line: (&'static str, uint) = (file!(), line!());
            ::core::failure::begin_unwind(fmt, &file_line)
        }
        format_args!(run_fmt, $fmt, $($arg)*)
    });
)

/// Runtime assertion, for details see std::macros
#[macro_export]
macro_rules! assert(
    ($cond:expr) => (
        if !$cond {
            fail!(concat!("assertion failed: ", stringify!($cond)))
        }
    );
    ($cond:expr, $($arg:tt)*) => (
        if !$cond {
            fail!($($arg)*)
        }
    );
)

/// Runtime assertion, only without `--cfg ndebug`
#[macro_export]
macro_rules! debug_assert(
    ($(a:tt)*) => ({
        if cfg!(not(ndebug)) {
            assert!($($a)*);
        }
    })
)

/// Runtime assertion for equality, for details see std::macros
#[macro_export]
macro_rules! assert_eq(
    ($cond1:expr, $cond2:expr) => ({
        let c1 = $cond1;
        let c2 = $cond2;
        if c1 != c2 || c2 != c1 {
            fail!("expressions not equal, left: {}, right: {}", c1, c2);
        }
    })
)

/// Runtime assertion for equality, only without `--cfg ndebug`
#[macro_export]
macro_rules! debug_assert_eq(
    ($($a:tt)*) => ({
        if cfg!(not(ndebug)) {
            assert_eq!($($a)*);
        }
    })
)

/// Runtime assertion, disableable at compile time
#[macro_export]
macro_rules! debug_assert(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
)

/// Short circuiting evaluation on Err
#[macro_export]
macro_rules! try(
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
)

/// Writing a formatted string into a writer
#[macro_export]
macro_rules! write(
    ($dst:expr, $($arg:tt)*) => (format_args_method!($dst, write_fmt, $($arg)*))
)

/// Writing a formatted string plus a newline into a writer
#[macro_export]
macro_rules! writeln(
    ($dst:expr, $fmt:expr $($arg:tt)*) => (
        write!($dst, concat!($fmt, "\n") $($arg)*)
    )
)

/// Write some formatted data into a stream.
///
/// Identical to the macro in `std::macros`
#[macro_export]
macro_rules! write(
    ($dst:expr, $($arg:tt)*) => ({
        format_args_method!($dst, write_fmt, $($arg)*)
    })
)

#[macro_export]
macro_rules! unreachable( () => (fail!("unreachable code")) )
<commit_msg>Use correct conventions for static<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![macro_escape]

/// Entry point of failure, for details, see std::macros
#[macro_export]
macro_rules! fail(
    () => (
        fail!("{}", "explicit failure")
    );
    ($msg:expr) => (
        fail!("{}", $msg)
    );
    ($fmt:expr, $($arg:tt)*) => ({
        // a closure can't have return type !, so we need a full
        // function to pass to format_args!, *and* we need the
        // file and line numbers right here; so an inner bare fn
        // is our only choice.
        //
        // LLVM doesn't tend to inline this, presumably because begin_unwind_fmt
        // is #[cold] and #[inline(never)] and because this is flagged as cold
        // as returning !. We really do want this to be inlined, however,
        // because it's just a tiny wrapper. Small wins (156K to 149K in size)
        // were seen when forcing this to be inlined, and that number just goes
        // up with the number of calls to fail!()
        #[inline(always)]
        fn run_fmt(fmt: &::std::fmt::Arguments) -> ! {
            static FILE_LINE: (&'static str, uint) = (file!(), line!());
            ::core::failure::begin_unwind(fmt, &FILE_LINE)
        }
        format_args!(run_fmt, $fmt, $($arg)*)
    });
)

/// Runtime assertion, for details see std::macros
#[macro_export]
macro_rules! assert(
    ($cond:expr) => (
        if !$cond {
            fail!(concat!("assertion failed: ", stringify!($cond)))
        }
    );
    ($cond:expr, $($arg:tt)*) => (
        if !$cond {
            fail!($($arg)*)
        }
    );
)

/// Runtime assertion, only without `--cfg ndebug`
#[macro_export]
macro_rules! debug_assert(
    ($(a:tt)*) => ({
        if cfg!(not(ndebug)) {
            assert!($($a)*);
        }
    })
)

/// Runtime assertion for equality, for details see std::macros
#[macro_export]
macro_rules! assert_eq(
    ($cond1:expr, $cond2:expr) => ({
        let c1 = $cond1;
        let c2 = $cond2;
        if c1 != c2 || c2 != c1 {
            fail!("expressions not equal, left: {}, right: {}", c1, c2);
        }
    })
)

/// Runtime assertion for equality, only without `--cfg ndebug`
#[macro_export]
macro_rules! debug_assert_eq(
    ($($a:tt)*) => ({
        if cfg!(not(ndebug)) {
            assert_eq!($($a)*);
        }
    })
)

/// Runtime assertion, disableable at compile time
#[macro_export]
macro_rules! debug_assert(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
)

/// Short circuiting evaluation on Err
#[macro_export]
macro_rules! try(
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
)

/// Writing a formatted string into a writer
#[macro_export]
macro_rules! write(
    ($dst:expr, $($arg:tt)*) => (format_args_method!($dst, write_fmt, $($arg)*))
)

/// Writing a formatted string plus a newline into a writer
#[macro_export]
macro_rules! writeln(
    ($dst:expr, $fmt:expr $($arg:tt)*) => (
        write!($dst, concat!($fmt, "\n") $($arg)*)
    )
)

/// Write some formatted data into a stream.
///
/// Identical to the macro in `std::macros`
#[macro_export]
macro_rules! write(
    ($dst:expr, $($arg:tt)*) => ({
        format_args_method!($dst, write_fmt, $($arg)*)
    })
)

#[macro_export]
macro_rules! unreachable( () => (fail!("unreachable code")) )
<|endoftext|>