<commit_before>//! Functions to read and write debug registers.
//!
//! * The dr{0,1,2,3} registers are used to set break points.
//! * The dr6 register contains debug conditions that were sampled at the time
//!   the last debug exception.
//! * The dr7 register enables or disables breakpoints and sets breakpoint
//!   conditions.
//!
//! See Intel Vol. 3a Chapter 17, "Debug, Branch, Profile, TSC ... Features"

use bit_field::BitField;
use bitflags::bitflags;

/// An array list of all available breakpoint registers.
pub const BREAKPOINT_REGS: [Breakpoint; 4] = [
    Breakpoint::Dr0,
    Breakpoint::Dr1,
    Breakpoint::Dr2,
    Breakpoint::Dr3,
];

/// Write dr{0-3} register based on provided `reg` enum.
pub unsafe fn dr_write(reg: Breakpoint, val: usize) {
    match reg {
        Breakpoint::Dr0 => dr0_write(val),
        Breakpoint::Dr1 => dr1_write(val),
        Breakpoint::Dr2 => dr2_write(val),
        Breakpoint::Dr3 => dr3_write(val),
    }
}

/// Read dr{0-3} register based on provided `reg` enum.
pub unsafe fn dr(reg: Breakpoint) -> usize {
    match reg {
        Breakpoint::Dr0 => dr0(),
        Breakpoint::Dr1 => dr1(),
        Breakpoint::Dr2 => dr2(),
        Breakpoint::Dr3 => dr3(),
    }
}

/// Read dr0.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr0() -> usize {
    let ret: usize;
    asm!("mov %dr0, {}", out(reg) ret, options(att_syntax));
    ret
}

/// Write dr0.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr0_write(val: usize) {
    asm!("mov {}, %dr0", in(reg) val, options(att_syntax));
}

/// Read dr1.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr1() -> usize {
    let ret: usize;
    asm!("mov %dr1, {}", out(reg) ret, options(att_syntax));
    ret
}

/// Write dr1.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr1_write(val: usize) {
    asm!("mov {}, %dr1", in(reg) val, options(att_syntax));
}

/// Read dr2.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr2() -> usize {
    let ret: usize;
    asm!("mov %dr2, {}", out(reg) ret, options(att_syntax));
    ret
}

/// Write dr2.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr2_write(val: usize) {
    asm!("mov {}, %dr2", in(reg) val, options(att_syntax));
}

/// Read dr3.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr3() -> usize {
    let ret: usize;
    asm!("mov %dr3, {}", out(reg) ret, options(att_syntax));
    ret
}

/// Write dr3.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr3_write(val: usize) {
    asm!("mov {}, %dr3", in(reg) val, options(att_syntax));
}

bitflags! {
    /// Debug register 6 (dr6) flags.
    pub struct Dr6: usize {
        /// B0 breakpoint condition detected
        ///
        /// # Notes
        ///
        /// The flag is set if the condition described for the breakpoint by
        /// the LENn, and R/Wn flags in debug control register DR7 is true. They
        /// may or may not be set if the breakpoint is not enabled by the Ln or
        /// the Gn flags in register DR7. Therefore on a #DB, a debug handler
        /// should check only those B0-B3 bits which correspond to an enabled
        /// breakpoint.
        const B0 = 0b0001;

        /// B1 breakpoint condition detected
        ///
        /// # Notes
        ///
        /// The flag is set if the condition described for the breakpoint by
        /// the LENn, and R/Wn flags in debug control register DR7 is true. They
        /// may or may not be set if the breakpoint is not enabled by the Ln or
        /// the Gn flags in register DR7. Therefore on a #DB, a debug handler
        /// should check only those B0-B3 bits which correspond to an enabled
        /// breakpoint.
        const B1 = 0b0010;

        /// B2 breakpoint condition detected
        ///
        /// # Notes
        ///
        /// The flag is set if the condition described for the breakpoint by
        /// the LENn, and R/Wn flags in debug control register DR7 is true. They
        /// may or may not be set if the breakpoint is not enabled by the Ln or
        /// the Gn flags in register DR7. Therefore on a #DB, a debug handler
        /// should check only those B0-B3 bits which correspond to an enabled
        /// breakpoint.
        const B2 = 0b0100;

        /// B3 breakpoint condition detected
        ///
        /// # Notes
        ///
        /// The flag is set if the condition described for the breakpoint by
        /// the LENn, and R/Wn flags in debug control register DR7 is true. They
        /// may or may not be set if the breakpoint is not enabled by the Ln or
        /// the Gn flags in register DR7. Therefore on a #DB, a debug handler
        /// should check only those B0-B3 bits which correspond to an enabled
        /// breakpoint.
        const B3 = 0b1000;

        /// BD debug register access detected
        ///
        /// Indicates that the next instruction in the instruction stream
        /// accesses one of the debug registers.
        ///
        /// This flag is enabled when the GD (general detect) flag in debug
        /// control register DR7 is set.
        const BD = 1 << 13;

        /// BS single step
        ///
        /// Indicates (when set) that the debug exception was triggered by the
        /// single- step execution mode (enabled with the TF flag in the EFLAGS
        /// register).
        const BS = 1 << 14;

        /// BT task switch
        ///
        /// Indicates (when set) that the debug exception resulted from a task
        /// switch where the T flag (debug trap flag) in the TSS of the target
        /// task was set.
        const BT = 1 << 15;

        /// Enables (when set) advanced debugging of RTM transactional regions.
        const RTM = 1 << 16;
    }
}

/// Read dr6.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr6() -> Dr6 {
    let ret: usize;
    asm!("mov %dr6, {}", out(reg) ret, options(att_syntax));
    Dr6::from_bits_truncate(ret)
}

/// Write dr6.
///
/// # Notes
///
/// Certain debug exceptions may clear bits 0-3. The remaining contents of the
/// DR6 register are never cleared by the processor. To avoid confusion in
/// identifying debug exceptions, debug handlers should clear the register
/// (except bit 16, which they should set) before returning to the interrupted
/// task).
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr6_write(val: Dr6) {
    asm!("mov {}, %dr6", in(reg) val.bits, options(att_syntax));
}

/// Specifies available hardware breakpoints.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Breakpoint {
    Dr0 = 0,
    Dr1 = 1,
    Dr2 = 2,
    Dr3 = 3,
}

/// Specifies the  breakpoint condition for a corresponding breakpoint.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BreakCondition {
    /// 00 — Break on instruction execution only.
    Instructions = 0b00,
    /// 01 — Break on data writes only.
    DataWrites = 0b01,
    /// 10 — Break on I/O reads or writes.
    ///
    /// # Notes
    /// For this type to be available, the DE (debug extensions) flag in control
    /// register CR4 must be set.
    IoReadsWrites = 0b10,
    /// 11 — Break on data reads or writes but not instruction fetches.
    DataReadsWrites = 0b11,
}

/// Specify the size of the memory location at the address specified in the
/// corresponding breakpoint address register (DR0 through DR3).
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BreakSize {
    /// 00 — 1-byte length.
    Bytes1 = 0b00,
    /// 01 — 2-byte length.
    Bytes2 = 0b01,
    /// 10 — 8 byte length (or undefined, on older processors).
    Bytes8 = 0b10,
    /// 11 — 4-byte length.
    Bytes4 = 0b11,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Dr7(pub usize);

impl Default for Dr7 {
    fn default() -> Self {
        Self(1 << 10)
    }
}

impl Dr7 {
    fn set_bp(&mut self, bp: Breakpoint, global: bool, val: bool) {
        let bp = bp as usize;
        assert!(bp < 4);
        let idx = if global { bp + 1 } else { bp };
        self.0.set_bit(idx, val);
    }

    fn set_bc(&mut self, bp: Breakpoint, bc: BreakCondition) {
        let idx = 16 + (bp as usize * 4);
        assert!(idx == 16 || idx == 20 || idx == 24 || idx == 28);
        self.0.set_bits(idx..=idx + 1, bc as usize);
    }

    fn set_bs(&mut self, bp: Breakpoint, bs: BreakSize) {
        let idx = 18 + (bp as usize * 4);
        assert!(idx == 18 || idx == 22 || idx == 26 || idx == 30);
        self.0.set_bits(idx..=idx + 1, bs as usize);
    }

    /// Enables the breakpoint condition for the associated breakpoint.
    ///
    /// - `bp`: The breakpoint to enable.
    /// - `global`: If true, the breakpoint is global (e.g., never reset on task
    ///   switches). If false, the CPU resets the flag (disables bp) on task
    ///   switch.
    pub fn enable_bp(&mut self, bp: Breakpoint, bc: BreakCondition, bs: BreakSize, global: bool) {
        assert!(
            !(bc == BreakCondition::Instructions && bs != BreakSize::Bytes1),
            "If bc is 00 (instruction execution), then the bs field should be 00"
        );
        self.set_bp(bp, global, true);
        self.set_bc(bp, bc);
        self.set_bs(bp, bs);
    }

    /// Disables the breakpoint condition for the associated breakpoint.
    ///
    /// - `bp`: The breakpoint to disable.
    /// - `global`: If true, the breakpoint is global (e.g., never reset on task
    ///   switches). If false, the CPU resets the flag (disables bp) on task
    ///   switch.
    pub fn disable_bp(&mut self, bp: Breakpoint, global: bool) {
        self.set_bp(bp, global, false);
    }

    /// Local exact breakpoint enable.
    ///
    /// This flag causes the processor to detect the exact instruction that
    /// caused a data breakpoint condition. This feature is not supported in the
    /// P6 family processors, later IA-32 processors, and Intel 64 processors.
    ///
    /// For backward and forward compatibility with other Intel processors,
    /// Intel recommends that the LE flag be set to 1 if exact breakpoints are
    /// required.
    pub fn enable_exact_local_bp(&mut self) {
        self.0.set_bit(8, true);
    }

    /// Global exact breakpoint enable.
    ///
    /// This flag causes the processor to detect the exact instruction that
    /// caused a data breakpoint condition. This feature is not supported in the
    /// P6 family processors, later IA-32 processors, and Intel 64 processors.
    ///
    /// For backward and forward compatibility with other Intel processors,
    /// Intel recommends that the GE flag be set to 1 if exact breakpoints are
    /// required.
    pub fn enable_exact_global_bp(&mut self) {
        self.0.set_bit(9, true);
    }

    /// Enables advanced debugging of RTM transactional regions.
    ///
    /// # Note
    /// This advanced debugging is enabled only if IA32_DEBUGCTL.RTM is also
    /// set.
    pub fn enable_rtm(&mut self) {
        self.0.set_bit(11, true);
    }

    /// Enables debug-register protection, which causes a debug exception to be
    /// generated prior to any MOV instruction that accesses a debug register.
    pub fn enable_general_detect(&mut self) {
        self.0.set_bit(13, true);
    }
}

/// Read dr7.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr7() -> Dr7 {
    let ret: usize;
    asm!("mov %dr7, {}", out(reg) ret, options(att_syntax));
    Dr7(ret)
}

