<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

use glib::ffi::GType;
use gtk;
use gtk::TreeIter;
use gtk::ffi;
use std::c_str::CString;
use std::string::raw::from_buf;

pub struct TreeModel {
    pointer: *mut ffi::C_GtkTreeModel
}

impl TreeModel {
    pub fn get_flags(&self) -> gtk::TreeModelFlags {
        unsafe { ffi::gtk_tree_model_get_flags(self.pointer) }
    }

    pub fn get_n_columns(&self) -> i32 {
        unsafe { ffi::gtk_tree_model_get_n_columns(self.pointer) }
    }

    pub fn get_column_type(&self, index_: i32) -> GType {
        unsafe { ffi::gtk_tree_model_get_column_type(self.pointer, index_) }
    }

    pub fn get_iter(&self, iter: &TreeIter, path: &gtk::TreePath) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter(self.pointer, iter.get_pointer(), path.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_iter_from_string(&self, iter: &TreeIter, path_string: &str) -> bool {
        path_string.with_c_str(|c_str| {
            match unsafe { ffi::gtk_tree_model_get_iter_from_string(self.pointer, iter.get_pointer(), c_str) } {
                0 => false,
                _ => true
            }
        })
    }

    pub fn get_iter_first(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter_first(self.pointer, iter.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_path(&self, iter: &TreeIter) -> Option<gtk::TreePath> {
        let tmp_pointer = unsafe { ffi::gtk_tree_model_get_path(self.pointer, iter.get_pointer()) };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(gtk::TreePath::wrap_pointer(tmp_pointer))
        }
    }

    pub fn iter_next(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_next(self.pointer, iter.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_previous(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_previous(self.pointer, iter.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_children(&self, iter: &TreeIter, parent: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_children(self.pointer, iter.get_pointer(), parent.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_has_child(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_has_child(self.pointer, iter.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_n_children(&self, iter: &TreeIter) -> i32 {
        unsafe { ffi::gtk_tree_model_iter_n_children(self.pointer, iter.get_pointer()) }
    }

    pub fn iter_nth_child(&self, iter: &TreeIter, parent: &TreeIter, n: i32) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_nth_child(self.pointer, iter.get_pointer(), parent.get_pointer(), n) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_parent(&self, iter: &TreeIter, child: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_parent(self.pointer, iter.get_pointer(), child.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    #[allow(unused_variable)]
    pub fn get_string_from_iter(&self, iter: &TreeIter) -> String {
        let string = unsafe { ffi::gtk_tree_model_get_string_from_iter(self.pointer, iter.get_pointer()) };

        if string.is_null() {
            String::new()
        } else {
            unsafe {
                // used to free the returned string
                let container = CString::new(string as *const i8, true);

                from_buf(string as *const u8)
            }
        }
    }

    pub fn row_changed(&self, path: &gtk::TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_changed(self.pointer, path.get_pointer(), iter.get_pointer()) }
    }

    pub fn row_inserted(&self, path: &gtk::TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_inserted(self.pointer, path.get_pointer(), iter.get_pointer()) }
    }

    pub fn row_has_child_toggled(&self, path: &gtk::TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_has_child_toggled(self.pointer, path.get_pointer(), iter.get_pointer()) }
    }

    pub fn row_deleted(&self, path: &gtk::TreePath) {
        unsafe { ffi::gtk_tree_model_row_deleted(self.pointer, path.get_pointer()) }
    }

    pub fn rows_reordered(&self, path: &gtk::TreePath, iter: &TreeIter, new_order: &mut [i32]) {
        unsafe { ffi::gtk_tree_model_rows_reordered(self.pointer, path.get_pointer(), iter.get_pointer(), new_order.as_mut_ptr()) }
    }

    pub fn ref_node(&self, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_ref_node(self.pointer, iter.get_pointer()) }
    }

    pub fn unref_node(&self, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_unref_node(self.pointer, iter.get_pointer()) }
    }

    #[doc(hidden)]
    pub fn get_pointer(&self) -> *mut ffi::C_GtkTreeModel {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treemodel: *mut ffi::C_GtkTreeModel) -> TreeModel {
        TreeModel {
            pointer: c_treemodel
        }
    }
}

impl Drop for TreeModel {
    fn drop(&mut self) {
        unsafe {
            ::glib::ffi::g_object_unref(self.pointer as *mut ::glib::ffi::C_GObject);
        }
    }
}

impl Clone for TreeModel {
    fn clone(&self) -> TreeModel {
        let pointer = unsafe {
            ::glib::ffi::g_object_ref(self.pointer as *mut ::glib::ffi::C_GObject)
        };

        TreeModel {
            pointer: pointer as *mut ffi::C_GtkTreeModel
        }
    }
}
<commit_msg>Import name for brevity<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

use glib::ffi::GType;
use gtk;
use gtk::{TreeIter, TreePath};
use gtk::ffi;
use std::c_str::CString;
use std::string::raw::from_buf;

pub struct TreeModel {
    pointer: *mut ffi::C_GtkTreeModel
}

impl TreeModel {
    pub fn get_flags(&self) -> gtk::TreeModelFlags {
        unsafe { ffi::gtk_tree_model_get_flags(self.pointer) }
    }

    pub fn get_n_columns(&self) -> i32 {
        unsafe { ffi::gtk_tree_model_get_n_columns(self.pointer) }
    }

    pub fn get_column_type(&self, index_: i32) -> GType {
        unsafe { ffi::gtk_tree_model_get_column_type(self.pointer, index_) }
    }

    pub fn get_iter(&self, iter: &TreeIter, path: &TreePath) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter(self.pointer, iter.get_pointer(), path.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_iter_from_string(&self, iter: &TreeIter, path_string: &str) -> bool {
        path_string.with_c_str(|c_str| {
            match unsafe { ffi::gtk_tree_model_get_iter_from_string(self.pointer, iter.get_pointer(), c_str) } {
                0 => false,
                _ => true
            }
        })
    }

    pub fn get_iter_first(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter_first(self.pointer, iter.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_path(&self, iter: &TreeIter) -> Option<TreePath> {
        let tmp_pointer = unsafe { ffi::gtk_tree_model_get_path(self.pointer, iter.get_pointer()) };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(TreePath::wrap_pointer(tmp_pointer))
        }
    }

    pub fn iter_next(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_next(self.pointer, iter.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_previous(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_previous(self.pointer, iter.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_children(&self, iter: &TreeIter, parent: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_children(self.pointer, iter.get_pointer(), parent.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_has_child(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_has_child(self.pointer, iter.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_n_children(&self, iter: &TreeIter) -> i32 {
        unsafe { ffi::gtk_tree_model_iter_n_children(self.pointer, iter.get_pointer()) }
    }

    pub fn iter_nth_child(&self, iter: &TreeIter, parent: &TreeIter, n: i32) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_nth_child(self.pointer, iter.get_pointer(), parent.get_pointer(), n) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_parent(&self, iter: &TreeIter, child: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_parent(self.pointer, iter.get_pointer(), child.get_pointer()) } {
            0 => false,
            _ => true
        }
    }

    #[allow(unused_variable)]
    pub fn get_string_from_iter(&self, iter: &TreeIter) -> String {
        let string = unsafe { ffi::gtk_tree_model_get_string_from_iter(self.pointer, iter.get_pointer()) };

        if string.is_null() {
            String::new()
        } else {
            unsafe {
                // used to free the returned string
                let container = CString::new(string as *const i8, true);

                from_buf(string as *const u8)
            }
        }
    }

    pub fn row_changed(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_changed(self.pointer, path.get_pointer(), iter.get_pointer()) }
    }

    pub fn row_inserted(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_inserted(self.pointer, path.get_pointer(), iter.get_pointer()) }
    }

    pub fn row_has_child_toggled(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_has_child_toggled(self.pointer, path.get_pointer(), iter.get_pointer()) }
    }

    pub fn row_deleted(&self, path: &TreePath) {
        unsafe { ffi::gtk_tree_model_row_deleted(self.pointer, path.get_pointer()) }
    }

    pub fn rows_reordered(&self, path: &TreePath, iter: &TreeIter, new_order: &mut [i32]) {
        unsafe { ffi::gtk_tree_model_rows_reordered(self.pointer, path.get_pointer(), iter.get_pointer(), new_order.as_mut_ptr()) }
    }

    pub fn ref_node(&self, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_ref_node(self.pointer, iter.get_pointer()) }
    }

    pub fn unref_node(&self, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_unref_node(self.pointer, iter.get_pointer()) }
    }

    #[doc(hidden)]
    pub fn get_pointer(&self) -> *mut ffi::C_GtkTreeModel {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treemodel: *mut ffi::C_GtkTreeModel) -> TreeModel {
        TreeModel {
            pointer: c_treemodel
        }
    }
}

impl Drop for TreeModel {
    fn drop(&mut self) {
        unsafe {
            ::glib::ffi::g_object_unref(self.pointer as *mut ::glib::ffi::C_GObject);
        }
    }
}

impl Clone for TreeModel {
    fn clone(&self) -> TreeModel {
        let pointer = unsafe {
            ::glib::ffi::g_object_ref(self.pointer as *mut ::glib::ffi::C_GObject)
        };

        TreeModel {
            pointer: pointer as *mut ffi::C_GtkTreeModel
        }
    }
}
<|endoftext|>


<commit_before>use dora_asm::arm64::Cond;
use lazy_static::lazy_static;

use crate::masm::CondCode;

#[cfg(target_os = "macos")]
pub fn flush_icache(start: *const u8, len: usize) {
    extern "C" {
        fn sys_icache_invalidate(data: *const u8, len: usize);
    }

    unsafe {
        sys_icache_invalidate(start, len);
    }
}

#[cfg(not(target_os = "macos"))]
pub fn flush_icache(start: *const u8, len: usize) {
    let start = start as usize;
    let end = start + len;

    let (icacheline_size, dcacheline_size) = cacheline_sizes();

    let istart = start & !(icacheline_size - 1);
    let dstart = start & !(dcacheline_size - 1);

    let mut ptr = dstart;

    while ptr < end {
        unsafe {
            llvm_asm!("dc civac, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += dcacheline_size;
    }

    unsafe {
        llvm_asm!("dsb ish" ::: "memory" : "volatile");
    }

    ptr = istart;

    while ptr < end {
        unsafe {
            llvm_asm!("ic ivau, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += icacheline_size;
    }

    unsafe {
        llvm_asm!("dsb ish
              isb" ::: "memory" : "volatile");
    }
}

pub fn has_lse_atomics() -> bool {
    *HAS_LSE_ATOMICS
}

lazy_static! {
static ref HAS_LSE_ATOMICS: bool = check_support_for_lse_atomics();
}

#[cfg(target_os = "macos")]
fn check_support_for_lse_atomics() -> bool {
    use std::ffi::CString;

    unsafe {
        let mut oldbuffer: usize = 0;
        let mut oldlenp: libc::size_t = 4;
        let name = CString::new("hw.optional.armv8_1_atomics").unwrap();
        let result = libc::sysctlbyname(
            name.as_ptr(),
            &mut oldbuffer as *mut usize as *mut libc::c_void,
            &mut oldlenp,
            std::ptr::null_mut(),
            0,
        );
        assert_eq!(result, 0);
        oldbuffer != 0
    }
}

#[cfg(not(target_os = "macos"))]
fn check_support_for_lse_atomics() -> bool {
    let value: usize;
    unsafe {
        llvm_asm!("mrs $0, ID_AA64DFR1_EL1": "=r"(value)::: "volatile");
    }
    (value >> 20) & 0xF == 0b0010
}

#[cfg(not(target_os = "macos"))]
pub fn cacheline_sizes() -> (usize, usize) {
    let value: usize;

    unsafe {
        llvm_asm!("mrs $0, ctr_el0": "=r"(value)::: "volatile");
    }

    let insn = 4 << (value & 0xF);
    let data = 4 << ((value >> 16) & 0xF);

    (insn, data)
}

pub fn has_round() -> bool {
    true
}

pub fn has_popcnt() -> bool {
    true
}

pub fn has_lzcnt() -> bool {
    true
}

pub fn has_tzcnt() -> bool {
    true
}

impl From<CondCode> for Cond {
    fn from(c: CondCode) -> Cond {
        match c {
            CondCode::Zero => Cond::EQ,
            CondCode::NonZero => Cond::NE,
            CondCode::Equal => Cond::EQ,
            CondCode::NotEqual => Cond::NE,
            CondCode::Greater => Cond::GT,
            CondCode::GreaterEq => Cond::GE,
            CondCode::Less => Cond::LT,
            CondCode::LessEq => Cond::LE,
            CondCode::UnsignedGreater => Cond::HI,
            CondCode::UnsignedGreaterEq => Cond::HS,
            CondCode::UnsignedLess => Cond::LO,
            CondCode::UnsignedLessEq => Cond::LS,
        }
    }
}

use crate::cpu::{FReg, Reg};
use crate::ty::SourceType;
use dora_asm::arm64 as asm;
use dora_asm::arm64::Register;

pub static REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static CCALL_REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static CCALL_FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static SCRATCH: [Reg; 5] = [R9, R12, R13, R14, R15];

pub const REG_RESULT: Reg = R0;
pub const REG_TMP1: Reg = R10;
pub const REG_TMP2: Reg = R11;
pub const REG_FP: Reg = R29;
pub const REG_LR: Reg = R30;
pub const REG_THREAD: Reg = R28;

pub const REG_SP: Reg = Reg(32);
pub const REG_ZERO: Reg = Reg(33);

pub const FREG_RESULT: FReg = F0;

// shall not overlap with param registers
pub const FREG_TMP1: FReg = F16;

pub const STACK_FRAME_ALIGNMENT: usize = 16;

pub const R0: Reg = Reg(0);
pub const R1: Reg = Reg(1);
pub const R2: Reg = Reg(2);
pub const R3: Reg = Reg(3);
pub const R4: Reg = Reg(4);
pub const R5: Reg = Reg(5);
pub const R6: Reg = Reg(6);
pub const R7: Reg = Reg(7);
pub const R8: Reg = Reg(8);
pub const R9: Reg = Reg(9);
pub const R10: Reg = Reg(10);
pub const R11: Reg = Reg(11);
pub const R12: Reg = Reg(12);
pub const R13: Reg = Reg(13);
pub const R14: Reg = Reg(14);
pub const R15: Reg = Reg(15);
pub const R16: Reg = Reg(16);
pub const R17: Reg = Reg(17);
pub const R18: Reg = Reg(18);
pub const R19: Reg = Reg(19);
pub const R20: Reg = Reg(20);
pub const R21: Reg = Reg(21);
pub const R22: Reg = Reg(22);
pub const R23: Reg = Reg(23);
pub const R24: Reg = Reg(24);
pub const R25: Reg = Reg(25);
pub const R26: Reg = Reg(26);
pub const R27: Reg = Reg(27);
pub const R28: Reg = Reg(28);
pub const R29: Reg = Reg(29);
pub const R30: Reg = Reg(30);

pub const F0: FReg = FReg(0);
pub const F1: FReg = FReg(1);
pub const F2: FReg = FReg(2);
pub const F3: FReg = FReg(3);
pub const F4: FReg = FReg(4);
pub const F5: FReg = FReg(5);
pub const F6: FReg = FReg(6);
pub const F7: FReg = FReg(7);
pub const F8: FReg = FReg(8);
pub const F9: FReg = FReg(9);
pub const F10: FReg = FReg(10);
pub const F11: FReg = FReg(11);
pub const F12: FReg = FReg(12);
pub const F13: FReg = FReg(13);
pub const F14: FReg = FReg(14);
pub const F15: FReg = FReg(15);
pub const F16: FReg = FReg(16);
pub const F17: FReg = FReg(17);
pub const F18: FReg = FReg(18);
pub const F19: FReg = FReg(19);
pub const F20: FReg = FReg(20);
pub const F21: FReg = FReg(21);
pub const F22: FReg = FReg(22);
pub const F23: FReg = FReg(23);
pub const F24: FReg = FReg(24);
pub const F25: FReg = FReg(25);
pub const F26: FReg = FReg(26);
pub const F27: FReg = FReg(27);
pub const F28: FReg = FReg(28);
pub const F29: FReg = FReg(29);
pub const F30: FReg = FReg(30);
pub const F31: FReg = FReg(31);

impl Reg {
    pub fn asm(self) -> u32 {
        match self {
            REG_SP => 31,
            REG_ZERO => 31,
            _ => self.0 as u32,
        }
    }

    pub fn is_gpr(self) -> bool {
        self.0 <= 30
    }

    pub fn is_gpr_or_zero(self) -> bool {
        self.is_gpr() || self == REG_ZERO
    }

    pub fn is_gpr_or_sp(self) -> bool {
        self.is_gpr() || self == REG_SP
    }
}

impl From<Reg> for Register {
    fn from(reg: Reg) -> Register {
        if reg.0 < 31 {
            Register::new(reg.0)
        } else if reg == REG_ZERO {
            asm::REG_ZERO
        } else {
            assert_eq!(reg, REG_SP);
            asm::REG_SP
        }
    }
}

impl FReg {
    pub fn asm(self) -> u32 {
        assert!(self.0 < 32);
        self.0 as u32
    }
}

pub static PARAM_OFFSET: i32 = 16;

pub fn next_param_offset(param_offset: i32, _: SourceType) -> i32 {
    param_offset + 8
}
<commit_msg>reformat<commit_after>use dora_asm::arm64::Cond;
use lazy_static::lazy_static;

use crate::masm::CondCode;

#[cfg(target_os = "macos")]
pub fn flush_icache(start: *const u8, len: usize) {
    extern "C" {
        fn sys_icache_invalidate(data: *const u8, len: usize);
    }

    unsafe {
        sys_icache_invalidate(start, len);
    }
}

#[cfg(not(target_os = "macos"))]
pub fn flush_icache(start: *const u8, len: usize) {
    let start = start as usize;
    let end = start + len;

    let (icacheline_size, dcacheline_size) = cacheline_sizes();

    let istart = start & !(icacheline_size - 1);
    let dstart = start & !(dcacheline_size - 1);

    let mut ptr = dstart;

    while ptr < end {
        unsafe {
            llvm_asm!("dc civac, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += dcacheline_size;
    }

    unsafe {
        llvm_asm!("dsb ish" ::: "memory" : "volatile");
    }

    ptr = istart;

    while ptr < end {
        unsafe {
            llvm_asm!("ic ivau, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += icacheline_size;
    }

    unsafe {
        llvm_asm!("dsb ish
              isb" ::: "memory" : "volatile");
    }
}

pub fn has_lse_atomics() -> bool {
    *HAS_LSE_ATOMICS
}

lazy_static! {
    static ref HAS_LSE_ATOMICS: bool = check_support_for_lse_atomics();
}

#[cfg(target_os = "macos")]
fn check_support_for_lse_atomics() -> bool {
    use std::ffi::CString;

    unsafe {
        let mut oldbuffer: usize = 0;
        let mut oldlenp: libc::size_t = 4;
        let name = CString::new("hw.optional.armv8_1_atomics").unwrap();
        let result = libc::sysctlbyname(
            name.as_ptr(),
            &mut oldbuffer as *mut usize as *mut libc::c_void,
            &mut oldlenp,
            std::ptr::null_mut(),
            0,
        );
        assert_eq!(result, 0);
        oldbuffer != 0
    }
}

#[cfg(not(target_os = "macos"))]
fn check_support_for_lse_atomics() -> bool {
    let value: usize;
    unsafe {
        llvm_asm!("mrs $0, ID_AA64DFR1_EL1": "=r"(value)::: "volatile");
    }
    (value >> 20) & 0xF == 0b0010
}

#[cfg(not(target_os = "macos"))]
pub fn cacheline_sizes() -> (usize, usize) {
    let value: usize;

    unsafe {
        llvm_asm!("mrs $0, ctr_el0": "=r"(value)::: "volatile");
    }

    let insn = 4 << (value & 0xF);
    let data = 4 << ((value >> 16) & 0xF);

    (insn, data)
}

pub fn has_round() -> bool {
    true
}

pub fn has_popcnt() -> bool {
    true
}

pub fn has_lzcnt() -> bool {
    true
}

pub fn has_tzcnt() -> bool {
    true
}

impl From<CondCode> for Cond {
    fn from(c: CondCode) -> Cond {
        match c {
            CondCode::Zero => Cond::EQ,
            CondCode::NonZero => Cond::NE,
            CondCode::Equal => Cond::EQ,
            CondCode::NotEqual => Cond::NE,
            CondCode::Greater => Cond::GT,
            CondCode::GreaterEq => Cond::GE,
            CondCode::Less => Cond::LT,
            CondCode::LessEq => Cond::LE,
            CondCode::UnsignedGreater => Cond::HI,
            CondCode::UnsignedGreaterEq => Cond::HS,
            CondCode::UnsignedLess => Cond::LO,
            CondCode::UnsignedLessEq => Cond::LS,
        }
    }
}

use crate::cpu::{FReg, Reg};
use crate::ty::SourceType;
use dora_asm::arm64 as asm;
use dora_asm::arm64::Register;

pub static REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static CCALL_REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static CCALL_FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static SCRATCH: [Reg; 5] = [R9, R12, R13, R14, R15];

pub const REG_RESULT: Reg = R0;
pub const REG_TMP1: Reg = R10;
pub const REG_TMP2: Reg = R11;
pub const REG_FP: Reg = R29;
pub const REG_LR: Reg = R30;
pub const REG_THREAD: Reg = R28;

pub const REG_SP: Reg = Reg(32);
pub const REG_ZERO: Reg = Reg(33);

pub const FREG_RESULT: FReg = F0;

// shall not overlap with param registers
pub const FREG_TMP1: FReg = F16;

pub const STACK_FRAME_ALIGNMENT: usize = 16;

pub const R0: Reg = Reg(0);
pub const R1: Reg = Reg(1);
pub const R2: Reg = Reg(2);
pub const R3: Reg = Reg(3);
pub const R4: Reg = Reg(4);
pub const R5: Reg = Reg(5);
pub const R6: Reg = Reg(6);
pub const R7: Reg = Reg(7);
pub const R8: Reg = Reg(8);
pub const R9: Reg = Reg(9);
pub const R10: Reg = Reg(10);
pub const R11: Reg = Reg(11);
pub const R12: Reg = Reg(12);
pub const R13: Reg = Reg(13);
pub const R14: Reg = Reg(14);
pub const R15: Reg = Reg(15);
pub const R16: Reg = Reg(16);
pub const R17: Reg = Reg(17);
pub const R18: Reg = Reg(18);
pub const R19: Reg = Reg(19);
pub const R20: Reg = Reg(20);
pub const R21: Reg = Reg(21);
pub const R22: Reg = Reg(22);
pub const R23: Reg = Reg(23);
pub const R24: Reg = Reg(24);
pub const R25: Reg = Reg(25);
pub const R26: Reg = Reg(26);
pub const R27: Reg = Reg(27);
pub const R28: Reg = Reg(28);
pub const R29: Reg = Reg(29);
pub const R30: Reg = Reg(30);

pub const F0: FReg = FReg(0);
pub const F1: FReg = FReg(1);
pub const F2: FReg = FReg(2);
pub const F3: FReg = FReg(3);
pub const F4: FReg = FReg(4);
pub const F5: FReg = FReg(5);
pub const F6: FReg = FReg(6);
pub const F7: FReg = FReg(7);
pub const F8: FReg = FReg(8);
pub const F9: FReg = FReg(9);
pub const F10: FReg = FReg(10);
pub const F11: FReg = FReg(11);
pub const F12: FReg = FReg(12);
pub const F13: FReg = FReg(13);
pub const F14: FReg = FReg(14);
pub const F15: FReg = FReg(15);
pub const F16: FReg = FReg(16);
pub const F17: FReg = FReg(17);
pub const F18: FReg = FReg(18);
pub const F19: FReg = FReg(19);
pub const F20: FReg = FReg(20);
pub const F21: FReg = FReg(21);
pub const F22: FReg = FReg(22);
pub const F23: FReg = FReg(23);
pub const F24: FReg = FReg(24);
pub const F25: FReg = FReg(25);
pub const F26: FReg = FReg(26);
pub const F27: FReg = FReg(27);
pub const F28: FReg = FReg(28);
pub const F29: FReg = FReg(29);
pub const F30: FReg = FReg(30);
pub const F31: FReg = FReg(31);

impl Reg {
    pub fn asm(self) -> u32 {
        match self {
            REG_SP => 31,
            REG_ZERO => 31,
            _ => self.0 as u32,
        }
    }

    pub fn is_gpr(self) -> bool {
        self.0 <= 30
    }

    pub fn is_gpr_or_zero(self) -> bool {
        self.is_gpr() || self == REG_ZERO
    }

    pub fn is_gpr_or_sp(self) -> bool {
        self.is_gpr() || self == REG_SP
    }
}

impl From<Reg> for Register {
    fn from(reg: Reg) -> Register {
        if reg.0 < 31 {
            Register::new(reg.0)
        } else if reg == REG_ZERO {
            asm::REG_ZERO
        } else {
            assert_eq!(reg, REG_SP);
            asm::REG_SP
        }
    }
}

impl FReg {
    pub fn asm(self) -> u32 {
        assert!(self.0 < 32);
        self.0 as u32
    }
}

pub static PARAM_OFFSET: i32 = 16;

pub fn next_param_offset(param_offset: i32, _: SourceType) -> i32 {
    param_offset + 8
}
<|endoftext|>


<commit_before>#[repr(C)]
pub struct MBuf {
    buf_addr: *mut u8,
    phys_addr: usize,
    data_off: u16,
    refcnt: u16,
    nb_segs: u8,
    port: u8,
    ol_flags: u64,
    packet_type: u32,
    pkt_len: u32,
    data_len: u16,
    vlan_tci: u16,
    hash: u64,
    vlan_tci_outer: u32,
    buf_len: u16,
    timestamp: u64,
    userdata: u64,
    pool: u64,
    next: *mut MBuf,
    tx_offload: u64,
    priv_size: u16,
    timesync: u16,
    seqn: u32,
}

// FIXME: Remove this once we start using these functions correctly
#[allow(dead_code)]
impl MBuf {
    #[inline]
    pub fn read_metadata_slot(mbuf: *mut MBuf, slot: usize) -> usize {
        unsafe {
            let ptr = (mbuf.offset(1) as *mut usize).offset(slot as isize);
            *ptr
        }
    }

    #[inline]
    pub fn write_metadata_slot(mbuf: *mut MBuf, slot: usize, value: usize) {
        unsafe {
            let ptr = (mbuf.offset(1) as *mut usize).offset(slot as isize);
            *ptr = value;
        }
    }

    #[inline]
    pub unsafe fn metadata_as<T: Sized>(mbuf: *const MBuf, slot: usize) -> *const T {
        (mbuf.offset(1) as *const usize).offset(slot as isize) as *const T
    }

    #[inline]
    pub unsafe fn mut_metadata_as<T: Sized>(mbuf: *mut MBuf, slot: usize) -> *mut T {
        (mbuf.offset(1) as *mut usize).offset(slot as isize) as *mut T
    }

    #[inline]
    pub fn data_address(&self, offset: usize) -> *mut u8 {
        unsafe {
            self.buf_addr
                .offset(self.data_off as isize + offset as isize)
        }
    }

    /// Returns the total allocated size of this mbuf segment.
    /// This is a constant.
    #[inline]
    pub fn buf_len(&self) -> usize {
        self.buf_len as usize
    }

    /// Returns the length of data in this mbuf segment.
    #[inline]
    pub fn data_len(&self) -> usize {
        self.data_len as usize
    }

    /// Returns the size of the packet (across multiple mbuf segment).
    #[inline]
    pub fn pkt_len(&self) -> usize {
        self.pkt_len as usize
    }

    #[inline]
    fn pkt_headroom(&self) -> usize {
        self.data_off as usize
    }

    #[inline]
    fn pkt_tailroom(&self) -> usize {
        self.buf_len() - self.data_off as usize - self.data_len()
    }

    /// Add data to the beginning of the packet. This might fail (i.e., return 0) when no more headroom is left.
    #[inline]
    pub fn add_data_beginning(&mut self, len: usize) -> usize {
        // If only we could add a likely here.
        if len > self.pkt_headroom() {
            0
        } else {
            self.data_off -= len as u16;
            self.data_len += len as u16;
            self.pkt_len += len as u32;
            len
        }
    }

    /// Add data to the end of a packet buffer. This might fail (i.e., return 0) when no more tailroom is left. We do
    /// not currently deal with packet with multiple segments.
    #[inline]
    pub fn add_data_end(&mut self, len: usize) -> usize {
        if len > self.pkt_tailroom() {
            0
        } else {
            self.data_len += len as u16;
            self.pkt_len += len as u32;
            len
        }
    }

    #[inline]
    pub fn remove_data_beginning(&mut self, len: usize) -> usize {
        if len > self.data_len() {
            0
        } else {
            self.data_off += len as u16;
            self.data_len -= len as u16;
            self.pkt_len -= len as u32;
            len
        }
    }

    #[inline]
    pub fn remove_data_end(&mut self, len: usize) -> usize {
        if len > self.data_len() {
            0
        } else {
            self.data_len -= len as u16;
            self.pkt_len -= len as u32;
            len
        }
    }

    #[inline]
    pub fn refcnt(&self) -> u16 {
        self.refcnt
    }

    #[inline]
    pub fn reference(&mut self) {
        self.refcnt += 1;
    }
}
<commit_msg>packet: Take mbuf struct fromDPDK<commit_after>use super::super::super::native_include as ldpdk;
pub type MBuf = ldpdk::rte_mbuf;

// FIXME: Remove this once we start using these functions correctly
#[allow(dead_code)]
impl MBuf {
    #[inline]
    pub fn read_metadata_slot(mbuf: *mut MBuf, slot: usize) -> usize {
        unsafe {
            let ptr = (mbuf.offset(1) as *mut usize).offset(slot as isize);
            *ptr
        }
    }

    #[inline]
    pub fn write_metadata_slot(mbuf: *mut MBuf, slot: usize, value: usize) {
        unsafe {
            let ptr = (mbuf.offset(1) as *mut usize).offset(slot as isize);
            *ptr = value;
        }
    }

    #[inline]
    pub unsafe fn metadata_as<T: Sized>(mbuf: *const MBuf, slot: usize) -> *const T {
        (mbuf.offset(1) as *const usize).offset(slot as isize) as *const T
    }

    #[inline]
    pub unsafe fn mut_metadata_as<T: Sized>(mbuf: *mut MBuf, slot: usize) -> *mut T {
        (mbuf.offset(1) as *mut usize).offset(slot as isize) as *mut T
    }

    #[inline]
    pub fn data_address(&self, offset: usize) -> *mut u8 {
        unsafe { (self.buf_addr as *mut u8).offset(self.data_off as isize + offset as isize) }
    }

    /// Returns the total allocated size of this mbuf segment.
    /// This is a constant.
    #[inline]
    pub fn buf_len(&self) -> usize {
        self.buf_len as usize
    }

    /// Returns the length of data in this mbuf segment.
    #[inline]
    pub fn data_len(&self) -> usize {
        self.data_len as usize
    }

    /// Returns the size of the packet (across multiple mbuf segment).
    #[inline]
    pub fn pkt_len(&self) -> usize {
        self.pkt_len as usize
    }

    #[inline]
    fn pkt_headroom(&self) -> usize {
        self.data_off as usize
    }

    #[inline]
    fn pkt_tailroom(&self) -> usize {
        self.buf_len() - self.data_off as usize - self.data_len()
    }

    /// Add data to the beginning of the packet. This might fail (i.e., return 0) when no more headroom is left.
    #[inline]
    pub fn add_data_beginning(&mut self, len: usize) -> usize {
        // If only we could add a likely here.
        if len > self.pkt_headroom() {
            0
        } else {
            self.data_off -= len as u16;
            self.data_len += len as u16;
            self.pkt_len += len as u32;
            len
        }
    }

    /// Add data to the end of a packet buffer. This might fail (i.e., return 0) when no more tailroom is left. We do
    /// not currently deal with packet with multiple segments.
    #[inline]
    pub fn add_data_end(&mut self, len: usize) -> usize {
        if len > self.pkt_tailroom() {
            0
        } else {
            self.data_len += len as u16;
            self.pkt_len += len as u32;
            len
        }
    }

    #[inline]
    pub fn remove_data_beginning(&mut self, len: usize) -> usize {
        if len > self.data_len() {
            0
        } else {
            self.data_off += len as u16;
            self.data_len -= len as u16;
            self.pkt_len -= len as u32;
            len
        }
    }

    #[inline]
    pub fn remove_data_end(&mut self, len: usize) -> usize {
        if len > self.data_len() {
            0
        } else {
            self.data_len -= len as u16;
            self.pkt_len -= len as u32;
            len
        }
    }

    #[inline]
    pub fn refcnt(&self) -> u16 {
        unsafe { self.__bindgen_anon_1.refcnt }
    }

    #[inline]
    pub fn reference(&mut self) {
        unsafe {
            self.__bindgen_anon_1.refcnt += 1;
        }
    }
}
<|endoftext|>


<commit_before>use rustwlc::{input, Point, ResizeEdge, Geometry,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM,
              RESIZE_TOPLEFT, RESIZE_TOPRIGHT, RESIZE_BOTTOMLEFT, RESIZE_BOTTOMRIGHT,
};

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType, MIN_SIZE};
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 {
    /// Updates pointer position for the node behind the id,
    /// in the same direction as the edge.
    pub fn update_pointer_pos(&self, id: Uuid, edge: ResizeEdge) -> CommandResult {
        let container = try!(self.lookup(id));
        let Geometry { mut origin, size } = container.get_geometry()
            .expect("Container had no geometry");
        drop(container);
        if edge.contains(RESIZE_TOPLEFT) {
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_TOPRIGHT) {
            origin.x += size.w as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMLEFT) {
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMRIGHT) {
            origin.x += size.w as i32;
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        }
        Ok(())
    }

    /// 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);
        }
        self.update_pointer_pos(id, edge)
    }

    pub fn resize_tiled(&mut self, id: Uuid, mut edge: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // This is the vector of operations we will perform, we do all geometry sets atomically.
        let mut resizing_ops: Vec<(Uuid, (ResizeEdge, Geometry))> = Vec::with_capacity(4);
        edge &= !RESIZE_TOP;
        edge &= !RESIZE_BOTTOM;
        let dirs_moving_in = Direction::from_edge(edge);
        assert_eq!(dirs_moving_in.len(), 1);
        let next_container = self.container_in_dir(id, dirs_moving_in[0]).unwrap();
        trace!("container: {:?}", next_container);
        trace!("tree: {:#?}", self);
        {
            let container = try!(self.lookup(next_container.0));//try!(self.lookup(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");
            if is_making_too_small(geo, edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            resizing_ops.push((next_container.0, (edge, new_geo)));
        }
        let siblings: Vec<Uuid> = vec!(next_container.1);
        /*let siblings: Vec<Uuid> = dirs_moving_in.iter()
            .map(|dir| {
                self.container_in_dir(id, *dir)
                    .map(|uuids| {
                        let container = try!(self.lookup(id));
                        let geo = container.get_geometry()
                            .expect("Could not get geometry of the container");
                        let new_geo = calculate_resize(geo, edge, pointer, action.grab);
                        resizing_ops.push((uuids.0, (edge, new_geo)));
                        Ok(uuids.1)
                    })
            })
        // TODO There MUST be a better way to do something like this...
            .filter(|thing| thing.is_ok())
            .map(|thing| thing.unwrap())
            .collect();

         */
        // and now we mutate the siblings
        let reversed_dir: Vec<Direction> = dirs_moving_in.iter()
            .map(|dir| dir.reverse()).collect();
        let reversed_edge = Direction::to_edge(reversed_dir.as_slice());
        for sibling in siblings {
            // TODO Abstract, the only thing different from above
            // is the edge and the exact node we are doing the calc on
            let container = try!(self.lookup_mut(sibling));
            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, reversed_edge, pointer, action.grab);
            resizing_ops.push((sibling, (reversed_edge, new_geo)));
            container.set_geometry(reversed_edge, new_geo);
        }
        action.grab = pointer;
        for (id, (edge, geo)) in resizing_ops {
            let container = self.lookup_mut(id)
                .expect("Id no longer points to node!");
            container.set_geometry(edge, geo);
        }
        action.grab = pointer;
        let node_ix = self.tree.lookup_id(id).unwrap();
        let workspace_ix = self.tree.ancestor_of_type(node_ix, ContainerType::Workspace).unwrap();
        self.layout(workspace_ix);
        self.update_pointer_pos(id, edge)
    }
}

/// 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 = geo.size.w.saturating_add(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        }
        new_geo.origin.x += dx;
    }
    else if edge.contains(RESIZE_RIGHT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        }
    }

    if edge.contains(RESIZE_TOP) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        }
        new_geo.origin.y += dy;
    }
    else if edge.contains(RESIZE_BOTTOM) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_add(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
}

/// If the geometry is at the minimum size (in either the x or y plane)
/// and the pointer is trying to make it even smaller in that direction,
/// the it returns true (to indicate you should abandon all operations).
///
/// Otherwise returns false
fn is_making_too_small(geo: Geometry, edge: ResizeEdge, cur_point: Point,
                       prev_point: Point) -> bool {
    if geo.size.w != MIN_SIZE.w && geo.size.h != MIN_SIZE.h {
        return false
    }
    if edge.contains(RESIZE_RIGHT) && cur_point.x - prev_point.x < 0 {
        true
    } else if edge.contains(RESIZE_LEFT) && cur_point.x - prev_point.x > 0 {
        true
    } else if edge.contains(RESIZE_TOP) && cur_point.y - prev_point.y > 0 {
        true
    } else if edge.contains(RESIZE_BOTTOM) && cur_point.y - prev_point.y < 0 {
        true
    } else {
        false
    }
}
<commit_msg>Fixed smashing, mostly<commit_after>use rustwlc::{input, Point, ResizeEdge, Geometry,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM,
              RESIZE_TOPLEFT, RESIZE_TOPRIGHT, RESIZE_BOTTOMLEFT, RESIZE_BOTTOMRIGHT,
};

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType, MIN_SIZE};
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 {
    /// Updates pointer position for the node behind the id,
    /// in the same direction as the edge.
    pub fn update_pointer_pos(&self, id: Uuid, edge: ResizeEdge) -> CommandResult {
        let container = try!(self.lookup(id));
        let Geometry { mut origin, size } = container.get_geometry()
            .expect("Container had no geometry");
        drop(container);
        if edge.contains(RESIZE_TOPLEFT) {
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_TOPRIGHT) {
            origin.x += size.w as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMLEFT) {
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMRIGHT) {
            origin.x += size.w as i32;
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        }
        Ok(())
    }

    /// 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);
        }
        self.update_pointer_pos(id, edge)
    }

    pub fn resize_tiled(&mut self, id: Uuid, mut edge: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // This is the vector of operations we will perform, we do all geometry sets atomically.
        let mut resizing_ops: Vec<(Uuid, (ResizeEdge, Geometry))> = Vec::with_capacity(4);
        edge &= !RESIZE_TOP;
        edge &= !RESIZE_BOTTOM;
        let dirs_moving_in = Direction::from_edge(edge);
        assert_eq!(dirs_moving_in.len(), 1);
        let next_container = try!(self.container_in_dir(id, dirs_moving_in[0]));
        {
            let container = try!(self.lookup(next_container.0));//try!(self.lookup(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");
            if is_making_too_small(geo, edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            resizing_ops.push((next_container.0, (edge, new_geo)));
        }
        let siblings: Vec<Uuid> = vec!(next_container.1);
        /*let siblings: Vec<Uuid> = dirs_moving_in.iter()
            .map(|dir| {
                self.container_in_dir(id, *dir)
                    .map(|uuids| {
                        let container = try!(self.lookup(id));
                        let geo = container.get_geometry()
                            .expect("Could not get geometry of the container");
                        let new_geo = calculate_resize(geo, edge, pointer, action.grab);
                        resizing_ops.push((uuids.0, (edge, new_geo)));
                        Ok(uuids.1)
                    })
            })
        // TODO There MUST be a better way to do something like this...
            .filter(|thing| thing.is_ok())
            .map(|thing| thing.unwrap())
            .collect();

         */
        // and now we mutate the siblings
        let reversed_dir: Vec<Direction> = dirs_moving_in.iter()
            .map(|dir| dir.reverse()).collect();
        let reversed_edge = Direction::to_edge(reversed_dir.as_slice());
        for sibling in siblings {
            // TODO Abstract, the only thing different from above
            // is the edge and the exact node we are doing the calc on
            let container = try!(self.lookup_mut(sibling));
            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");
            if is_making_too_small(geo, reversed_edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, reversed_edge, pointer, action.grab);
            resizing_ops.push((sibling, (reversed_edge, new_geo)));
            container.set_geometry(reversed_edge, new_geo);
        }
        action.grab = pointer;
        for (id, (edge, geo)) in resizing_ops {
            let container = self.lookup_mut(id)
                .expect("Id no longer points to node!");
            container.set_geometry(edge, geo);
        }
        action.grab = pointer;
        let node_ix = self.tree.lookup_id(id).unwrap();
        let workspace_ix = self.tree.ancestor_of_type(node_ix, ContainerType::Workspace).unwrap();
        self.layout(workspace_ix);
        self.update_pointer_pos(id, edge)
    }
}

/// 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 = geo.size.w.saturating_add(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        }
        new_geo.origin.x += dx;
    }
    else if edge.contains(RESIZE_RIGHT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        }
    }

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

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

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

/// If the geometry is at the minimum size (in either the x or y plane)
/// and the pointer is trying to make it even smaller in that direction,
/// the it returns true (to indicate you should abandon all operations).
///
/// Otherwise returns false
fn is_making_too_small(geo: Geometry, edge: ResizeEdge, cur_point: Point,
                       prev_point: Point) -> bool {
    if geo.size.w > MIN_SIZE.w && geo.size.h > MIN_SIZE.h {
        return false
    }
    if edge.contains(RESIZE_RIGHT) && cur_point.x - prev_point.x < 0 {
        true
    } else if edge.contains(RESIZE_LEFT) && cur_point.x - prev_point.x > 0 {
        true
    } else if edge.contains(RESIZE_TOP) && cur_point.y - prev_point.y > 0 {
        true
    } else if edge.contains(RESIZE_BOTTOM) && cur_point.y - prev_point.y < 0 {
        true
    } else {
        false
    }
}
<|endoftext|>


<commit_before>#![crate_name = "toy_aa"]
#![crate_type = "dylib"]

use std::fmt::{mod, Show};
use std::mem::{replace, swap};

type Link<T> = Option<Box<T>>;

struct Node<K, V> {
    key: K,
    value: V,
    left: Link<Node<K, V>>,
    right: Link<Node<K, V>>,
    level: uint
}

pub struct Tree<K, V> {
    root: Link<Node<K, V>>,
}

impl<K: Ord, V> Tree<K, V> {
    pub fn new() -> Tree<K, V> {
        Tree { root: None }
    }

    fn is_bst(&self) -> bool {
        match self.root {
            None => true,
            Some(ref r) => r.is_bst()
        }
    }

    fn is_aa(&self) -> bool {
        match self.root {
            None => true,
            Some(ref r) => r.is_aa()
        }
    }

    pub fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        match self.root {
            None => None,
            Some(ref r) => r.find(key)
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        match self.root {
            None => {
                self.root = Some(box Node::new(key, value));
                None
            },
            Some(ref mut r) => r.insert(key, value)
        }
    }
}

impl<K: Ord, V> Node<K, V> {
    pub fn new(key: K, value: V) -> Node<K, V> {
        Node { key: key, value: value, left: None, right: None, level: 1 }
    }

    fn max(&self) -> &K {
        match self.right {
            None => &self.key,
            Some(ref n) => n.max(),
        }
    }

    fn min(&self) -> &K {
        match self.left {
            None => &self.key,
            Some(ref n) => n.min(),
        }
    }

    pub fn is_bst(&self) -> bool {
        self.left.as_ref().map_or(true, |n| n.is_bst() && *n.max() < self.key)
        && self.right.as_ref().map_or(true, |n| n.is_bst() && *n.min() > self.key)
    }

    pub fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        let ch = match key.cmp(&self.key) {
            Equal => return Some(&self.value),
            Less => & self.left,
            Greater => & self.right,
        };

        match *ch {
            None => None,
            Some(ref b) => b.find(key),
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        let replaced =
        {
            let link = match key.cmp(&self.key) {
                Equal => {
                    self.key = key;
                    return Some(replace(&mut self.value, value))
                },
                Less => &mut self.left,
                Greater => &mut self.right,
            };

            match *link {
                None => {
                    *link = Some(box Node::new(key, value));
                    None
                },
                Some(ref mut b) => {
                    b.insert(key, value)
                },
            }
        };

        self.skew();
        self.split();
        replaced

    }

    // To be an AA tree, it must be a binary search tree and, for all nodes n:
    //   - if n is missing a child, its level must be 1
    //   - the left child must have a level one less than n's level
    //   - the right child must have a level equal to or one less than n's level
    //   - the right child's right child must not have the same level as n's level
    fn is_aa(&self) -> bool {
        let lvl = self.level;

        self.is_bst()
            && !((self.left.is_none() || self.right.is_none()) && self.level != 1)
            && self.left.as_ref().map_or(true, |n| n.is_aa())
            && self.no_red_left_child()
            && self.right.as_ref().map_or(true,
                |n| n.is_aa() && (n.level == lvl || n.level + 1 == lvl)
                    && !(n.level == lvl && !n.no_red_right_child()))
    }

    fn no_red_left_child(&self) -> bool {
        match self.left {
            None => true,
            Some(ref n) => n.level + 1 == self.level,
        }
    }

    fn no_red_right_child(&self) -> bool {
        match self.right {
            None => true,
            Some(ref n) => n.level + 1 == self.level,
        }
    }

    // Remove red left child by rotating right
    /*
         a      b
        /        \
       b    =>    a
        \        /
         c      c

      provided that a.level == b.level
    */
    fn skew(&mut self) {
        if self.left.is_some() && self.left.get_ref().level == self.level {
            let mut save = self.left.take_unwrap();
            swap(&mut self.left, &mut save.right); // save.right now None
            swap(self, &mut *save);
            self.right = Some(save);
        }
    }

    // Remove red right child of red right child by rotating left and increasing
    // level of the parent
    /*
        a            b
         \          / \
          b    =>  a   c
         / \        \
        d   c        d

      provided that a.level == c.level
    */
    fn split(&mut self) {
        if self.right.as_ref().map_or(false,
          |x| x.right.is_some() && x.right.get_ref().level == self.level) {
            let mut save = self.right.take_unwrap();
            swap(&mut self.right, &mut save.left); // save.left now None
            save.level += 1;
            swap(self, &mut *save);
            self.left = Some(save);
        }
    }

    /*

       In the below, 'o' represents black, '*' represents red.

       First, note that deleting a red leaf requires no rebalancing at all.

       ---

       There's only 1 possible AA tree of size 2:

       o
        \
         *

       Deleting the root or the leaf requires no rebalancing.

       ---

       For size 3 trees, we only have:

         o
        / \
       o   o

        - deleting left leaf means we have to decrease the level of root. this suffices to rebalance
        - deleting right leaf means we have to decrease level of root but then make left leaf the
          new root (and former root the child of new root)
        - deleting the root means right child is new root, left child becomes new root's right child

       ---

       For size 4 trees, we have either

         o       o
        / \     / \
       o   o   o   o
        \           \
         *           *

       There are 4 classes of deletion:

        - delete red leaf (see above)
        - delete red node's parent: make red a child of its former grandparent
        - delete root: in the first case, red needs to become root, so increase its level and make it
          the new root. in the second case, right child of root needs to become new root.
        - delete other child: in the first case, red needs to become root and the old root needs to
          be right child of new root. in the second case, decrease level of old root, increase level
          of right child and make old root the child of the right child (which is the new root)

       ---

       For size 5 trees, we have one of

         o        o
        / \      / \
       o   o    o   *
        \   \      / \
         *   *    o   o

       ===

       One fundamental operation we need is "promote the max from the left subtree (or min from right subtree!)
       this is used when we delete a root, for example. this seems essentially whenever we delete a node that
       has two children.

     */
}

impl<K: Show, V: Show> Show for Node<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.key, self.value)
    }
}

fn print_node_depth<K: Show, V: Show>(node: &Link<Node<K,V>>, depth: uint) {
    let mut pre = "".to_string();
    if depth > 0 {
        for i in range(0, depth) {
            pre = pre + "   ";
        }
    }

    match *node {
        Some(ref n) => {
            println!("{}{}^{}", pre, n, n.level);
            print_node_depth(&n.left, depth + 1);
            print_node_depth(&n.right, depth + 1);
        },
        None => println!("{}-", pre),
    }
}

pub fn print_tree<K: Show + Ord, V: Show>(tree: &Tree<K, V>) {
    print_node_depth(&tree.root, 0);
    println!("Is AA: {}", tree.is_aa());
    println!("------------");
}

mod test {
    use super::Tree;
    use std::rand;
    use std::rand::distributions::{IndependentSample, Range};

    #[test]
    fn test_find() {
        let mut t = Tree::new();
        assert_eq!(t.find(&1u), None);
        t.insert(1u, 'j');
        assert_eq!(t.find(&1u), Some(&'j'));

    }

    // testing whether we can find all the things we inserted
    #[test]
    fn test_insert() {
        let mut t: Tree<uint, u8> = Tree::new();
        for (i, c) in range(0u, 10).zip(range(b'a', b'z')) {
            t.insert(i, c);
        }

        for (ref i, ref c) in range(0u, 10).zip(range(b'a', b'z')) {
            assert_eq!(t.find(i), Some(c));
        }

        assert_eq!(t.find(&10u), None);
    }

    fn insert_n_check_aa(n: uint, between: Range<uint>, rng: &mut rand::TaskRng) {
        let mut t = Tree::new();

        for _ in range(0u, n) {
            let a = between.ind_sample(rng);
            println!("{}", a);
            t.insert(a, ());
        }

        assert!(t.is_aa());
    }

    // testing whether, after inserting 20 random keys, is_aa() returns true
    #[test]
    fn test_insert_is_aa() {
        let mut rng = rand::task_rng();
        let between = Range::new(0u, 100_000);

        for _ in range(0u, 300) {
            insert_n_check_aa(20, between, &mut rng);
        }
    }

    // testing whether, after inserting 20 random keys, is_aa() returns true,
    // but this time some of the keys are repeated
    #[test]
    fn test_insert_dups_is_aa() {
        let mut rng = rand::task_rng();
        let between = Range::new(0u, 15);

        for _ in range(0u, 300) {
            insert_n_check_aa(20, between, &mut rng);
        }
    }
}
<commit_msg>Rework insert() to be more clear<commit_after>#![crate_name = "toy_aa"]
#![crate_type = "dylib"]

use std::fmt::{mod, Show};
use std::mem::{replace, swap};

type Link<T> = Option<Box<T>>;

struct Node<K, V> {
    key: K,
    value: V,
    left: Link<Node<K, V>>,
    right: Link<Node<K, V>>,
    level: uint
}

pub struct Tree<K, V> {
    root: Link<Node<K, V>>,
}

impl<K: Ord, V> Tree<K, V> {
    pub fn new() -> Tree<K, V> {
        Tree { root: None }
    }

    fn is_bst(&self) -> bool {
        match self.root {
            None => true,
            Some(ref r) => r.is_bst()
        }
    }

    fn is_aa(&self) -> bool {
        match self.root {
            None => true,
            Some(ref r) => r.is_aa()
        }
    }

    pub fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        match self.root {
            None => None,
            Some(ref r) => r.find(key)
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        match self.root {
            None => {
                self.root = Some(box Node::new(key, value));
                None
            },
            Some(ref mut r) => r.insert(key, value)
        }
    }
}

impl<K: Ord, V> Node<K, V> {
    pub fn new(key: K, value: V) -> Node<K, V> {
        Node { key: key, value: value, left: None, right: None, level: 1 }
    }

    fn max(&self) -> &K {
        match self.right {
            None => &self.key,
            Some(ref n) => n.max(),
        }
    }

    fn min(&self) -> &K {
        match self.left {
            None => &self.key,
            Some(ref n) => n.min(),
        }
    }

    pub fn is_bst(&self) -> bool {
        self.left.as_ref().map_or(true, |n| n.is_bst() && *n.max() < self.key)
        && self.right.as_ref().map_or(true, |n| n.is_bst() && *n.min() > self.key)
    }

    pub fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        let ch = match key.cmp(&self.key) {
            Equal => return Some(&self.value),
            Less => & self.left,
            Greater => & self.right,
        };

        match *ch {
            None => None,
            Some(ref b) => b.find(key),
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        let replaced = match key.cmp(&self.key) {
            Equal => {
                self.key = key;
                return Some(replace(&mut self.value, value))
            },
            Less =>
                match self.left {
                    None => {
                        self.left = Some(box Node::new(key, value));
                        None
                    },
                    Some(ref mut b) => b.insert(key, value),
                },
            Greater =>
                match self.right {
                    None => {
                        self.right = Some(box Node::new(key, value));
                        None
                    },
                    Some(ref mut b) => b.insert(key, value),
                },
        };

        self.skew();
        self.split();
        replaced
    }

    // To be an AA tree, it must be a binary search tree and, for all nodes n:
    //   - if n is missing a child, its level must be 1
    //   - the left child must have a level one less than n's level
    //   - the right child must have a level equal to or one less than n's level
    //   - the right child's right child must not have the same level as n's level
    fn is_aa(&self) -> bool {
        let lvl = self.level;

        self.is_bst()
            && !((self.left.is_none() || self.right.is_none()) && self.level != 1)
            && self.left.as_ref().map_or(true, |n| n.is_aa())
            && self.no_red_left_child()
            && self.right.as_ref().map_or(true,
                |n| n.is_aa() && (n.level == lvl || n.level + 1 == lvl)
                    && !(n.level == lvl && !n.no_red_right_child()))
    }

    fn no_red_left_child(&self) -> bool {
        match self.left {
            None => true,
            Some(ref n) => n.level + 1 == self.level,
        }
    }

    fn no_red_right_child(&self) -> bool {
        match self.right {
            None => true,
            Some(ref n) => n.level + 1 == self.level,
        }
    }

    // Remove red left child by rotating right
    /*
         a      b
        /        \
       b    =>    a
        \        /
         c      c

      provided that a.level == b.level
    */
    fn skew(&mut self) {
        if self.left.is_some() && self.left.get_ref().level == self.level {
            let mut save = self.left.take_unwrap();
            swap(&mut self.left, &mut save.right); // save.right now None
            swap(self, &mut *save);
            self.right = Some(save);
        }
    }

    // Remove red right child of red right child by rotating left and increasing
    // level of the parent
    /*
        a            b
         \          / \
          b    =>  a   c
         / \        \
        d   c        d

      provided that a.level == c.level
    */
    fn split(&mut self) {
        if self.right.as_ref().map_or(false,
          |x| x.right.is_some() && x.right.get_ref().level == self.level) {
            let mut save = self.right.take_unwrap();
            swap(&mut self.right, &mut save.left); // save.left now None
            save.level += 1;
            swap(self, &mut *save);
            self.left = Some(save);
        }
    }

    /*

       In the below, 'o' represents black, '*' represents red.

       First, note that deleting a red leaf requires no rebalancing at all.

       ---

       There's only 1 possible AA tree of size 2:

       o
        \
         *

       Deleting the root or the leaf requires no rebalancing.

       ---

       For size 3 trees, we only have:

         o
        / \
       o   o

        - deleting left leaf means we have to decrease the level of root. this suffices to rebalance
        - deleting right leaf means we have to decrease level of root but then make left leaf the
          new root (and former root the child of new root)
        - deleting the root means right child is new root, left child becomes new root's right child

       ---

       For size 4 trees, we have either

         o       o
        / \     / \
       o   o   o   o
        \           \
         *           *

       There are 4 classes of deletion:

        - delete red leaf (see above)
        - delete red node's parent: make red a child of its former grandparent
        - delete root: in the first case, red needs to become root, so increase its level and make it
          the new root. in the second case, right child of root needs to become new root.
        - delete other child: in the first case, red needs to become root and the old root needs to
          be right child of new root. in the second case, decrease level of old root, increase level
          of right child and make old root the child of the right child (which is the new root)

       ---

       For size 5 trees, we have one of

         o        o
        / \      / \
       o   o    o   *
        \   \      / \
         *   *    o   o

       ===

       One fundamental operation we need is "promote the max from the left subtree (or min from right subtree!)
       this is used when we delete a root, for example. this seems essentially whenever we delete a node that
       has two children.

     */
}

impl<K: Show, V: Show> Show for Node<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.key, self.value)
    }
}

fn print_node_depth<K: Show, V: Show>(node: &Link<Node<K,V>>, depth: uint) {
    let mut pre = "".to_string();
    if depth > 0 {
        for i in range(0, depth) {
            pre = pre + "   ";
        }
    }

    match *node {
        Some(ref n) => {
            println!("{}{}^{}", pre, n, n.level);
            print_node_depth(&n.left, depth + 1);
            print_node_depth(&n.right, depth + 1);
        },
        None => println!("{}-", pre),
    }
}

pub fn print_tree<K: Show + Ord, V: Show>(tree: &Tree<K, V>) {
    print_node_depth(&tree.root, 0);
    println!("Is AA: {}", tree.is_aa());
    println!("------------");
}

mod test {
    use super::Tree;
    use std::rand;
    use std::rand::distributions::{IndependentSample, Range};

    #[test]
    fn test_find() {
        let mut t = Tree::new();
        assert_eq!(t.find(&1u), None);
        t.insert(1u, 'j');
        assert_eq!(t.find(&1u), Some(&'j'));

    }

    // testing whether we can find all the things we inserted
    #[test]
    fn test_insert() {
        let mut t: Tree<uint, u8> = Tree::new();
        for (i, c) in range(0u, 10).zip(range(b'a', b'z')) {
            t.insert(i, c);
        }

        for (ref i, ref c) in range(0u, 10).zip(range(b'a', b'z')) {
            assert_eq!(t.find(i), Some(c));
        }

        assert_eq!(t.find(&10u), None);
    }

    fn insert_n_check_aa(n: uint, between: Range<uint>, rng: &mut rand::TaskRng) {
        let mut t = Tree::new();

        for _ in range(0u, n) {
            let a = between.ind_sample(rng);
            println!("{}", a);
            t.insert(a, ());
        }

        assert!(t.is_aa());
    }

    // testing whether, after inserting 20 random keys, is_aa() returns true
    #[test]
    fn test_insert_is_aa() {
        let mut rng = rand::task_rng();
        let between = Range::new(0u, 100_000);

        for _ in range(0u, 300) {
            insert_n_check_aa(20, between, &mut rng);
        }
    }

    // testing whether, after inserting 20 random keys, is_aa() returns true,
    // but this time some of the keys are repeated
    #[test]
    fn test_insert_dups_is_aa() {
        let mut rng = rand::task_rng();
        let between = Range::new(0u, 15);

        for _ in range(0u, 300) {
            insert_n_check_aa(20, between, &mut rng);
        }
    }
}
<|endoftext|>


<commit_before>/// Verify we're built with run-time integer overflow detection.

// 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 https://mozilla.org/MPL/2.0/.

#[test]
#[should_panic(expected = "attempt to add with overflow")]
fn overflow_protection() {
    let edge = u32::max_value();
    assert_eq!(0u32, edge + 1);

    let edge = u64::max_value();
    assert_eq!(064, edge + 1);
}
<commit_msg>overflow.rs: Fix typo.<commit_after>/// Verify we're built with run-time integer overflow detection.

// 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 https://mozilla.org/MPL/2.0/.

#[test]
#[should_panic(expected = "attempt to add with overflow")]
fn overflow_protection() {
    let edge = u32::max_value();
    assert_eq!(0u32, edge + 1);

    let edge = u64::max_value();
    assert_eq!(0u64, edge + 1);
}
<|endoftext|>


<commit_before>use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Visitor};
use serde::de::impls::IgnoredAny;
use super::super::DateTime;
use json::value::{Deserializer as JsonDeserializer, Value};
use super::super::{List, Tweet, User};

/// Represents notifications about non-Tweet events are also sent over a stream.
///
/// # Reference
///
/// 1. [Streaming message types — Twitter Developers]
///    (https://dev.twitter.com/streaming/overview/messages-types#Events_event)
#[derive(Clone, Debug, PartialEq)]
pub struct Event {
    pub created_at: DateTime,
    /// An object which indicates the name of the event and contains an optional object which
    /// represents the target of the event.
    pub event: EventKind,
    pub target: User,
    pub source: User,
}

macro_rules! impl_event {
    (
        $(#[$attr:meta])*
        pub enum $T:ident {
            $(
                $(#[$c_attr:meta])*
                :$Container:ident($c_tag:expr, $Content:ty)
            ),*;
            $(
                $(#[$l_attr:meta])*
                :$Label:ident($l_tag:expr)
            ),*;
            $(#[$cu_attr:meta])*
            :$Custom:ident(_, _),
        }
    ) => {
        $(#[$attr])*
        pub enum $T {
            $(
                $(#[$c_attr])*
                $Container($Content),
            )*
            $(
                $(#[$l_attr])*
                $Label,
            )*
            $(#[$cu_attr])*
            $Custom(String, Option<Value>),
        }

        impl Deserialize for Event {
            fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
                struct EventVisitor;

                impl Visitor for EventVisitor {
                    type Value = Event;

                    fn visit_map<V: MapVisitor>(&mut self, mut v: V) -> Result<Event, V::Error> {
                        #[derive(Default)]
                        struct EventBuffer {
                            created_at: Option<DateTime>,
                            event: Option<EventKind>,
                            target: Option<User>,
                            source: Option<User>,
                        }

                        let mut event = EventBuffer::default();
                        let mut event_kind: Option<String> = None;
                        let mut target_obj: Option<Value> = None;

                        macro_rules! err_map {
                            () => (|e| V::Error::custom(e.to_string()));
                        }

                        while let Some(k) = v.visit_key::<String>()? {
                            match k.as_str() {
                                "created_at" => {
                                    let val = v.visit_value::<String>()?;
                                    event.created_at = Some(super::super::parse_datetime(&val).map_err(err_map!())?);
                                },
                                "event" => {
                                    let e = v.visit_value::<String>()?;
                                    event.event = if let Some(t) = target_obj.take() {
                                        match e.as_str() {
                                            $($c_tag => {
                                                let mut d = JsonDeserializer::new(t);
                                                $T::$Container(<$Content>::deserialize(&mut d).map_err(err_map!())?)
                                            },)*
                                            $($l_tag => $T::$Label,)*
                                            _ => $T::$Custom(e, Some(t)),
                                        }.into()
                                    } else {
                                        match e.as_str() {
                                            $($l_tag => Some($T::$Label),)*
                                            $($c_tag)|* => { event_kind = Some(e); None },
                                            _ => Some($T::Custom(e, None)),
                                        }
                                    };
                                },
                                "target" => event.target = Some(v.visit_value()?),
                                "source" => event.source = Some(v.visit_value()?),
                                "target_object" => if let Some(e) = event_kind.take() {
                                    event.event = match e.as_str() {
                                        $($c_tag => $T::$Container(v.visit_value()?),)*
                                        $($l_tag => { v.visit_value::<IgnoredAny>()?; $T::$Label },)*
                                        _ => $T::$Custom(e, v.visit_value()?),
                                    }.into();
                                } else if event.event.is_none() {
                                    target_obj = Some(v.visit_value()?);
                                } else {
                                    v.visit_value::<IgnoredAny>()?;
                                },
                                _ => { v.visit_value()?; },
                            }

                            if let EventBuffer {
                                    created_at: Some(ca), event: Some(e), target: Some(t), source: Some(s),
                                } = event
                            {
                                while let Some(_) = v.visit::<IgnoredAny, IgnoredAny>()? {}
                                v.end()?;
                                return Ok(Event { created_at: ca, event: e, target: t, source: s });
                            }
                        }

                        v.end()?;

                        v.missing_field(if event.created_at.is_none() {
                            "created_at"
                        } else if event.target.is_none() {
                            "target"
                        } else if event.source.is_none() {
                            "source"
                        } else if event.event.is_none() {
                            if target_obj.is_some() {
                                "event"
                            } else {
                                "target_object"
                            }
                        } else {
                            unreachable!();
                        })
                    }
                }

                d.deserialize_map(EventVisitor)
            }
        }
    };
}

impl_event! {
    /// An object which indicates the name of an event.
    /// It may contain an object called "target object" which represents the target of the event.
    ///
    /// The meaning of `target` and `source` field of an `Event` will be different based on the name of the event,
    /// as described below.
    ///
    /// | Description                         | Event Name             | `source`           | `target`       |
    /// | ----------------------------------- | ---------------------- | ------------------ | -------------- |
    /// | User deauthorizes stream            | `AccessRevoked`        | Deauthorizing user | App owner      |
    /// | User blocks someone                 | `Block`                | Current user       | Blocked user   |
    /// | User removes a block                | `Unblock`              | Current user       | Unblocked user |
    /// | User favorites a Tweet              | `Favorite`             | Current user       | Tweet author   |
    /// | User’s Tweet is favorited           | `Favorite`             | Favoriting user    | Current user   |
    /// | User unfavorites a Tweet            | `Unfavorite`           | Current user       | Tweet author   |
    /// | User’s Tweet is unfavorited         | `Unfavorite`           | Unfavoriting user  | Current user   |
    /// | User follows someone                | `Follow`               | Current user       | Followed user  |
    /// | User is followed                    | `Follow`               | Following user     | Current user   |
    /// | User unfollows someone              | `Unfollow`             | Current user       | Followed user  |
    /// | User creates a list                 | `ListCreated`          | Current user       | Current user   |
    /// | User deletes a list                 | `ListDestroyed`        | Current user       | Current user   |
    /// | User edits a list                   | `ListUpdated`          | Current user       | Current user   |
    /// | User adds someone to a list         | `ListMemberAdded`      | Current user       | Added user     |
    /// | User is added to a list             | `ListMemberAdded`      | Adding user        | Current user   |
    /// | User removes someone from a list    | `ListMemberRemoved`    | Current user       | Removed user   |
    /// | User is removed from a list         | `ListMemberRemoved`    | Removing user      | Current user   |
    /// | User subscribes to a list           | `ListUserSubscribed`   | Current user       | List owner     |
    /// | User’s list is subscribed to        | `ListUserSubscribed`   | Subscribing user   | Current user   |
    /// | User unsubscribes from a list       | `ListUserUnsubscribed` | Current user       | List owner     |
    /// | User’s list is unsubscribed from    | `ListUserUnsubscribed` | Unsubscribing user | Current user   |
    /// | User’s Tweet is quoted              | `QuotedTweet`          | quoting User       | Current User   |
    /// | User updates their profile          | `UserUpdate`           | Current user       | Current user   |
    /// | User updates their protected status | `UserUpdate`           | Current user       | Current user   |
    #[derive(Clone, Debug, PartialEq)]
    pub enum EventKind {
        :Favorite("favorite", Tweet),
        :Unfavorite("unfavorite", Tweet),
        :ListCreated("list_created", List),
        :ListDestroyed("list_destroyed", List),
        :ListUpdated("list_updated", List),
        :ListMemberAdded("list_member_added", List),
        :ListMemberRemoved("list_member_removed", List),
        :ListUserSubscribed("list_user_subscribed", List),
        :ListUserUnsubscribed("list_user_unsubscribed", List),
        :QuotedTweet("quoted_tweet", Tweet);
        :AccessRevoked("access_revoked"),
        :Block("block"),
        :Unblock("unblock"),
        :Follow("follow"),
        :Unfollow("unfollow"),
        :UserUpdate("user_update");
        /// An event this library does not know. The first value is raw event name
        /// and the second is the target object.
        :Custom(_, _),
    }
}
<commit_msg>Future-proof against inference changes<commit_after>use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Visitor};
use serde::de::impls::IgnoredAny;
use super::super::DateTime;
use json::value::{Deserializer as JsonDeserializer, Value};
use super::super::{List, Tweet, User};

/// Represents notifications about non-Tweet events are also sent over a stream.
///
/// # Reference
///
/// 1. [Streaming message types — Twitter Developers]
///    (https://dev.twitter.com/streaming/overview/messages-types#Events_event)
#[derive(Clone, Debug, PartialEq)]
pub struct Event {
    pub created_at: DateTime,
    /// An object which indicates the name of the event and contains an optional object which
    /// represents the target of the event.
    pub event: EventKind,
    pub target: User,
    pub source: User,
}

macro_rules! impl_event {
    (
        $(#[$attr:meta])*
        pub enum $T:ident {
            $(
                $(#[$c_attr:meta])*
                :$Container:ident($c_tag:expr, $Content:ty)
            ),*;
            $(
                $(#[$l_attr:meta])*
                :$Label:ident($l_tag:expr)
            ),*;
            $(#[$cu_attr:meta])*
            :$Custom:ident(_, _),
        }
    ) => {
        $(#[$attr])*
        pub enum $T {
            $(
                $(#[$c_attr])*
                $Container($Content),
            )*
            $(
                $(#[$l_attr])*
                $Label,
            )*
            $(#[$cu_attr])*
            $Custom(String, Option<Value>),
        }

        impl Deserialize for Event {
            fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
                struct EventVisitor;

                impl Visitor for EventVisitor {
                    type Value = Event;

                    fn visit_map<V: MapVisitor>(&mut self, mut v: V) -> Result<Event, V::Error> {
                        #[derive(Default)]
                        struct EventBuffer {
                            created_at: Option<DateTime>,
                            event: Option<EventKind>,
                            target: Option<User>,
                            source: Option<User>,
                        }

                        let mut event = EventBuffer::default();
                        let mut event_kind: Option<String> = None;
                        let mut target_obj: Option<Value> = None;

                        macro_rules! err_map {
                            () => (|e| V::Error::custom(e.to_string()));
                        }

                        while let Some(k) = v.visit_key::<String>()? {
                            match k.as_str() {
                                "created_at" => {
                                    let val = v.visit_value::<String>()?;
                                    event.created_at = Some(super::super::parse_datetime(&val).map_err(err_map!())?);
                                },
                                "event" => {
                                    let e = v.visit_value::<String>()?;
                                    event.event = if let Some(t) = target_obj.take() {
                                        match e.as_str() {
                                            $($c_tag => {
                                                let mut d = JsonDeserializer::new(t);
                                                $T::$Container(<$Content>::deserialize(&mut d).map_err(err_map!())?)
                                            },)*
                                            $($l_tag => $T::$Label,)*
                                            _ => $T::$Custom(e, Some(t)),
                                        }.into()
                                    } else {
                                        match e.as_str() {
                                            $($l_tag => Some($T::$Label),)*
                                            $($c_tag)|* => { event_kind = Some(e); None },
                                            _ => Some($T::Custom(e, None)),
                                        }
                                    };
                                },
                                "target" => event.target = Some(v.visit_value()?),
                                "source" => event.source = Some(v.visit_value()?),
                                "target_object" => if let Some(e) = event_kind.take() {
                                    event.event = match e.as_str() {
                                        $($c_tag => $T::$Container(v.visit_value()?),)*
                                        $($l_tag => { v.visit_value::<IgnoredAny>()?; $T::$Label },)*
                                        _ => $T::$Custom(e, v.visit_value()?),
                                    }.into();
                                } else if event.event.is_none() {
                                    target_obj = Some(v.visit_value()?);
                                } else {
                                    v.visit_value::<IgnoredAny>()?;
                                },
                                _ => { v.visit_value::<()>()?; },
                            }

                            if let EventBuffer {
                                    created_at: Some(ca), event: Some(e), target: Some(t), source: Some(s),
                                } = event
                            {
                                while let Some(_) = v.visit::<IgnoredAny, IgnoredAny>()? {}
                                v.end()?;
                                return Ok(Event { created_at: ca, event: e, target: t, source: s });
                            }
                        }

                        v.end()?;

                        v.missing_field(if event.created_at.is_none() {
                            "created_at"
                        } else if event.target.is_none() {
                            "target"
                        } else if event.source.is_none() {
                            "source"
                        } else if event.event.is_none() {
                            if target_obj.is_some() {
                                "event"
                            } else {
                                "target_object"
                            }
                        } else {
                            unreachable!();
                        })
                    }
                }

                d.deserialize_map(EventVisitor)
            }
        }
    };
}

impl_event! {
    /// An object which indicates the name of an event.
    /// It may contain an object called "target object" which represents the target of the event.
    ///
    /// The meaning of `target` and `source` field of an `Event` will be different based on the name of the event,
    /// as described below.
    ///
    /// | Description                         | Event Name             | `source`           | `target`       |
    /// | ----------------------------------- | ---------------------- | ------------------ | -------------- |
    /// | User deauthorizes stream            | `AccessRevoked`        | Deauthorizing user | App owner      |
    /// | User blocks someone                 | `Block`                | Current user       | Blocked user   |
    /// | User removes a block                | `Unblock`              | Current user       | Unblocked user |
    /// | User favorites a Tweet              | `Favorite`             | Current user       | Tweet author   |
    /// | User’s Tweet is favorited           | `Favorite`             | Favoriting user    | Current user   |
    /// | User unfavorites a Tweet            | `Unfavorite`           | Current user       | Tweet author   |
    /// | User’s Tweet is unfavorited         | `Unfavorite`           | Unfavoriting user  | Current user   |
    /// | User follows someone                | `Follow`               | Current user       | Followed user  |
    /// | User is followed                    | `Follow`               | Following user     | Current user   |
    /// | User unfollows someone              | `Unfollow`             | Current user       | Followed user  |
    /// | User creates a list                 | `ListCreated`          | Current user       | Current user   |
    /// | User deletes a list                 | `ListDestroyed`        | Current user       | Current user   |
    /// | User edits a list                   | `ListUpdated`          | Current user       | Current user   |
    /// | User adds someone to a list         | `ListMemberAdded`      | Current user       | Added user     |
    /// | User is added to a list             | `ListMemberAdded`      | Adding user        | Current user   |
    /// | User removes someone from a list    | `ListMemberRemoved`    | Current user       | Removed user   |
    /// | User is removed from a list         | `ListMemberRemoved`    | Removing user      | Current user   |
    /// | User subscribes to a list           | `ListUserSubscribed`   | Current user       | List owner     |
    /// | User’s list is subscribed to        | `ListUserSubscribed`   | Subscribing user   | Current user   |
    /// | User unsubscribes from a list       | `ListUserUnsubscribed` | Current user       | List owner     |
    /// | User’s list is unsubscribed from    | `ListUserUnsubscribed` | Unsubscribing user | Current user   |
    /// | User’s Tweet is quoted              | `QuotedTweet`          | quoting User       | Current User   |
    /// | User updates their profile          | `UserUpdate`           | Current user       | Current user   |
    /// | User updates their protected status | `UserUpdate`           | Current user       | Current user   |
    #[derive(Clone, Debug, PartialEq)]
    pub enum EventKind {
        :Favorite("favorite", Tweet),
        :Unfavorite("unfavorite", Tweet),
        :ListCreated("list_created", List),
        :ListDestroyed("list_destroyed", List),
        :ListUpdated("list_updated", List),
        :ListMemberAdded("list_member_added", List),
        :ListMemberRemoved("list_member_removed", List),
        :ListUserSubscribed("list_user_subscribed", List),
        :ListUserUnsubscribed("list_user_unsubscribed", List),
        :QuotedTweet("quoted_tweet", Tweet);
        :AccessRevoked("access_revoked"),
        :Block("block"),
        :Unblock("unblock"),
        :Follow("follow"),
        :Unfollow("unfollow"),
        :UserUpdate("user_update");
        /// An event this library does not know. The first value is raw event name
        /// and the second is the target object.
        :Custom(_, _),
    }
}
<|endoftext|>