/// Write dr7.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr7_write(val: Dr7) {
    asm!("mov {}, %dr7", in(reg) val.0, options(att_syntax));
}
<commit_msg>Update debugregs code, fix bug more types.<commit_after>//! Functions to read and write debug registers.
//!
//! * The dr{0,1,2,3} registers are used to set break points.
//! * The dr6 register contains debug conditions that were sampled at the time
//!   the last debug exception.
//! * The dr7 register enables or disables breakpoints and sets breakpoint
//!   conditions.
//!
//! See Intel Vol. 3a Chapter 17, "Debug, Branch, Profile, TSC ... Features"
//!
//! # Potential API Improvements
//! Maybe `Breakpoint` should be a linear type, and functions that mutate
//! dr0-dr3 should take `&mut self`. That would mean we'd have to remove
//! `BREAKPOINT_REGS` and a client maintains some mutable instance to the
//! registers on every core on its own.

use bit_field::BitField;
use bitflags::bitflags;

/// An array list of all available breakpoint registers.
pub const BREAKPOINT_REGS: [Breakpoint; 4] = [
    Breakpoint::Dr0,
    Breakpoint::Dr1,
    Breakpoint::Dr2,
    Breakpoint::Dr3,
];

/// Read dr0.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr0() -> usize {
    let ret: usize;
    asm!("mov %dr0, {}", out(reg) ret, options(att_syntax));
    ret
}

/// Write dr0.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr0_write(val: usize) {
    asm!("mov {}, %dr0", in(reg) val, options(att_syntax));
}

/// Read dr1.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr1() -> usize {
    let ret: usize;
    asm!("mov %dr1, {}", out(reg) ret, options(att_syntax));
    ret
}

/// Write dr1.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr1_write(val: usize) {
    asm!("mov {}, %dr1", in(reg) val, options(att_syntax));
}

/// Read dr2.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr2() -> usize {
    let ret: usize;
    asm!("mov %dr2, {}", out(reg) ret, options(att_syntax));
    ret
}

/// Write dr2.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr2_write(val: usize) {
    asm!("mov {}, %dr2", in(reg) val, options(att_syntax));
}

/// Read dr3.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr3() -> usize {
    let ret: usize;
    asm!("mov %dr3, {}", out(reg) ret, options(att_syntax));
    ret
}

/// Write dr3.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr3_write(val: usize) {
    asm!("mov {}, %dr3", in(reg) val, options(att_syntax));
}

bitflags! {
    /// Debug register 6 (dr6) flags.
    pub struct Dr6: usize {
        /// B0 breakpoint condition detected
        ///
        /// # Notes
        ///
        /// The flag is set if the condition described for the breakpoint by
        /// the LENn, and R/Wn flags in debug control register DR7 is true. They
        /// may or may not be set if the breakpoint is not enabled by the Ln or
        /// the Gn flags in register DR7. Therefore on a #DB, a debug handler
        /// should check only those B0-B3 bits which correspond to an enabled
        /// breakpoint.
        const B0 = 0b0001;

        /// B1 breakpoint condition detected
        ///
        /// # Notes
        ///
        /// The flag is set if the condition described for the breakpoint by
        /// the LENn, and R/Wn flags in debug control register DR7 is true. They
        /// may or may not be set if the breakpoint is not enabled by the Ln or
        /// the Gn flags in register DR7. Therefore on a #DB, a debug handler
        /// should check only those B0-B3 bits which correspond to an enabled
        /// breakpoint.
        const B1 = 0b0010;

        /// B2 breakpoint condition detected
        ///
        /// # Notes
        ///
        /// The flag is set if the condition described for the breakpoint by
        /// the LENn, and R/Wn flags in debug control register DR7 is true. They
        /// may or may not be set if the breakpoint is not enabled by the Ln or
        /// the Gn flags in register DR7. Therefore on a #DB, a debug handler
        /// should check only those B0-B3 bits which correspond to an enabled
        /// breakpoint.
        const B2 = 0b0100;

        /// B3 breakpoint condition detected
        ///
        /// # Notes
        ///
        /// The flag is set if the condition described for the breakpoint by
        /// the LENn, and R/Wn flags in debug control register DR7 is true. They
        /// may or may not be set if the breakpoint is not enabled by the Ln or
        /// the Gn flags in register DR7. Therefore on a #DB, a debug handler
        /// should check only those B0-B3 bits which correspond to an enabled
        /// breakpoint.
        const B3 = 0b1000;

        /// BD debug register access detected
        ///
        /// Indicates that the next instruction in the instruction stream
        /// accesses one of the debug registers.
        ///
        /// This flag is enabled when the GD (general detect) flag in debug
        /// control register DR7 is set.
        const BD = 1 << 13;

        /// BS single step
        ///
        /// Indicates (when set) that the debug exception was triggered by the
        /// single- step execution mode (enabled with the TF flag in the EFLAGS
        /// register).
        const BS = 1 << 14;

        /// BT task switch
        ///
        /// Indicates (when set) that the debug exception resulted from a task
        /// switch where the T flag (debug trap flag) in the TSS of the target
        /// task was set.
        const BT = 1 << 15;

        /// Enables (when set) advanced debugging of RTM transactional regions.
        const RTM = 1 << 16;
    }
}

/// Read dr6.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr6() -> Dr6 {
    let ret: usize;
    asm!("mov %dr6, {}", out(reg) ret, options(att_syntax));
    Dr6::from_bits_truncate(ret)
}

/// Write dr6.
///
/// # Notes
///
/// Certain debug exceptions may clear bits 0-3. The remaining contents of the
/// DR6 register are never cleared by the processor. To avoid confusion in
/// identifying debug exceptions, debug handlers should clear the register
/// (except bit 16, which they should set) before returning to the interrupted
/// task).
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr6_write(val: Dr6) {
    asm!("mov {}, %dr6", in(reg) val.bits, options(att_syntax));
}

/// Specifies available hardware breakpoints.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Breakpoint {
    Dr0 = 0,
    Dr1 = 1,
    Dr2 = 2,
    Dr3 = 3,
}

impl Breakpoint {
    /// Write dr{0-3} register based on provided enum variant.
    ///
    /// # Safety
    /// Needs CPL 0.
    pub unsafe fn write(&self, val: usize) {
        match self {
            Breakpoint::Dr0 => dr0_write(val),
            Breakpoint::Dr1 => dr1_write(val),
            Breakpoint::Dr2 => dr2_write(val),
            Breakpoint::Dr3 => dr3_write(val),
        }
    }

    /// Read dr{0-3} register based on enum variant.
    ///
    /// # Safety
    /// Needs CPL 0.
    pub unsafe fn dr(&self) -> usize {
        match self {
            Breakpoint::Dr0 => dr0(),
            Breakpoint::Dr1 => dr1(),
            Breakpoint::Dr2 => dr2(),
            Breakpoint::Dr3 => dr3(),
        }
    }

    /// Configures the breakpoint by writing `dr` registers.
    ///
    /// # Safety
    /// Needs CPL 0.
    pub unsafe fn configure(&self, addr: usize, bc: BreakCondition, bs: BreakSize) {
        self.write(addr);
        let mut dr7 = dr7();
        dr7.configure_bp(*self, bc, bs);
        dr7_write(dr7);
    }

    /// Enables the breakpoint with `dr7_write`.
    ///
    /// # Safety
    /// Needs CPL 0.
    unsafe fn enable(&self, global: bool) {
        let mut dr7 = dr7();
        dr7.enable_bp(*self, global);
        dr7_write(dr7);
    }

    /// Enable the breakpoint in global mode.
    ///
    /// # Safety
    /// Needs CPL 0.
    pub unsafe fn enable_global(&self) {
        self.enable(true);
    }

    /// Enable the breakpoint in local mode.
    ///
    /// # Safety
    /// Needs CPL 0.
    pub unsafe fn enable_local(&self) {
        self.enable(false);
    }

    /// Disable the breakpoint with `dr7_write`.
    ///
    /// # Safety
    /// Needs CPL 0.
    unsafe fn disable(&self, global: bool) {
        self.write(0x0);
        let mut dr7 = dr7();
        dr7.disable_bp(*self, global);
        dr7_write(dr7);
    }

    /// Disable breakpoint in global mode.
    ///
    /// # Safety
    /// Needs CPL 0.
    pub unsafe fn disable_global(&self) {
        self.disable(true);
    }

    /// Disable breakpoint in local mode.
    ///
    /// # Safety
    /// Needs CPL 0.
    pub unsafe fn disable_local(&self) {
        self.disable(false);
    }
}

/// Specifies the  breakpoint condition for a corresponding breakpoint.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BreakCondition {
    /// 00 — Break on instruction execution only.
    Instructions = 0b00,
    /// 01 — Break on data writes only.
    DataWrites = 0b01,
    /// 10 — Break on I/O reads or writes.
    ///
    /// # Notes
    /// For this type to be available, the DE (debug extensions) flag in control
    /// register CR4 must be set.
    IoReadsWrites = 0b10,
    /// 11 — Break on data reads or writes but not instruction fetches.
    DataReadsWrites = 0b11,
}

/// Specify the size of the memory location at the address specified in the
/// corresponding breakpoint address register (DR0 through DR3).
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BreakSize {
    /// 00 — 1-byte length.
    Bytes1 = 0b00,
    /// 01 — 2-byte length.
    Bytes2 = 0b01,
    /// 10 — 8 byte length (or undefined, on older processors).
    Bytes8 = 0b10,
    /// 11 — 4-byte length.
    Bytes4 = 0b11,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Dr7(pub usize);

impl Default for Dr7 {
    fn default() -> Self {
        Self(Dr7::EMPTY)
    }
}

impl Dr7 {
    /// Empty Dr7 has bit 10 always set.
    pub const EMPTY: usize = 1 << 10;

    /// Bit that controls debug-register protection.
    pub const GD_BIT: usize = 13;

    /// Bit that controls debugging of RTM transactional regions.
    pub const RTM_BIT: usize = 11;

    /// Bit that controls global exact breakpoints.
    pub const GE_BIT: usize = 9;

    /// Bit that controls local exact breakpoints.
    pub const LE_BIT: usize = 8;

    /// Enable/disable a breakpoint either as global or local.
    ///
    /// # Arguments
    /// * `bp` - The breakpoint to enable/disable.
    /// * `global` - Whether the breakpoint is global or local.
    /// * `enable` - Whether to enable or disable the breakpoint.
    fn set_bp(&mut self, bp: Breakpoint, global: bool, enable: bool) {
        let bp = bp as usize;
        assert!(bp < 4);
        let idx = if global { bp * 2 + 1 } else { bp * 2 };
        assert!(idx <= 7);
        self.0.set_bit(idx, enable);
    }

    /// Set break condition `bc` for a given breakpoint `bc`.
    fn set_bc(&mut self, bp: Breakpoint, bc: BreakCondition) {
        let idx = 16 + (bp as usize * 4);
        assert!(idx == 16 || idx == 20 || idx == 24 || idx == 28);
        self.0.set_bits(idx..=idx + 1, bc as usize);
    }

    /// Set size `bs` for a given break point `bp`.
    fn set_bs(&mut self, bp: Breakpoint, bs: BreakSize) {
        let idx = 18 + (bp as usize * 4);
        assert!(idx == 18 || idx == 22 || idx == 26 || idx == 30);
        self.0.set_bits(idx..=idx + 1, bs as usize);
    }

    /// Configures a breakpoint condition `bc` and size `bs` for the associated
    /// breakpoint `bp`.
    ///
    /// # Note
    /// This should be called before `enable_bp`.
    pub fn configure_bp(&mut self, bp: Breakpoint, bc: BreakCondition, bs: BreakSize) {
        assert!(
            !(bc == BreakCondition::Instructions && bs != BreakSize::Bytes1),
            "If bc is 00 (instruction execution), then the bs field should be 00"
        );
        self.set_bc(bp, bc);
        self.set_bs(bp, bs);
    }

    /// Enables the breakpoint condition for the associated breakpoint.
    ///
    /// # Arguments
    /// * `bp` - The breakpoint to enable.
    /// * `global` - If true, the breakpoint is global (e.g., never reset on
    ///   task switches). If false, the CPU resets the flag (disables bp) on
    ///   task switch.
    pub fn enable_bp(&mut self, bp: Breakpoint, global: bool) {
        self.set_bp(bp, global, true);
    }

    /// Disables the breakpoint condition for the associated breakpoint.
    ///
    /// - `bp`: The breakpoint to disable.
    /// - `global`: If true, the global breakpoint bit is unset (e.g., never
    ///   reset on task switches). If false, the local breakpoint bit is unset.
    pub fn disable_bp(&mut self, bp: Breakpoint, global: bool) {
        self.set_bp(bp, global, false);
    }

    /// Local exact breakpoint enable.
    ///
    /// This flag causes the processor to detect the exact instruction that
    /// caused a data breakpoint condition. This feature is not supported in the
    /// P6 family processors, later IA-32 processors, and Intel 64 processors.
    ///
    /// For backward and forward compatibility with other Intel processors,
    /// Intel recommends that the LE flag be set to 1 if exact breakpoints are
    /// required.
    pub fn enable_exact_local_bp(&mut self) {
        self.0.set_bit(Dr7::LE_BIT, true);
    }

    /// Global exact breakpoint enable.
    ///
    /// This flag causes the processor to detect the exact instruction that
    /// caused a data breakpoint condition. This feature is not supported in the
    /// P6 family processors, later IA-32 processors, and Intel 64 processors.
    ///
    /// For backward and forward compatibility with other Intel processors,
    /// Intel recommends that the GE flag be set to 1 if exact breakpoints are
    /// required.
    pub fn enable_exact_global_bp(&mut self) {
        self.0.set_bit(Dr7::GE_BIT, true);
    }

    /// Enables advanced debugging of RTM transactional regions.
    ///
    /// # Note
    /// This advanced debugging is enabled only if IA32_DEBUGCTL.RTM is also
    /// set.
    pub fn enable_rtm(&mut self) {
        self.0.set_bit(Dr7::RTM_BIT, true);
    }

    /// Enables debug-register protection, which causes a debug exception to be
    /// generated prior to any MOV instruction that accesses a debug register.
    pub fn enable_general_detect(&mut self) {
        self.0.set_bit(Dr7::GD_BIT, true);
    }
}

/// Read dr7.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr7() -> Dr7 {
    let ret: usize;
    asm!("mov %dr7, {}", out(reg) ret, options(att_syntax));
    Dr7(ret)
}

/// Write dr7.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn dr7_write(val: Dr7) {
    asm!("mov {}, %dr7", in(reg) val.0, options(att_syntax));
}
<|endoftext|>


<commit_before>use lexer::{Symbol, Token, Tokens};
use function::{Function, Functions, functions};
use error::EvaluatorError;
use constants::{VERSION, KEYWORDS, HELP, LICENSE};
use std::u32;

pub struct Evaluator {
    functions: Functions,
}

impl Evaluator {
    pub fn new() -> Evaluator {
        Evaluator { functions: Functions::new() }
    }

    fn is_keyword(&self, variable: &String) -> Option<&str> {
        for keyword in KEYWORDS {
            if keyword.to_string() == variable.to_lowercase() {
                return Some(keyword);
            }
        }

        None
    }

    pub fn evaluate(&self, tokens: Tokens) -> Result<Vec<String>, EvaluatorError> {
        let mut result: Vec<String> = Vec::with_capacity(3);
        let mut stack: Vec<u32> = Vec::with_capacity(3);

        if tokens.is_empty() {
            return Ok(result);
        }

        for (position, token) in tokens {
            match token {
                Token::Decimal(ref dec) => {
                    stack.push(dec.parse().unwrap());
                }
                Token::Hexadecimal(ref hex) => {
                    stack.push(u32::from_str_radix(hex.as_str().split_at(2).1, 16).unwrap());
                }
                Token::Keyword(ref kw) => {
                    if let Some(keyword) = self.is_keyword(kw) {
                        match keyword {
                            "version" => result.push(VERSION.to_string()),
                            "help" => {
                                let mut h = HELP.lines()
                                    .map(|line| line.to_string())
                                    .collect();
                                result.append(&mut h);
                            }
                            "license" => {
                                let mut l = LICENSE.lines()
                                    .map(|line| line.to_string())
                                    .collect();
                                result.append(&mut l);
                            }
                            "exit" => return Err(EvaluatorError::Exit),
                            _ => unreachable!(),
                        }
                        return Ok(result);
                    } else {
                        return Err(EvaluatorError::UnknownKeyword(position));
                    }
                }
                Token::Operator(ref op) => {
                    let function = self.functions.get(&op).unwrap();
                    if stack.len() >= function.arity {
                        let stack_len = stack.len();
                        let args: Vec<u32> = stack.split_off(stack_len - function.arity);
                        let interm_result = try!((function.handle)(args, position));
                        stack.push(interm_result.0);
                        result.push(interm_result.1);
                        result.push(interm_result.0.to_string());
                    } else {
                        return Err(EvaluatorError::MissingArgument(position));
                    }
                }
                _ => continue,

            }
        }

        // The last element on the stack should be the final result
        if stack.len() != 1 {
            return Err(EvaluatorError::TooManyArguments);
        } else if result.is_empty() {
            result.push(stack.pop().unwrap().to_string());
        }

        Ok(result)
    }
}

impl Default for Evaluator {
    fn default() -> Evaluator {
        let mut evaluator = Evaluator::new();

        evaluator.functions.insert(Symbol::NOT, Function::new(1, Box::new(functions::not)));
        evaluator.functions.insert(Symbol::XOR, Function::new(2, Box::new(functions::xor)));
        evaluator.functions.insert(Symbol::OR, Function::new(2, Box::new(functions::or)));
        evaluator.functions.insert(Symbol::AND, Function::new(2, Box::new(functions::and)));
        evaluator.functions.insert(Symbol::LSHIFT,
                                   Function::new(2, Box::new(functions::lshift)));
        evaluator.functions.insert(Symbol::RSHIFT,
                                   Function::new(2, Box::new(functions::rshift)));

        evaluator
    }
}
<commit_msg>Move is_keyword out of Evaluator to a helper function<commit_after>use lexer::{Symbol, Token, Tokens};
use function::{Function, Functions, functions};
use error::EvaluatorError;
use constants::{VERSION, KEYWORDS, HELP, LICENSE};
use std::u32;

pub struct Evaluator {
    functions: Functions,
}

fn is_keyword(variable: &String) -> Option<&str> {
    for keyword in KEYWORDS {
        if keyword.to_string() == variable.to_lowercase() {
            return Some(keyword);
        }
    }

    None
}

impl Evaluator {
    pub fn new() -> Evaluator {
        Evaluator { functions: Functions::new() }
    }

    pub fn evaluate(&self, tokens: Tokens) -> Result<Vec<String>, EvaluatorError> {
        let mut result: Vec<String> = Vec::with_capacity(3);
        let mut stack: Vec<u32> = Vec::with_capacity(3);

        if tokens.is_empty() {
            return Ok(result);
        }

        for (position, token) in tokens {
            match token {
                Token::Decimal(ref dec) => {
                    stack.push(dec.parse().unwrap());
                }
                Token::Hexadecimal(ref hex) => {
                    stack.push(u32::from_str_radix(hex.as_str().split_at(2).1, 16).unwrap());
                }
                Token::Keyword(ref kw) => {
                    if let Some(keyword) = is_keyword(kw) {
                        match keyword {
                            "version" => result.push(VERSION.to_string()),
                            "help" => {
                                let mut h = HELP.lines()
                                    .map(|line| line.to_string())
                                    .collect();
                                result.append(&mut h);
                            }
                            "license" => {
                                let mut l = LICENSE.lines()
                                    .map(|line| line.to_string())
                                    .collect();
                                result.append(&mut l);
                            }
                            "exit" => return Err(EvaluatorError::Exit),
                            _ => unreachable!(),
                        }
                        return Ok(result);
                    } else {
                        return Err(EvaluatorError::UnknownKeyword(position));
                    }
                }
                Token::Operator(ref op) => {
                    let function = self.functions.get(&op).unwrap();
                    if stack.len() >= function.arity {
                        let stack_len = stack.len();
                        let args: Vec<u32> = stack.split_off(stack_len - function.arity);
                        let interm_result = try!((function.handle)(args, position));
                        stack.push(interm_result.0);
                        result.push(interm_result.1);
                        result.push(interm_result.0.to_string());
                    } else {
                        return Err(EvaluatorError::MissingArgument(position));
                    }
                }
                _ => continue,

            }
        }

        // The last element on the stack should be the final result
        if stack.len() != 1 {
            return Err(EvaluatorError::TooManyArguments);
        } else if result.is_empty() {
            result.push(stack.pop().unwrap().to_string());
        }

        Ok(result)
    }
}

impl Default for Evaluator {
    fn default() -> Evaluator {
        let mut evaluator = Evaluator::new();

        evaluator.functions.insert(Symbol::NOT, Function::new(1, Box::new(functions::not)));
        evaluator.functions.insert(Symbol::XOR, Function::new(2, Box::new(functions::xor)));
        evaluator.functions.insert(Symbol::OR, Function::new(2, Box::new(functions::or)));
        evaluator.functions.insert(Symbol::AND, Function::new(2, Box::new(functions::and)));
        evaluator.functions.insert(Symbol::LSHIFT,
                                   Function::new(2, Box::new(functions::lshift)));
        evaluator.functions.insert(Symbol::RSHIFT,
                                   Function::new(2, Box::new(functions::rshift)));

        evaluator
    }
}
<|endoftext|>


<commit_before>use std::hash::BuildHasher;
use std::hash::BuildHasherDefault;
use std::hash::Hasher;
use std::collections::HashMap;
use std::collections::BinaryHeap;
use std::fmt::{self};
use twox_hash::XxHash64;

/// As a convenience, rust-hash-ring provides a default struct to hold node
/// information. It is optional and you can define your own.
#[derive(Clone, Debug, PartialEq)]
pub struct NodeInfo {
    pub host: &'static str,
    pub port: u16,
}

impl fmt::Display for NodeInfo {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{}:{}", self.host, self.port)
    }
}

type XxHash64Hasher = BuildHasherDefault<XxHash64>;

/// HashRing
pub struct HashRing<T, S = XxHash64Hasher> {
    replicas: isize,
    ring: HashMap<u64, T>,
    sorted_keys: Vec<u64>,
    hash_builder: S,
}

impl<T: ToString + Clone> HashRing<T, XxHash64Hasher> {
    /// Creates a new hash ring with the specified nodes.
    /// Replicas is the number of virtual nodes each node has to make a better distribution.
    pub fn new(nodes: Vec<T>, replicas: isize) -> HashRing<T, XxHash64Hasher> {
        HashRing::with_hasher(nodes, replicas, XxHash64Hasher::default())
    }
}

impl<T, S> HashRing<T, S>
where
    T: ToString + Clone,
    S: BuildHasher,
{

    pub fn with_hasher(nodes: Vec<T>, replicas: isize, hash_builder: S) -> HashRing<T, S> {
        let mut new_hash_ring: HashRing<T, S> = HashRing {
            replicas,
            ring: HashMap::new(),
            sorted_keys: Vec::new(),
            hash_builder,
        };

        for n in &nodes {
            new_hash_ring.add_node(n);
        }
        new_hash_ring
    }

    /// Adds a node to the hash ring
    pub fn add_node(&mut self, node: &T) {
        for i in 0..self.replicas {
            let key = self.gen_key(format!("{}:{}", node.to_string(), i));
            self.ring.insert(key, (*node).clone());
            self.sorted_keys.push(key);
        }

        self.sorted_keys = BinaryHeap::from(self.sorted_keys.clone()).into_sorted_vec();
    }

    /// Deletes a node from the hash ring
    pub fn remove_node(&mut self, node: &T) {
        for i in 0..self.replicas {
            let key = self.gen_key(format!("{}:{}", node.to_string(), i));
            if !self.ring.contains_key(&key) {
                return;
            }
            self.ring.remove(&key);
            let mut index = 0;
            for j in 0..self.sorted_keys.len() {
                if self.sorted_keys[j] == key {
                    index = j;
                    break;
                }
            }
            self.sorted_keys.remove(index);
        }
    }

    /// Gets the node a specific key belongs to
    pub fn get_node(&self, key: String) -> Option<&T> {
        if self.sorted_keys.is_empty() {
            return None;
        }

        let generated_key = self.gen_key(key);
        let nodes = self.sorted_keys.clone();

        for node in &nodes {
            if generated_key <= *node {
                return Some(self.ring.get(node).unwrap());
            }
        }

        let node = &nodes[0];
        return Some(self.ring.get(node).unwrap());
    }

    /// Generates a key from a string value
    fn gen_key(&self, key: String) -> u64 {
        let mut hasher = self.hash_builder.build_hasher();
        hasher.write(key.as_bytes());
        hasher.finish()
    }
}

#[cfg(test)]
mod test {
    use std::hash::Hasher;
    use std::hash::BuildHasherDefault;
    use hash_ring::{NodeInfo, HashRing};

    // Defines a NodeInfo for a localhost address with a given port.
    fn node(port: u16) -> NodeInfo {
        NodeInfo {
            host: "localhost",
            port,
        }
    }

    #[test]
    fn test_empty_ring() {
        let hash_ring: HashRing<NodeInfo> = HashRing::new(vec![], 10);
        assert_eq!(None, hash_ring.get_node("hello".to_string()));
    }

    #[test]
    fn test_default_nodes() {
        let mut nodes: Vec<NodeInfo> = Vec::new();
        nodes.push(node(15324));
        nodes.push(node(15325));
        nodes.push(node(15326));
        nodes.push(node(15327));
        nodes.push(node(15328));
        nodes.push(node(15329));

        let mut hash_ring: HashRing<NodeInfo> = HashRing::new(nodes, 10);

        assert_eq!(Some(&node(15326)), hash_ring.get_node("hello".to_string()));
        assert_eq!(Some(&node(15327)), hash_ring.get_node("dude".to_string()));
        assert_eq!(Some(&node(15324)), hash_ring.get_node("two".to_string()));

        hash_ring.remove_node(&node(15329));
        assert_eq!(Some(&node(15326)), hash_ring.get_node("hello".to_string()));

        hash_ring.add_node(&node(15329));
        assert_eq!(Some(&node(15326)), hash_ring.get_node("hello".to_string()));
    }

    #[derive(Clone)]
    struct CustomNodeInfo {
        pub host: &'static str,
        pub port: u16,
    }

    impl ToString for CustomNodeInfo {
        fn to_string(&self) -> String {
            format!("{}:{}", self.host, self.port)
        }
    }

    #[test]
    fn test_custom_nodes() {
        let mut nodes: Vec<CustomNodeInfo> = Vec::new();
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15324,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15325,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15326,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15327,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15328,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15329,
        });

        let mut hash_ring: HashRing<CustomNodeInfo> = HashRing::new(nodes, 10);

        assert_eq!(
            Some("localhost:15326".to_string()),
            hash_ring.get_node("hello".to_string()).map(
                |x| x.to_string(),
            )
        );
        assert_eq!(
            Some("localhost:15327".to_string()),
            hash_ring.get_node("dude".to_string()).map(
                |x| x.to_string(),
            )
        );

        hash_ring.remove_node(&CustomNodeInfo {
            host: "localhost",
            port: 15329,
        });
        assert_eq!(
            Some("localhost:15326".to_string()),
            hash_ring.get_node("hello".to_string()).map(
                |x| x.to_string(),
            )
        );

        hash_ring.add_node(&CustomNodeInfo {
            host: "localhost",
            port: 15329,
        });
        assert_eq!(
            Some("localhost:15326".to_string()),
            hash_ring.get_node("hello".to_string()).map(
                |x| x.to_string(),
            )
        );
    }

    #[test]
    fn test_remove_actual_node() {
        let mut nodes: Vec<NodeInfo> = Vec::new();
        nodes.push(node(15324));
        nodes.push(node(15325));
        nodes.push(node(15326));
        nodes.push(node(15327));
        nodes.push(node(15328));
        nodes.push(node(15329));

        let mut hash_ring: HashRing<NodeInfo> = HashRing::new(nodes, 10);

        // This should be num nodes * num replicas
        assert_eq!(60, hash_ring.sorted_keys.len());
        assert_eq!(60, hash_ring.ring.len());

        hash_ring.remove_node(&node(15326));

        // This should be num nodes * num replicas
        assert_eq!(50, hash_ring.sorted_keys.len());
        assert_eq!(50, hash_ring.ring.len());
    }

    #[test]
    fn test_remove_non_existent_node() {
        let mut nodes: Vec<NodeInfo> = Vec::new();
        nodes.push(node(15324));
        nodes.push(node(15325));
        nodes.push(node(15326));
        nodes.push(node(15327));
        nodes.push(node(15328));
        nodes.push(node(15329));

        let mut hash_ring: HashRing<NodeInfo> = HashRing::new(nodes, 10);

        hash_ring.remove_node(&node(15330));

        // This should be num nodes * num replicas
        assert_eq!(60, hash_ring.sorted_keys.len());
        assert_eq!(60, hash_ring.ring.len());
    }

    #[test]
    fn test_custom_hasher() {
        #[derive(Default)]
        struct ConstantHasher;

        impl Hasher for ConstantHasher {
            fn write(&mut self, _bytes: &[u8]) {
                // Do nothing
            }

            fn finish(&self) -> u64 {
                return 1;
            }
        }

        type ConstantBuildHasher = BuildHasherDefault<ConstantHasher>;

        let mut nodes: Vec<NodeInfo> = Vec::new();
        nodes.push(node(15324));
        nodes.push(node(15325));
        nodes.push(node(15326));
        nodes.push(node(15327));
        nodes.push(node(15328));
        nodes.push(node(15329));

        let hash_ring: HashRing<NodeInfo, ConstantBuildHasher> = HashRing::with_hasher(nodes, 10, ConstantBuildHasher::default());

        assert_eq!(Some(&node(15329)), hash_ring.get_node("hello".to_string()));
        assert_eq!(Some(&node(15329)), hash_ring.get_node("dude".to_string()));
        assert_eq!(Some(&node(15329)), hash_ring.get_node("two".to_string()));
    }
}
<commit_msg>rustfmt hash_ring.rs<commit_after>use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::fmt::{self};
use std::hash::BuildHasher;
use std::hash::BuildHasherDefault;
use std::hash::Hasher;
use twox_hash::XxHash64;

/// As a convenience, rust-hash-ring provides a default struct to hold node
/// information. It is optional and you can define your own.
#[derive(Clone, Debug, PartialEq)]
pub struct NodeInfo {
    pub host: &'static str,
    pub port: u16,
}

impl fmt::Display for NodeInfo {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{}:{}", self.host, self.port)
    }
}

type XxHash64Hasher = BuildHasherDefault<XxHash64>;

/// HashRing
pub struct HashRing<T, S = XxHash64Hasher> {
    replicas: isize,
    ring: HashMap<u64, T>,
    sorted_keys: Vec<u64>,
    hash_builder: S,
}

impl<T: ToString + Clone> HashRing<T, XxHash64Hasher> {
    /// Creates a new hash ring with the specified nodes.
    /// Replicas is the number of virtual nodes each node has to make a better distribution.
    pub fn new(nodes: Vec<T>, replicas: isize) -> HashRing<T, XxHash64Hasher> {
        HashRing::with_hasher(nodes, replicas, XxHash64Hasher::default())
    }
}

impl<T, S> HashRing<T, S>
where
    T: ToString + Clone,
    S: BuildHasher,
{
    pub fn with_hasher(nodes: Vec<T>, replicas: isize, hash_builder: S) -> HashRing<T, S> {
        let mut new_hash_ring: HashRing<T, S> = HashRing {
            replicas,
            ring: HashMap::new(),
            sorted_keys: Vec::new(),
            hash_builder,
        };

        for n in &nodes {
            new_hash_ring.add_node(n);
        }
        new_hash_ring
    }

    /// Adds a node to the hash ring
    pub fn add_node(&mut self, node: &T) {
        for i in 0..self.replicas {
            let key = self.gen_key(format!("{}:{}", node.to_string(), i));
            self.ring.insert(key, (*node).clone());
            self.sorted_keys.push(key);
        }

        self.sorted_keys = BinaryHeap::from(self.sorted_keys.clone()).into_sorted_vec();
    }

    /// Deletes a node from the hash ring
    pub fn remove_node(&mut self, node: &T) {
        for i in 0..self.replicas {
            let key = self.gen_key(format!("{}:{}", node.to_string(), i));
            if !self.ring.contains_key(&key) {
                return;
            }
            self.ring.remove(&key);
            let mut index = 0;
            for j in 0..self.sorted_keys.len() {
                if self.sorted_keys[j] == key {
                    index = j;
                    break;
                }
            }
            self.sorted_keys.remove(index);
        }
    }

    /// Gets the node a specific key belongs to
    pub fn get_node(&self, key: String) -> Option<&T> {
        if self.sorted_keys.is_empty() {
            return None;
        }

        let generated_key = self.gen_key(key);
        let nodes = self.sorted_keys.clone();

        for node in &nodes {
            if generated_key <= *node {
                return Some(self.ring.get(node).unwrap());
            }
        }

        let node = &nodes[0];
        return Some(self.ring.get(node).unwrap());
    }

    /// Generates a key from a string value
    fn gen_key(&self, key: String) -> u64 {
        let mut hasher = self.hash_builder.build_hasher();
        hasher.write(key.as_bytes());
        hasher.finish()
    }
}

#[cfg(test)]
mod test {
    use hash_ring::{HashRing, NodeInfo};
    use std::hash::BuildHasherDefault;
    use std::hash::Hasher;

    // Defines a NodeInfo for a localhost address with a given port.
    fn node(port: u16) -> NodeInfo {
        NodeInfo {
            host: "localhost",
            port,
        }
    }

    #[test]
    fn test_empty_ring() {
        let hash_ring: HashRing<NodeInfo> = HashRing::new(vec![], 10);
        assert_eq!(None, hash_ring.get_node("hello".to_string()));
    }

    #[test]
    fn test_default_nodes() {
        let mut nodes: Vec<NodeInfo> = Vec::new();
        nodes.push(node(15324));
        nodes.push(node(15325));
        nodes.push(node(15326));
        nodes.push(node(15327));
        nodes.push(node(15328));
        nodes.push(node(15329));

        let mut hash_ring: HashRing<NodeInfo> = HashRing::new(nodes, 10);

        assert_eq!(Some(&node(15326)), hash_ring.get_node("hello".to_string()));
        assert_eq!(Some(&node(15327)), hash_ring.get_node("dude".to_string()));
        assert_eq!(Some(&node(15324)), hash_ring.get_node("two".to_string()));

        hash_ring.remove_node(&node(15329));
        assert_eq!(Some(&node(15326)), hash_ring.get_node("hello".to_string()));

        hash_ring.add_node(&node(15329));
        assert_eq!(Some(&node(15326)), hash_ring.get_node("hello".to_string()));
    }

    #[derive(Clone)]
    struct CustomNodeInfo {
        pub host: &'static str,
        pub port: u16,
    }

    impl ToString for CustomNodeInfo {
        fn to_string(&self) -> String {
            format!("{}:{}", self.host, self.port)
        }
    }

    #[test]
    fn test_custom_nodes() {
        let mut nodes: Vec<CustomNodeInfo> = Vec::new();
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15324,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15325,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15326,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15327,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15328,
        });
        nodes.push(CustomNodeInfo {
            host: "localhost",
            port: 15329,
        });

        let mut hash_ring: HashRing<CustomNodeInfo> = HashRing::new(nodes, 10);

        assert_eq!(
            Some("localhost:15326".to_string()),
            hash_ring
                .get_node("hello".to_string())
                .map(|x| x.to_string(),)
        );
        assert_eq!(
            Some("localhost:15327".to_string()),
            hash_ring
                .get_node("dude".to_string())
                .map(|x| x.to_string(),)
        );

        hash_ring.remove_node(&CustomNodeInfo {
            host: "localhost",
            port: 15329,
        });
        assert_eq!(
            Some("localhost:15326".to_string()),
            hash_ring
                .get_node("hello".to_string())
                .map(|x| x.to_string(),)
        );

        hash_ring.add_node(&CustomNodeInfo {
            host: "localhost",
            port: 15329,
        });
        assert_eq!(
            Some("localhost:15326".to_string()),
            hash_ring
                .get_node("hello".to_string())
                .map(|x| x.to_string(),)
        );
    }

    #[test]
    fn test_remove_actual_node() {
        let mut nodes: Vec<NodeInfo> = Vec::new();
        nodes.push(node(15324));
        nodes.push(node(15325));
        nodes.push(node(15326));
        nodes.push(node(15327));
        nodes.push(node(15328));
        nodes.push(node(15329));

        let mut hash_ring: HashRing<NodeInfo> = HashRing::new(nodes, 10);

        // This should be num nodes * num replicas
        assert_eq!(60, hash_ring.sorted_keys.len());
        assert_eq!(60, hash_ring.ring.len());

        hash_ring.remove_node(&node(15326));

        // This should be num nodes * num replicas
        assert_eq!(50, hash_ring.sorted_keys.len());
        assert_eq!(50, hash_ring.ring.len());
    }

    #[test]
    fn test_remove_non_existent_node() {
        let mut nodes: Vec<NodeInfo> = Vec::new();
        nodes.push(node(15324));
        nodes.push(node(15325));
        nodes.push(node(15326));
        nodes.push(node(15327));
        nodes.push(node(15328));
        nodes.push(node(15329));

        let mut hash_ring: HashRing<NodeInfo> = HashRing::new(nodes, 10);

        hash_ring.remove_node(&node(15330));

        // This should be num nodes * num replicas
        assert_eq!(60, hash_ring.sorted_keys.len());
        assert_eq!(60, hash_ring.ring.len());
    }

    #[test]
    fn test_custom_hasher() {
        #[derive(Default)]
        struct ConstantHasher;

        impl Hasher for ConstantHasher {
            fn write(&mut self, _bytes: &[u8]) {
                // Do nothing
            }

            fn finish(&self) -> u64 {
                return 1;
            }
        }

        type ConstantBuildHasher = BuildHasherDefault<ConstantHasher>;

        let mut nodes: Vec<NodeInfo> = Vec::new();
        nodes.push(node(15324));
        nodes.push(node(15325));
        nodes.push(node(15326));
        nodes.push(node(15327));
        nodes.push(node(15328));
        nodes.push(node(15329));

        let hash_ring: HashRing<NodeInfo, ConstantBuildHasher> =
            HashRing::with_hasher(nodes, 10, ConstantBuildHasher::default());

        assert_eq!(Some(&node(15329)), hash_ring.get_node("hello".to_string()));
        assert_eq!(Some(&node(15329)), hash_ring.get_node("dude".to_string()));
        assert_eq!(Some(&node(15329)), hash_ring.get_node("two".to_string()));
    }
}
<|endoftext|>


<commit_before>use libc::{c_double, c_void};
use std::cmp::{Ordering};
use std::sync::{Once, ONCE_INIT};

static EXACTINIT: Once = ONCE_INIT;

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point2D {
    x: c_double,
    y: c_double,
}

impl Point2D {
    pub fn new(x: c_double, y: c_double) -> Point2D {
        Point2D { x: x, y: y }
    }
}

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point3D {
    x: c_double,
    y: c_double,
    z: c_double,
}

impl Point3D {
    pub fn new(x: c_double, y: c_double, z: c_double) -> Point3D {
        Point3D { x: x, y: y, z: z }
    }
}

#[link(name = "predicates")]
extern "C" {
    fn exactinit() -> c_void;
    fn insphere(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D, pe: *const Point3D) -> c_double;
    fn incircle(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D, pd: *const Point2D) -> c_double;
}

fn init_predicates() {
    EXACTINIT.call_once(|| {
        unsafe { exactinit() };
    });
}

#[derive(Debug, Eq, PartialEq)]
pub enum InCircleLocation {
    Inside,
    Outside,
    On
}

pub trait InCircleTestable<P> {
    fn in_circle_test(&self, point: &P) -> Option<InCircleLocation>;
}

pub struct Triangle<P> {
    p1: P,
    p2: P,
    p3: P,
}

pub struct Tetrahedron<P> {
    p1: P,
    p2: P,
    p3: P,
    p4: P,
}

impl InCircleTestable<Point2D> for Triangle<Point2D> {
    fn in_circle_test(&self, point: &Point2D) -> Option<InCircleLocation> {
        init_predicates();

        let incircle_det = unsafe { incircle(&self.p1, &self.p2, &self.p3, point) };

        match 0.0.partial_cmp(&incircle_det) {
            Some(Ordering::Greater) => { Some(InCircleLocation::Inside) }
            Some(Ordering::Less) => { Some(InCircleLocation::Outside) }
            Some(Ordering::Equal) => { Some(InCircleLocation::On) }
            None => { None }
        }
    }
}

impl InCircleTestable<Point3D> for Tetrahedron<Point3D> {
    fn in_circle_test(&self, point: &Point3D) -> Option<InCircleLocation> {
        init_predicates();

        let incircle_det = unsafe { insphere(&self.p1, &self.p2, &self.p3, &self.p4, point) };

        match 0.0.partial_cmp(&incircle_det) {
            Some(Ordering::Less) => { Some(InCircleLocation::Inside) }
            Some(Ordering::Greater) => { Some(InCircleLocation::Outside) }
            Some(Ordering::Equal) => { Some(InCircleLocation::On) }
            None => { None }
        }
    }
}

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

    use std::f64;

    #[test]
    fn in_circle_2d() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);
        let d_inside = Point2D::new(0.5, 0.5);
        let d_outside = Point2D::new(2.0, 0.0);
        let d_on = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

    #[test]
    fn in_circle_2d_nan_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NAN);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_nan_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NAN);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::INFINITY);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NEG_INFINITY);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NEG_INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_3d() {
        let p1 = Point3D::new(-1.0,  1.0, -1.0);
        let p2 = Point3D::new( 1.0,  1.0, -1.0);
        let p3 = Point3D::new( 0.0, -1.0, -1.0);
        let p4 = Point3D::new( 0.0,  0.0,  1.0);
        let d_inside = Point3D::new(0.0, 0.0, 0.0);
        let d_outside = Point3D::new(10.0, 10.0, 10.0);
        let d_on = Point3D::new(0.0, 0.0, 1.0);

        let t = Tetrahedron { p1: p1, p2: p2, p3: p3, p4: p4 };

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

}
<commit_msg>Implement correct orientation detection<commit_after>use libc::{c_double, c_void};
use std::cmp::{Ordering};
use std::sync::{Once, ONCE_INIT};

static EXACTINIT: Once = ONCE_INIT;

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point2D {
    x: c_double,
    y: c_double,
}

impl Point2D {
    pub fn new(x: c_double, y: c_double) -> Point2D {
        Point2D { x: x, y: y }
    }
}

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point3D {
    x: c_double,
    y: c_double,
    z: c_double,
}

impl Point3D {
    pub fn new(x: c_double, y: c_double, z: c_double) -> Point3D {
        Point3D { x: x, y: y, z: z }
    }
}

#[link(name = "predicates")]
extern "C" {
    fn exactinit() -> c_void;
    fn orient2d(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D) -> c_double;
    fn incircle(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D, pd: *const Point2D) -> c_double;
    fn orient3d(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D) -> c_double;
    fn insphere(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D, pe: *const Point3D) -> c_double;
}

fn init_predicates() {
    EXACTINIT.call_once(|| {
        unsafe { exactinit() };
    });
}

#[derive(Debug, Eq, PartialEq)]
pub enum InCircleLocation {
    Inside,
    Outside,
    On
}

#[derive(Debug, Eq, PartialEq)]
pub enum Orientation {
    Positive,
    Negative
}

impl Orientation {
    pub fn to_f64_multiplier(&self) -> f64 {
        match *self {
            Orientation::Positive => {  1.0 },
            Orientation::Negative => { -1.0 }
        }
    }
}

pub trait InCircleTestable<P> {
    fn in_circle_test(&self, point: &P) -> Option<InCircleLocation>;
}

pub trait Orientable {
    fn orientation(&self) -> Option<Orientation>;
}

pub struct Triangle<P> {
    p1: P,
    p2: P,
    p3: P,
}

pub struct Tetrahedron<P> {
    p1: P,
    p2: P,
    p3: P,
    p4: P,
}

fn det_to_in_circle_location(det: f64) -> Option<InCircleLocation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(InCircleLocation::Inside) }
        Some(Ordering::Less) => { Some(InCircleLocation::Outside) }
        Some(Ordering::Equal) => { Some(InCircleLocation::On) }
        None => { None }
    }
}

fn det_to_orientation(det: f64) -> Option<Orientation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(Orientation::Positive) }
        Some(Ordering::Less) => { Some(Orientation::Negative) }
        _ => { None }
    }
}

impl Orientable for Triangle<Point2D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient2d(&self.p1, &self.p2, &self.p3) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point2D> for Triangle<Point2D> {
    fn in_circle_test(&self, point: &Point2D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { incircle(&self.p1, &self.p2, &self.p3, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

impl Orientable for Tetrahedron<Point3D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient3d(&self.p1, &self.p2, &self.p3, &self.p4) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point3D> for Tetrahedron<Point3D> {
    fn in_circle_test(&self, point: &Point3D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { insphere(&self.p1, &self.p2, &self.p3, &self.p4, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

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

    use std::f64;

    #[test]
    fn in_circle_2d() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);
        let d_inside = Point2D::new(0.5, 0.5);
        let d_outside = Point2D::new(2.0, 0.0);
        let d_on = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

    #[test]
    fn in_circle_2d_nan_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NAN);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_nan_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NAN);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::INFINITY);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NEG_INFINITY);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NEG_INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle { p1: p1, p2: p2, p3: p3 };

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_3d() {
        let p1 = Point3D::new(-1.0,  1.0, -1.0);
        let p2 = Point3D::new( 1.0,  1.0, -1.0);
        let p3 = Point3D::new( 0.0, -1.0, -1.0);
        let p4 = Point3D::new( 0.0,  0.0,  1.0);
        let d_inside = Point3D::new(0.0, 0.0, 0.0);
        let d_outside = Point3D::new(10.0, 10.0, 10.0);
        let d_on = Point3D::new(0.0, 0.0, 1.0);

        let t = Tetrahedron { p1: p1, p2: p2, p3: p3, p4: p4 };

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

}
<|endoftext|>


<commit_before>//! Various data structures used by the Rust compiler. The intention
//! is that code in here should be not be *specific* to rustc, so that
//! it can be easily unit tested and so forth.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
#![feature(control_flow_enum)]
#![feature(in_band_lifetimes)]
#![feature(min_specialization)]
#![feature(auto_traits)]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
#![feature(core_intrinsics)]
#![feature(test)]
#![feature(associated_type_bounds)]
#![feature(thread_id_value)]
#![feature(extend_one)]
#![feature(const_panic)]
#![feature(new_uninit)]
#![feature(once_cell)]
#![feature(maybe_uninit_uninit_array)]
#![feature(min_type_alias_impl_trait)]
#![allow(rustc::default_hash_types)]
#![deny(unaligned_references)]
#![feature(iter_map_while)]
#![feature(bool_to_option)]

#[macro_use]
extern crate tracing;
#[macro_use]
extern crate cfg_if;
#[macro_use]
extern crate rustc_macros;

#[inline(never)]
#[cold]
pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
    f()
}

#[macro_export]
macro_rules! likely {
    ($e:expr) => {
        match $e {
            #[allow(unused_unsafe)]
            e => unsafe { std::intrinsics::likely(e) },
        }
    };
}

#[macro_export]
macro_rules! unlikely {
    ($e:expr) => {
        match $e {
            #[allow(unused_unsafe)]
            e => unsafe { std::intrinsics::unlikely(e) },
        }
    };
}

pub mod base_n;
pub mod binary_search_util;
pub mod captures;
pub mod flock;
pub mod functor;
pub mod fx;
pub mod graph;
pub mod jobserver;
pub mod macros;
pub mod map_in_place;
pub mod obligation_forest;
pub mod owning_ref;
pub mod ptr_key;
pub mod sip128;
pub mod small_c_str;
pub mod snapshot_map;
pub mod stable_map;
pub mod svh;
pub use ena::snapshot_vec;
pub mod memmap;
pub mod sorted_map;
pub mod stable_set;
#[macro_use]
pub mod stable_hasher;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod sharded;
pub mod stack;
pub mod sync;
pub mod thin_vec;
pub mod tiny_list;
pub mod transitive_relation;
pub mod vec_linked_list;
pub mod vec_map;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod sso;
pub mod steal;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;

pub use ena::undo_log;
pub use ena::unify;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
    /// Forgets the function which prevents it from running.
    /// Ensure that the function owns no memory, otherwise it will be leaked.
    #[inline]
    pub fn disable(self) {
        std::mem::forget(self);
    }
}

impl<F: Fn()> Drop for OnDrop<F> {
    #[inline]
    fn drop(&mut self) {
        (self.0)();
    }
}

// See comments in src/librustc_middle/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
<commit_msg>Sort features alphabetically<commit_after>//! Various data structures used by the Rust compiler. The intention
//! is that code in here should be not be *specific* to rustc, so that
//! it can be easily unit tested and so forth.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(allow_internal_unstable)]
#![feature(array_windows)]
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
#![feature(bool_to_option)]
#![feature(const_panic)]
#![feature(control_flow_enum)]
#![feature(core_intrinsics)]
#![feature(extend_one)]
#![feature(hash_raw_entry)]
#![feature(in_band_lifetimes)]
#![feature(iter_map_while)]
#![feature(maybe_uninit_uninit_array)]
#![feature(min_specialization)]
#![feature(min_type_alias_impl_trait)]
#![feature(new_uninit)]
#![feature(nll)]
#![feature(once_cell)]
#![feature(test)]
#![feature(thread_id_value)]
#![allow(rustc::default_hash_types)]
#![deny(unaligned_references)]

#[macro_use]
extern crate tracing;
#[macro_use]
extern crate cfg_if;
#[macro_use]
extern crate rustc_macros;

#[inline(never)]
#[cold]
pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
    f()
}

#[macro_export]
macro_rules! likely {
    ($e:expr) => {
        match $e {
            #[allow(unused_unsafe)]
            e => unsafe { std::intrinsics::likely(e) },
        }
    };
}

#[macro_export]
macro_rules! unlikely {
    ($e:expr) => {
        match $e {
            #[allow(unused_unsafe)]
            e => unsafe { std::intrinsics::unlikely(e) },
        }
    };
}

pub mod base_n;
pub mod binary_search_util;
pub mod captures;
pub mod flock;
pub mod functor;
pub mod fx;
pub mod graph;
pub mod jobserver;
pub mod macros;
pub mod map_in_place;
pub mod obligation_forest;
pub mod owning_ref;
pub mod ptr_key;
pub mod sip128;
pub mod small_c_str;
pub mod snapshot_map;
pub mod stable_map;
pub mod svh;
pub use ena::snapshot_vec;
pub mod memmap;
pub mod sorted_map;
pub mod stable_set;
#[macro_use]
pub mod stable_hasher;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod sharded;
pub mod stack;
pub mod sync;
pub mod thin_vec;
pub mod tiny_list;
pub mod transitive_relation;
pub mod vec_linked_list;
pub mod vec_map;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod sso;
pub mod steal;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;

pub use ena::undo_log;
pub use ena::unify;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
    /// Forgets the function which prevents it from running.
    /// Ensure that the function owns no memory, otherwise it will be leaked.
    #[inline]
    pub fn disable(self) {
        std::mem::forget(self);
    }
}

impl<F: Fn()> Drop for OnDrop<F> {
    #[inline]
    fn drop(&mut self) {
        (self.0)();
    }
}

// See comments in src/librustc_middle/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
<|endoftext|>


<commit_before>pub struct PascalsTriangle {
    row_count: u32,
}

impl PascalsTriangle {
    pub fn new(row_count: u32) -> Self {
        PascalsTriangle { row_count: row_count }
    }

    pub fn rows(&self) -> Vec<Vec<u32>> {
        match self.row_count {
            0 => Vec::new(),
            _ => (1..self.row_count).fold(vec![vec![1]], |res, _| append_next_row(res)),
        }
    }
}

fn append_next_row(mut rows: Vec<Vec<u32>>) -> Vec<Vec<u32>> {
    let end_row = rows.last().unwrap().to_vec();
    let end_row_iter_left = end_row[0..end_row.len() - 1].iter();
    let end_row_iter_right = end_row[1..end_row.len()].iter();

    let mut next_row: Vec<u32> = end_row_iter_left.zip(end_row_iter_right)
        .fold(vec![1], |mut res, (x, y)| {
            res.push(x + y);
            res
        });
    next_row.push(1);

    rows.push(next_row);
    rows
}
<commit_msg>Way better solution for pascals-triangle<commit_after>pub struct PascalsTriangle {
    row_count: u32,
}

impl PascalsTriangle {
    pub fn new(row_count: u32) -> Self {
        PascalsTriangle { row_count: row_count }
    }

    pub fn rows(&self) -> Vec<Vec<u32>> {
        (0..self.row_count).map(|x| calc_row(x)).collect()
    }
}

fn calc_row(n: u32) -> Vec<u32> {
    let mut next_row: Vec<u32> = Vec::with_capacity(n as usize + 1);
    (1..n + 2).fold(1, |acc, x| {
        next_row.push(acc);
        acc * (n + 1 - x) / x
    });
    next_row
}
<|endoftext|>


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

use dom::audiodestinationnode::AudioDestinationNode;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation};
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::BaseAudioContextMethods;
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::AudioContextState;
use dom::bindings::codegen::Bindings::OscillatorNodeBinding::OscillatorOptions;
use dom::bindings::inheritance::Castable;
use dom::bindings::num::Finite;
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{DomObject, Reflector};
use dom::bindings::root::DomRoot;
use dom::globalscope::GlobalScope;
use dom::oscillatornode::OscillatorNode;
use dom::promise::Promise;
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::ServoMedia;
use servo_media::audio::graph::AudioGraph;
use servo_media::audio::graph::{OfflineAudioGraphOptions, RealTimeAudioGraphOptions};
use servo_media::audio::graph_impl::NodeId;
use servo_media::audio::node::AudioNodeType;
use std::cell::Cell;
use std::rc::Rc;
use task_source::TaskSource;

pub enum BaseAudioContextOptions {
    AudioContext(RealTimeAudioGraphOptions),
    OfflineAudioContext(OfflineAudioGraphOptions),
}

#[dom_struct]
pub struct BaseAudioContext {
    reflector_: Reflector,
    #[ignore_malloc_size_of = "servo_media"]
    audio_graph: AudioGraph,
    /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination
    destination: Option<DomRoot<AudioDestinationNode>>,
    /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-samplerate
    sample_rate: f32,
    /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-currenttime
    current_time: f64,
    /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-state
    state: Cell<AudioContextState>,
    /// https://webaudio.github.io/web-audio-api/#pendingresumepromises
    #[ignore_malloc_size_of = "promises are hard"]
    pending_resume_promises: DomRefCell<Vec<Rc<Promise>>>,
}

impl BaseAudioContext {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(
        global: &GlobalScope,
        options: BaseAudioContextOptions,
        ) -> BaseAudioContext {
        let options = match options {
            BaseAudioContextOptions::AudioContext(options) => options,
            BaseAudioContextOptions::OfflineAudioContext(_) => unimplemented!(),
        };

        let sample_rate = options.sample_rate;

        let mut context = BaseAudioContext {
            reflector_: Reflector::new(),
            audio_graph: ServoMedia::get().unwrap().create_audio_graph(Some(options.into())),
            destination: None,
            current_time: 0.,
            sample_rate,
            state: Cell::new(AudioContextState::Suspended),
            pending_resume_promises: Default::default(),
        };

        let mut options = unsafe { AudioNodeOptions::empty(global.get_cx()) };
        options.channelCount = Some(2);
        options.channelCountMode = Some(ChannelCountMode::Explicit);
        options.channelInterpretation = Some(ChannelInterpretation::Speakers);

        context.destination = Some(AudioDestinationNode::new(global, &context, &options));

        context
    }

    pub fn create_node_engine(&self, node_type: AudioNodeType) -> NodeId {
        self.audio_graph.create_node(node_type)
    }

    // https://webaudio.github.io/web-audio-api/#allowed-to-start
    pub fn is_allowed_to_start(&self) -> bool {
        self.state.get() == AudioContextState::Suspended
    }

    pub fn resume(&self) {
        let window = DomRoot::downcast::<Window>(self.global()).unwrap();
        let task_source = window.dom_manipulation_task_source();

        // Set the state attribute to `running`.
        let this = Trusted::new(self);
        task_source.queue(task!(set_state: move || {
            let this = this.root();
            this.state.set(AudioContextState::Running);
        }), window.upcast()).unwrap();

        // Queue a task to fire a simple event named `statechange` at the AudioContext.
        task_source.queue_simple_event(
            self.upcast(),
            atom!("statechange"),
            &window,
            );
    }
}

impl BaseAudioContextMethods for BaseAudioContext {
    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-currenttime
    fn CurrentTime(&self) -> Finite<f64> {
        Finite::wrap(self.current_time)
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-state
    fn State(&self) -> AudioContextState {
        self.state.get()
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-resume
    #[allow(unrooted_must_root)]
    fn Resume(&self) -> Rc<Promise> {
        // TODO
        Promise::new(&self.global())
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination
    fn Destination(&self) -> DomRoot<AudioDestinationNode> {
        DomRoot::from_ref(self.destination.as_ref().unwrap())
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
    event_handler!(statechange, GetOnstatechange, SetOnstatechange);

    #[allow(unsafe_code)]
    fn CreateOscillator(&self) -> DomRoot<OscillatorNode> {
        let global = self.global();
        let window = global.as_window();
        let options = unsafe { OscillatorOptions::empty(window.get_cx()) };
        OscillatorNode::new(&window, &self, &options)
    }
}
<commit_msg>Get audio context current time from audio graph<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audiodestinationnode::AudioDestinationNode;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation};
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::BaseAudioContextMethods;
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::AudioContextState;
use dom::bindings::codegen::Bindings::OscillatorNodeBinding::OscillatorOptions;
use dom::bindings::inheritance::Castable;
use dom::bindings::num::Finite;
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{DomObject, Reflector};
use dom::bindings::root::DomRoot;
use dom::globalscope::GlobalScope;
use dom::oscillatornode::OscillatorNode;
use dom::promise::Promise;
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::ServoMedia;
use servo_media::audio::graph::AudioGraph;
use servo_media::audio::graph::{OfflineAudioGraphOptions, RealTimeAudioGraphOptions};
use servo_media::audio::graph_impl::NodeId;
use servo_media::audio::node::AudioNodeType;
use std::cell::Cell;
use std::rc::Rc;
use task_source::TaskSource;

pub enum BaseAudioContextOptions {
    AudioContext(RealTimeAudioGraphOptions),
    OfflineAudioContext(OfflineAudioGraphOptions),
}

#[dom_struct]
pub struct BaseAudioContext {
    reflector_: Reflector,
    #[ignore_malloc_size_of = "servo_media"]
    audio_graph: AudioGraph,
    /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination
    destination: Option<DomRoot<AudioDestinationNode>>,
    /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-samplerate
    sample_rate: f32,
    /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-state
    state: Cell<AudioContextState>,
    /// https://webaudio.github.io/web-audio-api/#pendingresumepromises
    #[ignore_malloc_size_of = "promises are hard"]
    pending_resume_promises: DomRefCell<Vec<Rc<Promise>>>,
}

impl BaseAudioContext {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(
        global: &GlobalScope,
        options: BaseAudioContextOptions,
        ) -> BaseAudioContext {
        let options = match options {
            BaseAudioContextOptions::AudioContext(options) => options,
            BaseAudioContextOptions::OfflineAudioContext(_) => unimplemented!(),
        };

        let sample_rate = options.sample_rate;

        let mut context = BaseAudioContext {
            reflector_: Reflector::new(),
            audio_graph: ServoMedia::get().unwrap().create_audio_graph(Some(options.into())),
            destination: None,
            sample_rate,
            state: Cell::new(AudioContextState::Suspended),
            pending_resume_promises: Default::default(),
        };

        let mut options = unsafe { AudioNodeOptions::empty(global.get_cx()) };
        options.channelCount = Some(2);
        options.channelCountMode = Some(ChannelCountMode::Explicit);
        options.channelInterpretation = Some(ChannelInterpretation::Speakers);

        context.destination = Some(AudioDestinationNode::new(global, &context, &options));

        context
    }

    pub fn create_node_engine(&self, node_type: AudioNodeType) -> NodeId {
        self.audio_graph.create_node(node_type)
    }

    // https://webaudio.github.io/web-audio-api/#allowed-to-start
    pub fn is_allowed_to_start(&self) -> bool {
        self.state.get() == AudioContextState::Suspended
    }

    pub fn resume(&self) {
        let window = DomRoot::downcast::<Window>(self.global()).unwrap();
        let task_source = window.dom_manipulation_task_source();

        // Set the state attribute to `running`.
        let this = Trusted::new(self);
        task_source.queue(task!(set_state: move || {
            let this = this.root();
            this.state.set(AudioContextState::Running);
        }), window.upcast()).unwrap();

        // Queue a task to fire a simple event named `statechange` at the AudioContext.
        task_source.queue_simple_event(
            self.upcast(),
            atom!("statechange"),
            &window,
            );
    }
}

impl BaseAudioContextMethods for BaseAudioContext {
    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-currenttime
    fn CurrentTime(&self) -> Finite<f64> {
        let current_time = self.audio_graph.current_time();
        Finite::wrap(current_time)
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-state
    fn State(&self) -> AudioContextState {
        self.state.get()
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-resume
    #[allow(unrooted_must_root)]
    fn Resume(&self) -> Rc<Promise> {
        // TODO
        Promise::new(&self.global())
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination
    fn Destination(&self) -> DomRoot<AudioDestinationNode> {
        DomRoot::from_ref(self.destination.as_ref().unwrap())
    }

    // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
    event_handler!(statechange, GetOnstatechange, SetOnstatechange);

    #[allow(unsafe_code)]
    fn CreateOscillator(&self) -> DomRoot<OscillatorNode> {
        let global = self.global();
        let window = global.as_window();
        let options = unsafe { OscillatorOptions::empty(window.get_cx()) };
        OscillatorNode::new(&window, &self, &options)
    }
}
<|endoftext|>