<commit_before>use core::mem;

use crate::syscall::IntRegisters;

use super::super::flags::*;

#[derive(Default)]
#[repr(packed)]
pub struct ScratchRegisters {
    pub r11: usize,
    pub r10: usize,
    pub r9: usize,
    pub r8: usize,
    pub rsi: usize,
    pub rdi: usize,
    pub rdx: usize,
    pub rcx: usize,
    pub rax: usize,
}

impl ScratchRegisters {
    pub fn dump(&self) {
        println!("RAX:   {:>016X}", { self.rax });
        println!("RCX:   {:>016X}", { self.rcx });
        println!("RDX:   {:>016X}", { self.rdx });
        println!("RDI:   {:>016X}", { self.rdi });
        println!("RSI:   {:>016X}", { self.rsi });
        println!("R8:    {:>016X}", { self.r8 });
        println!("R9:    {:>016X}", { self.r9 });
        println!("R10:   {:>016X}", { self.r10 });
        println!("R11:   {:>016X}", { self.r11 });
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct PreservedRegisters {
    pub r15: usize,
    pub r14: usize,
    pub r13: usize,
    pub r12: usize,
    pub rbp: usize,
    pub rbx: usize,
}

impl PreservedRegisters {
    pub fn dump(&self) {
        println!("RBX:   {:>016X}", { self.rbx });
        println!("RBP:   {:>016X}", { self.rbp });
        println!("R12:   {:>016X}", { self.r12 });
        println!("R13:   {:>016X}", { self.r13 });
        println!("R14:   {:>016X}", { self.r14 });
        println!("R15:   {:>016X}", { self.r15 });
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct IretRegisters {
    pub rip: usize,
    pub cs: usize,
    pub rflags: usize,

    // ----
    // The following will only be present if interrupt is raised from another
    // privilege ring. Otherwise, they are undefined values.
    // ----

    pub rsp: usize,
    pub ss: usize
}

impl IretRegisters {
    pub fn dump(&self) {
        println!("RFLAG: {:>016X}", { self.rflags });
        println!("CS:    {:>016X}", { self.cs });
        println!("RIP:   {:>016X}", { self.rip });

        if self.cs & 0b11 != 0b00 {
            println!("RSP:   {:>016X}", { self.rsp });
            println!("SS:    {:>016X}", { self.ss });
        }
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct InterruptStack {
    pub preserved: PreservedRegisters,
    pub scratch: ScratchRegisters,
    pub iret: IretRegisters,
}

impl InterruptStack {
    pub fn dump(&self) {
        self.iret.dump();
        self.scratch.dump();
        self.preserved.dump();
    }
    /// Saves all registers to a struct used by the proc:
    /// scheme to read/write registers.
    pub fn save(&self, all: &mut IntRegisters) {
        all.r15 = self.preserved.r15;
        all.r14 = self.preserved.r14;
        all.r13 = self.preserved.r13;
        all.r12 = self.preserved.r12;
        all.rbp = self.preserved.rbp;
        all.rbx = self.preserved.rbx;
        all.r11 = self.scratch.r11;
        all.r10 = self.scratch.r10;
        all.r9 = self.scratch.r9;
        all.r8 = self.scratch.r8;
        all.rsi = self.scratch.rsi;
        all.rdi = self.scratch.rdi;
        all.rdx = self.scratch.rdx;
        all.rcx = self.scratch.rcx;
        all.rax = self.scratch.rax;
        all.rip = self.iret.rip;
        all.cs = self.iret.cs;
        all.rflags = self.iret.rflags;

        // Set rsp and ss:

        const CPL_MASK: usize = 0b11;

        let cs: usize;
        unsafe {
            asm!("mov {}, cs", out(reg) cs);
        }

        if self.iret.cs & CPL_MASK == cs & CPL_MASK {
            // Privilege ring didn't change, so neither did the stack
            all.rsp = self as *const Self as usize // rsp after Self was pushed to the stack
                + mem::size_of::<Self>() // disregard Self
                - mem::size_of::<usize>() * 2; // well, almost: rsp and ss need to be excluded as they aren't present
            unsafe {
                asm!("mov {}, ss", out(reg) all.ss);
            }
        } else {
            all.rsp = self.iret.rsp;
            all.ss = self.iret.ss;
        }
    }
    /// Loads all registers from a struct used by the proc:
    /// scheme to read/write registers.
    pub fn load(&mut self, all: &IntRegisters) {
        // TODO: Which of these should be allowed to change?

        // self.fs = all.fs;
        self.preserved.r15 = all.r15;
        self.preserved.r14 = all.r14;
        self.preserved.r13 = all.r13;
        self.preserved.r12 = all.r12;
        self.preserved.rbp = all.rbp;
        self.preserved.rbx = all.rbx;
        self.scratch.r11 = all.r11;
        self.scratch.r10 = all.r10;
        self.scratch.r9 = all.r9;
        self.scratch.r8 = all.r8;
        self.scratch.rsi = all.rsi;
        self.scratch.rdi = all.rdi;
        self.scratch.rdx = all.rdx;
        self.scratch.rcx = all.rcx;
        self.scratch.rax = all.rax;
        self.iret.rip = all.rip;

        // These should probably be restricted
        // self.iret.cs = all.cs;
        // self.iret.rflags = all.eflags;
    }
    /// Enables the "Trap Flag" in the FLAGS register, causing the CPU
    /// to send a Debug exception after the next instruction. This is
    /// used for singlestep in the proc: scheme.
    pub fn set_singlestep(&mut self, enabled: bool) {
        if enabled {
            self.iret.rflags |= FLAG_SINGLESTEP;
        } else {
            self.iret.rflags &= !FLAG_SINGLESTEP;
        }
    }
    /// Checks if the trap flag is enabled, see `set_singlestep`
    pub fn is_singlestep(&self) -> bool {
        self.iret.rflags & FLAG_SINGLESTEP == FLAG_SINGLESTEP
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct InterruptErrorStack {
    pub code: usize,
    pub inner: InterruptStack,
}

impl InterruptErrorStack {
    pub fn dump(&self) {
        println!("CODE:  {:>016X}", { self.code });
        self.inner.dump();
    }
}

#[macro_export]
macro_rules! intel_asm {
    ($($strings:expr,)+) => {
        global_asm!(concat!(
            ".intel_syntax noprefix\n",
            $($strings),+,
            ".att_syntax prefix\n",
        ));
    };
}
#[macro_export]
macro_rules! function {
    ($name:ident => { $($body:expr,)+ }) => {
        intel_asm!(
            ".global ", stringify!($name), "\n",
            ".type ", stringify!($name), ", @function\n",
            ".section .text.", stringify!($name), ", \"ax\", @progbits\n",
            // Align the function to a 16-byte boundary, padding with multi-byte NOPs.
            ".p2align 4,,15\n",
            stringify!($name), ":\n",
            $($body),+,
            ".size ", stringify!($name), ", . - ", stringify!($name), "\n",
            ".text\n",
        );
        extern "C" {
            pub fn $name();
        }
    };
}

#[macro_export]
macro_rules! push_scratch {
    () => { "
        // Push scratch registers
        push rcx
        push rdx
        push rdi
        push rsi
        push r8
        push r9
        push r10
        push r11
    " };
}
#[macro_export]
macro_rules! pop_scratch {
    () => { "
        // Pop scratch registers
        pop r11
        pop r10
        pop r9
        pop r8
        pop rsi
        pop rdi
        pop rdx
        pop rcx
        pop rax
    " };
}

#[macro_export]
macro_rules! push_preserved {
    () => { "
        // Push preserved registers
        push rbx
        push rbp
        push r12
        push r13
        push r14
        push r15
    " };
}
#[macro_export]
macro_rules! pop_preserved {
    () => { "
        // Pop preserved registers
        pop r15
        pop r14
        pop r13
        pop r12
        pop rbp
        pop rbx
    " };
}
macro_rules! swapgs_iff_ring3_fast {
    () => { "
        // Check whether the last two bits RSP+8 (code segment) are equal to zero.
        test QWORD PTR [rsp + 8], 0x3
        // Skip the SWAPGS instruction if CS & 0b11 == 0b00.
        jz 1f
        swapgs
        1:
    " };
}
macro_rules! swapgs_iff_ring3_fast_errorcode {
    () => { "
        test QWORD PTR [rsp + 16], 0x3
        jz 1f
        swapgs
        1:
    " };
}
#[macro_export]
macro_rules! swapgs_iff_ring3_slow {
    () => { "
    push rax
    push rdx
    push rcx
    mov ecx, 0xC0000102
    rdmsr
    shl rdx, 32
    or eax, edx
    test rdx, rdx
    jnz 1f
    swapgs
    1:
    pop rcx
    pop rdx
    pop rax
    " }
}

#[macro_export]
macro_rules! interrupt_stack {
    // XXX: Apparently we cannot use $expr and check for bool exhaustiveness, so we will have to
    // use idents directly instead.
    ($name:ident, super_atomic: $is_super_atomic:ident!, |$stack:ident| $code:block) => {
        paste::item! {
            #[no_mangle]
            unsafe extern "C" fn [<__interrupt_ $name>]($stack: &mut $crate::arch::x86_64::interrupt::InterruptStack) {
                let _guard = $crate::ptrace::set_process_regs($stack);

                // TODO: Force the declarations to specify unsafe?

                #[allow(unused_unsafe)]
                unsafe {
                    $code
                }
            }

            function!($name => {
                // Backup all userspace registers to stack
                $is_super_atomic!(),
                "push rax\n",
                push_scratch!(),
                push_preserved!(),

                // TODO: Map PTI
                // $crate::arch::x86_64::pti::map();

                // Call inner function with pointer to stack
                "mov rdi, rsp\n",
                "call __interrupt_", stringify!($name), "\n",

                // TODO: Unmap PTI
                // $crate::arch::x86_64::pti::unmap();

                // Restore all userspace registers
                pop_preserved!(),
                pop_scratch!(),

                $is_super_atomic!(),
                "iretq\n",
            });
        }
    };
    ($name:ident, |$stack:ident| $code:block) => { interrupt_stack!($name, super_atomic: swapgs_iff_ring3_fast!, |$stack| $code); };
}

#[macro_export]
macro_rules! interrupt {
    ($name:ident, || $code:block) => {
        paste::item! {
            #[no_mangle]
            unsafe extern "C" fn [<__interrupt_ $name>]() {
                $code
            }

            function!($name => {
                // Backup all userspace registers to stack
                swapgs_iff_ring3_fast!(),
                "push rax\n",
                push_scratch!(),

                // TODO: Map PTI
                // $crate::arch::x86_64::pti::map();

                // Call inner function with pointer to stack
                "call __interrupt_", stringify!($name), "\n",

                // TODO: Unmap PTI
                // $crate::arch::x86_64::pti::unmap();

                // Restore all userspace registers
                pop_scratch!(),

                swapgs_iff_ring3_fast!(),
                "iretq\n",
            });
        }
    };
}

#[macro_export]
macro_rules! interrupt_error {
    ($name:ident, |$stack:ident| $code:block) => {
        paste::item! {
            #[no_mangle]
            unsafe extern "C" fn [<__interrupt_ $name>]($stack: &mut $crate::arch::x86_64::interrupt::handler::InterruptErrorStack) {
                let _guard = $crate::ptrace::set_process_regs(&mut $stack.inner);

                #[allow(unused_unsafe)]
                unsafe {
                    $code
                }
            }

            function!($name => {
                swapgs_iff_ring3_fast_errorcode!(),
                // Move rax into code's place, put code in last instead (to be
                // compatible with InterruptStack)
                "xchg [rsp], rax\n",

                // Push all userspace registers
                push_scratch!(),
                push_preserved!(),

                // Put code in, it's now in rax
                "push rax\n",

                // TODO: Map PTI
                // $crate::arch::x86_64::pti::map();

                // Call inner function with pointer to stack
                "mov rdi, rsp\n",
                "call __interrupt_", stringify!($name), "\n",

                // TODO: Unmap PTI
                // $crate::arch::x86_64::pti::unmap();

                // Pop code
                "add rsp, 8\n",

                // Restore all userspace registers
                pop_preserved!(),
                pop_scratch!(),

                swapgs_iff_ring3_fast_errorcode!(),
                "iretq\n",
            });
        }
    };
}
<commit_msg>Remove explicit .intel_syntax directive.<commit_after>use core::mem;

use crate::syscall::IntRegisters;

use super::super::flags::*;

#[derive(Default)]
#[repr(packed)]
pub struct ScratchRegisters {
    pub r11: usize,
    pub r10: usize,
    pub r9: usize,
    pub r8: usize,
    pub rsi: usize,
    pub rdi: usize,
    pub rdx: usize,
    pub rcx: usize,
    pub rax: usize,
}

impl ScratchRegisters {
    pub fn dump(&self) {
        println!("RAX:   {:>016X}", { self.rax });
        println!("RCX:   {:>016X}", { self.rcx });
        println!("RDX:   {:>016X}", { self.rdx });
        println!("RDI:   {:>016X}", { self.rdi });
        println!("RSI:   {:>016X}", { self.rsi });
        println!("R8:    {:>016X}", { self.r8 });
        println!("R9:    {:>016X}", { self.r9 });
        println!("R10:   {:>016X}", { self.r10 });
        println!("R11:   {:>016X}", { self.r11 });
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct PreservedRegisters {
    pub r15: usize,
    pub r14: usize,
    pub r13: usize,
    pub r12: usize,
    pub rbp: usize,
    pub rbx: usize,
}

impl PreservedRegisters {
    pub fn dump(&self) {
        println!("RBX:   {:>016X}", { self.rbx });
        println!("RBP:   {:>016X}", { self.rbp });
        println!("R12:   {:>016X}", { self.r12 });
        println!("R13:   {:>016X}", { self.r13 });
        println!("R14:   {:>016X}", { self.r14 });
        println!("R15:   {:>016X}", { self.r15 });
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct IretRegisters {
    pub rip: usize,
    pub cs: usize,
    pub rflags: usize,

    // ----
    // The following will only be present if interrupt is raised from another
    // privilege ring. Otherwise, they are undefined values.
    // ----

    pub rsp: usize,
    pub ss: usize
}

impl IretRegisters {
    pub fn dump(&self) {
        println!("RFLAG: {:>016X}", { self.rflags });
        println!("CS:    {:>016X}", { self.cs });
        println!("RIP:   {:>016X}", { self.rip });

        if self.cs & 0b11 != 0b00 {
            println!("RSP:   {:>016X}", { self.rsp });
            println!("SS:    {:>016X}", { self.ss });
        }
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct InterruptStack {
    pub preserved: PreservedRegisters,
    pub scratch: ScratchRegisters,
    pub iret: IretRegisters,
}

impl InterruptStack {
    pub fn dump(&self) {
        self.iret.dump();
        self.scratch.dump();
        self.preserved.dump();
    }
    /// Saves all registers to a struct used by the proc:
    /// scheme to read/write registers.
    pub fn save(&self, all: &mut IntRegisters) {
        all.r15 = self.preserved.r15;
        all.r14 = self.preserved.r14;
        all.r13 = self.preserved.r13;
        all.r12 = self.preserved.r12;
        all.rbp = self.preserved.rbp;
        all.rbx = self.preserved.rbx;
        all.r11 = self.scratch.r11;
        all.r10 = self.scratch.r10;
        all.r9 = self.scratch.r9;
        all.r8 = self.scratch.r8;
        all.rsi = self.scratch.rsi;
        all.rdi = self.scratch.rdi;
        all.rdx = self.scratch.rdx;
        all.rcx = self.scratch.rcx;
        all.rax = self.scratch.rax;
        all.rip = self.iret.rip;
        all.cs = self.iret.cs;
        all.rflags = self.iret.rflags;

        // Set rsp and ss:

        const CPL_MASK: usize = 0b11;

        let cs: usize;
        unsafe {
            asm!("mov {}, cs", out(reg) cs);
        }

        if self.iret.cs & CPL_MASK == cs & CPL_MASK {
            // Privilege ring didn't change, so neither did the stack
            all.rsp = self as *const Self as usize // rsp after Self was pushed to the stack
                + mem::size_of::<Self>() // disregard Self
                - mem::size_of::<usize>() * 2; // well, almost: rsp and ss need to be excluded as they aren't present
            unsafe {
                asm!("mov {}, ss", out(reg) all.ss);
            }
        } else {
            all.rsp = self.iret.rsp;
            all.ss = self.iret.ss;
        }
    }
    /// Loads all registers from a struct used by the proc:
    /// scheme to read/write registers.
    pub fn load(&mut self, all: &IntRegisters) {
        // TODO: Which of these should be allowed to change?

        // self.fs = all.fs;
        self.preserved.r15 = all.r15;
        self.preserved.r14 = all.r14;
        self.preserved.r13 = all.r13;
        self.preserved.r12 = all.r12;
        self.preserved.rbp = all.rbp;
        self.preserved.rbx = all.rbx;
        self.scratch.r11 = all.r11;
        self.scratch.r10 = all.r10;
        self.scratch.r9 = all.r9;
        self.scratch.r8 = all.r8;
        self.scratch.rsi = all.rsi;
        self.scratch.rdi = all.rdi;
        self.scratch.rdx = all.rdx;
        self.scratch.rcx = all.rcx;
        self.scratch.rax = all.rax;
        self.iret.rip = all.rip;

        // These should probably be restricted
        // self.iret.cs = all.cs;
        // self.iret.rflags = all.eflags;
    }
    /// Enables the "Trap Flag" in the FLAGS register, causing the CPU
    /// to send a Debug exception after the next instruction. This is
    /// used for singlestep in the proc: scheme.
    pub fn set_singlestep(&mut self, enabled: bool) {
        if enabled {
            self.iret.rflags |= FLAG_SINGLESTEP;
        } else {
            self.iret.rflags &= !FLAG_SINGLESTEP;
        }
    }
    /// Checks if the trap flag is enabled, see `set_singlestep`
    pub fn is_singlestep(&self) -> bool {
        self.iret.rflags & FLAG_SINGLESTEP == FLAG_SINGLESTEP
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct InterruptErrorStack {
    pub code: usize,
    pub inner: InterruptStack,
}

impl InterruptErrorStack {
    pub fn dump(&self) {
        println!("CODE:  {:>016X}", { self.code });
        self.inner.dump();
    }
}

#[macro_export]
macro_rules! intel_asm {
    ($($strings:expr,)+) => {
        global_asm!(concat!(
            $($strings),+,
        ));
    };
}
#[macro_export]
macro_rules! function {
    ($name:ident => { $($body:expr,)+ }) => {
        intel_asm!(
            ".global ", stringify!($name), "\n",
            ".type ", stringify!($name), ", @function\n",
            ".section .text.", stringify!($name), ", \"ax\", @progbits\n",
            // Align the function to a 16-byte boundary, padding with multi-byte NOPs.
            ".p2align 4,,15\n",
            stringify!($name), ":\n",
            $($body),+,
            ".size ", stringify!($name), ", . - ", stringify!($name), "\n",
            ".text\n",
        );
        extern "C" {
            pub fn $name();
        }
    };
}

#[macro_export]
macro_rules! push_scratch {
    () => { "
        // Push scratch registers
        push rcx
        push rdx
        push rdi
        push rsi
        push r8
        push r9
        push r10
        push r11
    " };
}
#[macro_export]
macro_rules! pop_scratch {
    () => { "
        // Pop scratch registers
        pop r11
        pop r10
        pop r9
        pop r8
        pop rsi
        pop rdi
        pop rdx
        pop rcx
        pop rax
    " };
}

#[macro_export]
macro_rules! push_preserved {
    () => { "
        // Push preserved registers
        push rbx
        push rbp
        push r12
        push r13
        push r14
        push r15
    " };
}
#[macro_export]
macro_rules! pop_preserved {
    () => { "
        // Pop preserved registers
        pop r15
        pop r14
        pop r13
        pop r12
        pop rbp
        pop rbx
    " };
}
macro_rules! swapgs_iff_ring3_fast {
    () => { "
        // Check whether the last two bits RSP+8 (code segment) are equal to zero.
        test QWORD PTR [rsp + 8], 0x3
        // Skip the SWAPGS instruction if CS & 0b11 == 0b00.
        jz 1f
        swapgs
        1:
    " };
}
macro_rules! swapgs_iff_ring3_fast_errorcode {
    () => { "
        test QWORD PTR [rsp + 16], 0x3
        jz 1f
        swapgs
        1:
    " };
}
#[macro_export]
macro_rules! swapgs_iff_ring3_slow {
    () => { "
    push rax
    push rdx
    push rcx
    mov ecx, 0xC0000102
    rdmsr
    shl rdx, 32
    or eax, edx
    test rdx, rdx
    jnz 1f
    swapgs
    1:
    pop rcx
    pop rdx
    pop rax
    " }
}

#[macro_export]
macro_rules! interrupt_stack {
    // XXX: Apparently we cannot use $expr and check for bool exhaustiveness, so we will have to
    // use idents directly instead.
    ($name:ident, super_atomic: $is_super_atomic:ident!, |$stack:ident| $code:block) => {
        paste::item! {
            #[no_mangle]
            unsafe extern "C" fn [<__interrupt_ $name>]($stack: &mut $crate::arch::x86_64::interrupt::InterruptStack) {
                let _guard = $crate::ptrace::set_process_regs($stack);

                // TODO: Force the declarations to specify unsafe?

                #[allow(unused_unsafe)]
                unsafe {
                    $code
                }
            }

            function!($name => {
                // Backup all userspace registers to stack
                $is_super_atomic!(),
                "push rax\n",
                push_scratch!(),
                push_preserved!(),

                // TODO: Map PTI
                // $crate::arch::x86_64::pti::map();

                // Call inner function with pointer to stack
                "mov rdi, rsp\n",
                "call __interrupt_", stringify!($name), "\n",

                // TODO: Unmap PTI
                // $crate::arch::x86_64::pti::unmap();

                // Restore all userspace registers
                pop_preserved!(),
                pop_scratch!(),

                $is_super_atomic!(),
                "iretq\n",
            });
        }
    };
    ($name:ident, |$stack:ident| $code:block) => { interrupt_stack!($name, super_atomic: swapgs_iff_ring3_fast!, |$stack| $code); };
}

#[macro_export]
macro_rules! interrupt {
    ($name:ident, || $code:block) => {
        paste::item! {
            #[no_mangle]
            unsafe extern "C" fn [<__interrupt_ $name>]() {
                $code
            }

            function!($name => {
                // Backup all userspace registers to stack
                swapgs_iff_ring3_fast!(),
                "push rax\n",
                push_scratch!(),

                // TODO: Map PTI
                // $crate::arch::x86_64::pti::map();

                // Call inner function with pointer to stack
                "call __interrupt_", stringify!($name), "\n",

                // TODO: Unmap PTI
                // $crate::arch::x86_64::pti::unmap();

                // Restore all userspace registers
                pop_scratch!(),

                swapgs_iff_ring3_fast!(),
                "iretq\n",
            });
        }
    };
}

#[macro_export]
macro_rules! interrupt_error {
    ($name:ident, |$stack:ident| $code:block) => {
        paste::item! {
            #[no_mangle]
            unsafe extern "C" fn [<__interrupt_ $name>]($stack: &mut $crate::arch::x86_64::interrupt::handler::InterruptErrorStack) {
                let _guard = $crate::ptrace::set_process_regs(&mut $stack.inner);

                #[allow(unused_unsafe)]
                unsafe {
                    $code
                }
            }

            function!($name => {
                swapgs_iff_ring3_fast_errorcode!(),
                // Move rax into code's place, put code in last instead (to be
                // compatible with InterruptStack)
                "xchg [rsp], rax\n",

                // Push all userspace registers
                push_scratch!(),
                push_preserved!(),

                // Put code in, it's now in rax
                "push rax\n",

                // TODO: Map PTI
                // $crate::arch::x86_64::pti::map();

                // Call inner function with pointer to stack
                "mov rdi, rsp\n",
                "call __interrupt_", stringify!($name), "\n",

                // TODO: Unmap PTI
                // $crate::arch::x86_64::pti::unmap();

                // Pop code
                "add rsp, 8\n",

                // Restore all userspace registers
                pop_preserved!(),
                pop_scratch!(),

                swapgs_iff_ring3_fast_errorcode!(),
                "iretq\n",
            });
        }
    };
}
<|endoftext|>


<commit_before>use memory::VAddr;
use memory::paging::{Page, VirtualPage};

/// Something which may be flushed from the TLB
pub trait Flush {
    /// Invalidate this object in the TLB using the `invlpg` instruction.
    ///
    /// # Unsafe Because
    /// + Causes a general protection fault if not executed in kernel mode.
    unsafe fn invlpg(&self);

    /// Invalidate this object in the TLB instruction if we are in kernel mode.
    ///
    /// # Returns
    /// + True if the object was flushed
    /// + False if it was not flushed.
    #[inline]
    fn flush(&self) -> bool {
        use arch::cpu::PrivilegeLevel;

        if PrivilegeLevel::current_iopl() != PrivilegeLevel::KernelMode {
            false // can't flush, we are not in kernel mode
        } else {
            // this is safe since we know we are in kernel mode
            unsafe { self.invlpg() };
            true
        }
    }
}

impl Flush for VAddr {
    #[inline]
    unsafe fn invlpg(&self) {
         asm!( "invlpg [$0]"
             :
             : "r" (*self)
             : "memory"
             : "intel", "volatile" );
    }
}

impl Flush for VirtualPage {
    #[inline]
    unsafe fn invlpg(&self) {
        self.base().invlpg()
    }
}
<commit_msg>[x86_64] add tab::flush_all()<commit_after>use memory::VAddr;
use memory::paging::{Page, VirtualPage};

/// Invalidate the TLB completely by reloading the CR3 register.
///
/// # Unsafe Because
/// + Causes a general protection fault if not executed in kernel mode.
pub unsafe fn flush_all() {
    use arch::cpu::control_regs::cr3;
    cr3::write(cr3::read());
}

/// Something which may be flushed from the TLB
pub trait Flush {
    /// Invalidate this object in the TLB using the `invlpg` instruction.
    ///
    /// # Unsafe Because
    /// + Causes a general protection fault if not executed in kernel mode.
    unsafe fn invlpg(&self);

    /// Invalidate this object in the TLB instruction if we are in kernel mode.
    ///
    /// # Returns
    /// + True if the object was flushed
    /// + False if it was not flushed.
    #[inline]
    fn flush(&self) -> bool {
        use arch::cpu::PrivilegeLevel;

        if PrivilegeLevel::current_iopl() != PrivilegeLevel::KernelMode {
            false // can't flush, we are not in kernel mode
        } else {
            // this is safe since we know we are in kernel mode
            unsafe { self.invlpg() };
            true
        }
    }
}

impl Flush for VAddr {
    #[inline]
    unsafe fn invlpg(&self) {
         asm!( "invlpg [$0]"
             :
             : "r" (*self)
             : "memory"
             : "intel", "volatile" );
    }
}

impl Flush for VirtualPage {
    #[inline]
    unsafe fn invlpg(&self) {
        self.base().invlpg()
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{BufRead, BufReader};
use std::net::IpAddr;
use std::os::unix::io::AsRawFd;

use blake2::{self, Digest};
use failure::{Error, ResultExt};
use ipnetwork::IpNetwork;
use nix::sched::{setns, CLONE_NEWNET};
use nix::unistd::{getpid};
use serde_json::to_vec;
use unshare;

use lithos::sandbox_config::{SandboxConfig, BridgedNetwork};
use lithos::child_config::ChildConfig;
use lithos::container_config::InstantiatedConfig;

pub fn setup(sandbox: &SandboxConfig, child: &ChildConfig,
    container: &InstantiatedConfig)
    -> Result<(), String>
{
    _setup(sandbox, child, container)
    .map_err(|e| e.to_string())
}

fn interface_name(network: &BridgedNetwork, ip: &IpAddr) -> String {
    #[derive(Serialize)]
    struct HashSource<'a> {
        bridge: &'a str,
        ip: &'a IpAddr,
    }
    let (ip1, ip2) = match *ip {
        IpAddr::V4(ip) => (ip.octets()[2], ip.octets()[3]),
        IpAddr::V6(ip) => (ip.octets()[14], ip.octets()[15]),
    };
    let name = format!("li_{:06x}_{:02x}{:02x}",
        blake2::Blake2b::digest(&to_vec(&HashSource {
            bridge: &network.bridge,
            ip: ip,
        }).expect("can always serialize")),
        ip1, ip2);
    assert!(name.len() <= 15);
    return name;
}

fn get_real_parent_pid() -> Result<u32, Error> {
    let f = BufReader::new(File::open("/proc/self/status")
        .context("can open /proc/self/status")?);
    for line in f.lines() {
        let line = line.context("can open /proc/self/status")?;
        if line.starts_with("PPid:") {
            let ppid = line[5..].trim().parse::<u32>()
                .context("can parse pid in /proc/sef/status")?;
            return Ok(ppid);
        }
    }
    bail!("can't find ppid");
}

fn _setup(sandbox: &SandboxConfig, child: &ChildConfig,
    _container: &InstantiatedConfig)
    -> Result<(), Error>
{
    let net = sandbox.bridged_network.as_ref().expect("bridged network");
    let ip = child.ip_addresses.get(0).expect("ip address");
    let ppid = get_real_parent_pid()?;
    let my_ns = File::open("/proc/self/ns/net")
        .context("can't open namespace")?;
    let parent_ns = File::open(&format!("/proc/{}/ns/net", ppid))
        .context("can't open parent namespace")?;
    setns(parent_ns.as_raw_fd(), CLONE_NEWNET)?;
    let interface = interface_name(net, ip);
    let iinterface = interface.replace("_", "-");
    assert!(iinterface != interface);

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("link").arg("add");
    cmd.arg(&interface);
    cmd.arg("type").arg("veth");
    cmd.arg("peer").arg("name").arg(&iinterface);
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("link").arg("set");
    cmd.arg("dev").arg(&iinterface);
    // Note: this is a bit of hack bit it's known to work.
    // 1. We opened our namespace first so `/proc/<PID>/ns/net` is associated
    //    with that namespace even if we change namespace
    // 2. Then we set namespace to a parent one
    // 3. We move interface to ours namespace
    // 4. Then switch our namespace back to expected one
    cmd.arg("netns").arg(&format!("{}", getpid()));
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    let mut cmd = unshare::Command::new("brctl");
    cmd.arg("addif").arg(&net.bridge).arg(&interface);
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("brctl failed: {}", s),
        Err(e) => bail!("brctl failed: {}", e),
    }

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("link").arg("set");
    cmd.arg(&interface);
    cmd.arg("up");
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    setns(my_ns.as_raw_fd(), CLONE_NEWNET)?;

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("addr").arg("add");
    cmd.arg(&format!("{}",
        IpNetwork::new(*ip, net.network.prefix())
        .expect("network asways valid")));
    cmd.arg("dev").arg(&iinterface);
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("link").arg("set");
    cmd.arg(&iinterface);
    cmd.arg("up");
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    if let Some(gw) = net.default_gateway {
        let mut cmd = unshare::Command::new("ip");
        cmd.arg("route").arg("add");
        cmd.arg("default");
        cmd.arg("via").arg(&format!("{}", gw));
        match cmd.status() {
            Ok(s) if s.success() => {}
            Ok(s) => bail!("ip route failed: {}", s),
            Err(e) => bail!("ip route failed: {}", e),
        }
    }
    Ok(())
}
<commit_msg>Fix interface name generator<commit_after>use std::fs::File;
use std::io::{BufRead, BufReader};
use std::net::IpAddr;
use std::os::unix::io::AsRawFd;

use blake2::{self, Digest};
use failure::{Error, ResultExt};
use ipnetwork::IpNetwork;
use nix::sched::{setns, CLONE_NEWNET};
use nix::unistd::{getpid};
use serde_json::to_vec;
use unshare;

use lithos::sandbox_config::{SandboxConfig, BridgedNetwork};
use lithos::child_config::ChildConfig;
use lithos::container_config::InstantiatedConfig;

pub fn setup(sandbox: &SandboxConfig, child: &ChildConfig,
    container: &InstantiatedConfig)
    -> Result<(), String>
{
    _setup(sandbox, child, container)
    .map_err(|e| e.to_string())
}

fn interface_name(network: &BridgedNetwork, ip: &IpAddr) -> String {
    #[derive(Serialize)]
    struct HashSource<'a> {
        bridge: &'a str,
        ip: &'a IpAddr,
    }
    let (ip1, ip2) = match *ip {
        IpAddr::V4(ip) => (ip.octets()[2], ip.octets()[3]),
        IpAddr::V6(ip) => (ip.octets()[14], ip.octets()[15]),
    };
    let name = format!("li_{:.06x}_{:02x}{:02x}",
        blake2::Blake2b::digest(&to_vec(&HashSource {
            bridge: &network.bridge,
            ip: ip,
        }).expect("can always serialize")),
        ip1, ip2);
    assert!(name.len() <= 15);
    return name;
}

fn get_real_parent_pid() -> Result<u32, Error> {
    let f = BufReader::new(File::open("/proc/self/status")
        .context("can open /proc/self/status")?);
    for line in f.lines() {
        let line = line.context("can open /proc/self/status")?;
        if line.starts_with("PPid:") {
            let ppid = line[5..].trim().parse::<u32>()
                .context("can parse pid in /proc/sef/status")?;
            return Ok(ppid);
        }
    }
    bail!("can't find ppid");
}

fn _setup(sandbox: &SandboxConfig, child: &ChildConfig,
    _container: &InstantiatedConfig)
    -> Result<(), Error>
{
    let net = sandbox.bridged_network.as_ref().expect("bridged network");
    let ip = child.ip_addresses.get(0).expect("ip address");
    let ppid = get_real_parent_pid()?;
    let my_ns = File::open("/proc/self/ns/net")
        .context("can't open namespace")?;
    let parent_ns = File::open(&format!("/proc/{}/ns/net", ppid))
        .context("can't open parent namespace")?;
    setns(parent_ns.as_raw_fd(), CLONE_NEWNET)?;
    let interface = interface_name(net, ip);
    let iinterface = interface.replace("_", "-");
    assert!(iinterface != interface);

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("link").arg("add");
    cmd.arg(&interface);
    cmd.arg("type").arg("veth");
    cmd.arg("peer").arg("name").arg(&iinterface);
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("link").arg("set");
    cmd.arg("dev").arg(&iinterface);
    // Note: this is a bit of hack bit it's known to work.
    // 1. We opened our namespace first so `/proc/<PID>/ns/net` is associated
    //    with that namespace even if we change namespace
    // 2. Then we set namespace to a parent one
    // 3. We move interface to ours namespace
    // 4. Then switch our namespace back to expected one
    cmd.arg("netns").arg(&format!("{}", getpid()));
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    let mut cmd = unshare::Command::new("brctl");
    cmd.arg("addif").arg(&net.bridge).arg(&interface);
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("brctl failed: {}", s),
        Err(e) => bail!("brctl failed: {}", e),
    }

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("link").arg("set");
    cmd.arg(&interface);
    cmd.arg("up");
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    setns(my_ns.as_raw_fd(), CLONE_NEWNET)?;

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("addr").arg("add");
    cmd.arg(&format!("{}",
        IpNetwork::new(*ip, net.network.prefix())
        .expect("network asways valid")));
    cmd.arg("dev").arg(&iinterface);
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    let mut cmd = unshare::Command::new("ip");
    cmd.arg("link").arg("set");
    cmd.arg(&iinterface);
    cmd.arg("up");
    match cmd.status() {
        Ok(s) if s.success() => {}
        Ok(s) => bail!("ip link failed: {}", s),
        Err(e) => bail!("ip link failed: {}", e),
    }

    if let Some(gw) = net.default_gateway {
        let mut cmd = unshare::Command::new("ip");
        cmd.arg("route").arg("add");
        cmd.arg("default");
        cmd.arg("via").arg(&format!("{}", gw));
        match cmd.status() {
            Ok(s) if s.success() => {}
            Ok(s) => bail!("ip route failed: {}", s),
            Err(e) => bail!("ip route failed: {}", e),
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers

// Copyright (c) 2013-2014 The Rust Project Developers
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in
//   the documentation and/or other materials provided with the
//   distribution.
//
// - Neither the name of "The Computer Language Benchmarks Game" nor
//   the name of "The Computer Language Shootout Benchmarks" nor the
//   names of its contributors may be used to endorse or promote
//   products derived from this software without specific prior
//   written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

extern crate num;

use std::str::FromStr;
use std::io;

use num::traits::{FromPrimitive, ToPrimitive};
use num::{BigInt, Integer, One, Zero};

struct Context {
    numer: BigInt,
    accum: BigInt,
    denom: BigInt,
}

impl Context {
    fn new() -> Context {
        Context {
            numer: One::one(),
            accum: Zero::zero(),
            denom: One::one(),
        }
    }

    fn from_i32(i: i32) -> BigInt {
        FromPrimitive::from_i32(i).unwrap()
    }

    fn extract_digit(&self) -> i32 {
        if self.numer > self.accum {return -1;}
        let (q, r) =
            (&self.numer * Context::from_i32(3) + &self.accum)
            .div_rem(&self.denom);
        if r + &self.numer >= self.denom {return -1;}
        q.to_i32().unwrap()
    }

    fn next_term(&mut self, k: i32) {
        let y2 = Context::from_i32(k * 2 + 1);
        self.accum = (&self.accum + (&self.numer << 1)) * &y2;
        self.numer = &self.numer * Context::from_i32(k);
        self.denom = &self.denom * y2;
    }

    fn eliminate_digit(&mut self, d: i32) {
        let d = Context::from_i32(d);
        let ten = Context::from_i32(10);
        self.accum = (&self.accum - &self.denom * d) * &ten;
        self.numer = &self.numer * ten;
    }
}

fn pidigits(n: isize, out: &mut io::Write) -> io::Result<()> {
    let mut k = 0;
    let mut context = Context::new();

    for i in (1..(n+1)) {
        let mut d;
        loop {
            k += 1;
            context.next_term(k);
            d = context.extract_digit();
            if d != -1 {break;}
        }

        try!(write!(out, "{}", d));
        if i % 10 == 0 { try!(write!(out, "\t:{}\n", i)); }

        context.eliminate_digit(d);
    }

    let m = n % 10;
    if m != 0 {
        for _ in (m..10) { try!(write!(out, " ")); }
        try!(write!(out, "\t:{}\n", n));
    }
    Ok(())
}

const DEFAULT_DIGITS: isize = 512;

fn main() {
    let args = std::env::args().collect::<Vec<_>>();
    let n = if args.len() < 2 {
        DEFAULT_DIGITS
    } else if args[1] == "--bench" {
        return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap()
    } else {
        FromStr::from_str(&args[1]).unwrap()
    };
    pidigits(n, &mut std::io::stdout()).unwrap();
}
<commit_msg>fix some annoying build warnings<commit_after>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers

// Copyright (c) 2013-2014 The Rust Project Developers
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in
//   the documentation and/or other materials provided with the
//   distribution.
//
// - Neither the name of "The Computer Language Benchmarks Game" nor
//   the name of "The Computer Language Shootout Benchmarks" nor the
//   names of its contributors may be used to endorse or promote
//   products derived from this software without specific prior
//   written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

extern crate num;

use std::str::FromStr;
use std::io;

use num::traits::{FromPrimitive, ToPrimitive};
use num::{BigInt, Integer, One, Zero};

struct Context {
    numer: BigInt,
    accum: BigInt,
    denom: BigInt,
}

impl Context {
    fn new() -> Context {
        Context {
            numer: One::one(),
            accum: Zero::zero(),
            denom: One::one(),
        }
    }

    fn from_i32(i: i32) -> BigInt {
        FromPrimitive::from_i32(i).unwrap()
    }

    fn extract_digit(&self) -> i32 {
        if self.numer > self.accum {return -1;}
        let (q, r) =
            (&self.numer * Context::from_i32(3) + &self.accum)
            .div_rem(&self.denom);
        if r + &self.numer >= self.denom {return -1;}
        q.to_i32().unwrap()
    }

    fn next_term(&mut self, k: i32) {
        let y2 = Context::from_i32(k * 2 + 1);
        self.accum = (&self.accum + (&self.numer << 1)) * &y2;
        self.numer = &self.numer * Context::from_i32(k);
        self.denom = &self.denom * y2;
    }

    fn eliminate_digit(&mut self, d: i32) {
        let d = Context::from_i32(d);
        let ten = Context::from_i32(10);
        self.accum = (&self.accum - &self.denom * d) * &ten;
        self.numer = &self.numer * ten;
    }
}

fn pidigits(n: isize, out: &mut io::Write) -> io::Result<()> {
    let mut k = 0;
    let mut context = Context::new();

    for i in 1..(n+1) {
        let mut d;
        loop {
            k += 1;
            context.next_term(k);
            d = context.extract_digit();
            if d != -1 {break;}
        }

        try!(write!(out, "{}", d));
        if i % 10 == 0 { try!(write!(out, "\t:{}\n", i)); }

        context.eliminate_digit(d);
    }

    let m = n % 10;
    if m != 0 {
        for _ in m..10 { try!(write!(out, " ")); }
        try!(write!(out, "\t:{}\n", n));
    }
    Ok(())
}

const DEFAULT_DIGITS: isize = 512;

fn main() {
    let args = std::env::args().collect::<Vec<_>>();
    let n = if args.len() < 2 {
        DEFAULT_DIGITS
    } else if args[1] == "--bench" {
        return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap()
    } else {
        FromStr::from_str(&args[1]).unwrap()
    };
    pidigits(n, &mut std::io::stdout()).unwrap();
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate cc;

use bindgen::callbacks::{MacroParsingBehavior, ParseCallbacks};
use bindgen::Builder;
use std::collections::HashSet;
use std::env;
use std::path::PathBuf;
use std::sync::{Arc, Mutex, RwLock};

#[derive(Debug)]
struct MacroCallback {
    macros: Arc<RwLock<HashSet<String>>>,
    seen_hellos: Mutex<u32>,
}

impl ParseCallbacks for MacroCallback {
    fn will_parse_macro(&self, name: &str) -> MacroParsingBehavior {
        self.macros.write().unwrap().insert(name.into());

        if name == "MY_ANNOYING_MACRO" {
            return MacroParsingBehavior::Ignore;
        }

        MacroParsingBehavior::Default
    }

    fn item_name(&self, original_item_name: &str) -> Option<String> {
        if original_item_name.starts_with("my_prefixed_") {
            Some(
                original_item_name
                    .trim_start_matches("my_prefixed_")
                    .to_string(),
            )
        } else if original_item_name.starts_with("MY_PREFIXED_") {
            Some(
                original_item_name
                    .trim_start_matches("MY_PREFIXED_")
                    .to_string(),
            )
        } else {
            None
        }
    }

    fn str_macro(&self, name: &str, value: &[u8]) {
        match &name {
            &"TESTMACRO_STRING_EXPANDED"
            | &"TESTMACRO_STRING"
            | &"TESTMACRO_INTEGER" => {
                // The integer test macro is, actually, not expected to show up here at all -- but
                // should produce an error if it does.
                assert_eq!(
                    value, b"Hello Preprocessor!",
                    "str_macro handle received unexpected value"
                );
                *self.seen_hellos.lock().unwrap() += 1;
            }
            _ => {}
        }
    }
}

impl Drop for MacroCallback {
    fn drop(&mut self) {
        assert_eq!(
            *self.seen_hellos.lock().unwrap(),
            2,
            "str_macro handle was not called once for all relevant macros"
        )
    }
}

fn main() {
    cc::Build::new()
        .cpp(true)
        .file("cpp/Test.cc")
        .compile("libtest.a");

    let macros = Arc::new(RwLock::new(HashSet::new()));

    let bindings = Builder::default()
        .rustfmt_bindings(false)
        .enable_cxx_namespaces()
        .rustified_enum(".*")
        .raw_line("pub use self::root::*;")
        .raw_line("extern { fn my_prefixed_function_to_remove(i: i32); }")
        .module_raw_line("root::testing", "pub type Bar = i32;")
        .header("cpp/Test.h")
        .clang_args(&["-x", "c++", "-std=c++11"])
        .parse_callbacks(Box::new(MacroCallback {
            macros: macros.clone(),
            seen_hellos: Mutex::new(0),
        }))
        .blacklist_function("my_prefixed_function_to_remove")
        .generate()
        .expect("Unable to generate bindings");

    assert!(macros.read().unwrap().contains("TESTMACRO"));

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("test.rs"))
        .expect("Couldn't write bindings!");
}
<commit_msg>bindgen-integration: Reformat crate too.<commit_after>extern crate bindgen;
extern crate cc;

use bindgen::callbacks::{MacroParsingBehavior, ParseCallbacks};
use bindgen::Builder;
use std::collections::HashSet;
use std::env;
use std::path::PathBuf;
use std::sync::{Arc, Mutex, RwLock};

#[derive(Debug)]
struct MacroCallback {
    macros: Arc<RwLock<HashSet<String>>>,
    seen_hellos: Mutex<u32>,
}

impl ParseCallbacks for MacroCallback {
    fn will_parse_macro(&self, name: &str) -> MacroParsingBehavior {
        self.macros.write().unwrap().insert(name.into());

        if name == "MY_ANNOYING_MACRO" {
            return MacroParsingBehavior::Ignore;
        }

        MacroParsingBehavior::Default
    }

    fn item_name(&self, original_item_name: &str) -> Option<String> {
        if original_item_name.starts_with("my_prefixed_") {
            Some(
                original_item_name
                    .trim_start_matches("my_prefixed_")
                    .to_string(),
            )
        } else if original_item_name.starts_with("MY_PREFIXED_") {
            Some(
                original_item_name
                    .trim_start_matches("MY_PREFIXED_")
                    .to_string(),
            )
        } else {
            None
        }
    }

    fn str_macro(&self, name: &str, value: &[u8]) {
        match name {
            "TESTMACRO_STRING_EXPANDED" |
            "TESTMACRO_STRING" |
            "TESTMACRO_INTEGER" => {
                // The integer test macro is, actually, not expected to show up here at all -- but
                // should produce an error if it does.
                assert_eq!(
                    value, b"Hello Preprocessor!",
                    "str_macro handle received unexpected value"
                );
                *self.seen_hellos.lock().unwrap() += 1;
            }
            _ => {}
        }
    }
}

impl Drop for MacroCallback {
    fn drop(&mut self) {
        assert_eq!(
            *self.seen_hellos.lock().unwrap(),
            2,
            "str_macro handle was not called once for all relevant macros"
        )
    }
}

fn main() {
    cc::Build::new()
        .cpp(true)
        .file("cpp/Test.cc")
        .compile("libtest.a");

    let macros = Arc::new(RwLock::new(HashSet::new()));

    let bindings = Builder::default()
        .rustfmt_bindings(false)
        .enable_cxx_namespaces()
        .rustified_enum(".*")
        .raw_line("pub use self::root::*;")
        .raw_line("extern { fn my_prefixed_function_to_remove(i: i32); }")
        .module_raw_line("root::testing", "pub type Bar = i32;")
        .header("cpp/Test.h")
        .clang_args(&["-x", "c++", "-std=c++11"])
        .parse_callbacks(Box::new(MacroCallback {
            macros: macros.clone(),
            seen_hellos: Mutex::new(0),
        }))
        .blacklist_function("my_prefixed_function_to_remove")
        .generate()
        .expect("Unable to generate bindings");

    assert!(macros.read().unwrap().contains("TESTMACRO"));

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("test.rs"))
        .expect("Couldn't write bindings!");
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use ast::typed::{Signedness, Size, Type, TypeVar};
use super::rollback_map::Map;

#[derive(Debug, Clone)]
enum VarTarget {
    Type(Type),
    UnsizedInt(Signedness),
    Int,
}

pub struct UnifyTable {
    var_target: Map<TypeVar, VarTarget>,
    next_var: u32,
}

impl UnifyTable {
    pub fn new() -> UnifyTable {
        UnifyTable {
            var_target: Map::new(),
            next_var: 0,
        }
    }

    pub fn fresh_var(&mut self) -> TypeVar {
        let var = TypeVar(self.next_var);
        self.next_var += 1;
        var
    }

    pub fn fresh_int_var(&mut self, sign: Option<Signedness>) -> TypeVar {
        let var = TypeVar(self.next_var);
        match sign {
            Some(sign) => self.var_target.insert(var, VarTarget::UnsizedInt(sign)),
            None => self.var_target.insert(var, VarTarget::Int),
        }
        self.var_target.commit();
        self.next_var += 1;
        var
    }

    pub fn unify(&mut self, a: &Type, b: &Type) -> Result<Type, ()> {
        match self.unify_raw(a, b) {
            Ok(()) => {
                self.commit();
                Ok(a.clone())
            }
            Err(()) => {
                self.rollback();
                Err(())
            }
        }
    }

    fn unify_raw(&mut self, a: &Type, b: &Type) -> Result<(), ()> {
        let a = self.shallow_normalize(a);
        let b = self.shallow_normalize(b);
        match (a, b) {
            (Type::Error, _) | (_, Type::Error) => Ok(()),
            (Type::Concrete(a, ref ap), Type::Concrete(b, ref bp)) => if a == b {
                assert!(ap.len() == bp.len());
                for (a, b) in ap.iter().zip(bp.iter()) {
                    self.unify_raw(a, b)?;
                }
                Ok(())
            } else {
                Err(())
            },
            (Type::Function(ref ap, ref a), Type::Function(ref bp, ref b)) => {
                if ap.len() == bp.len() {
                    for (a, b) in ap.iter().zip(bp.iter()) {
                        self.unify_raw(a, b)?;
                    }
                    self.unify_raw(a, b)
                } else {
                    Err(())
                }
            }
            (Type::Int(sign1, size1), Type::Int(sign2, size2)) => {
                if sign1 == sign2 && size1 == size2 {
                    Ok(())
                } else {
                    Err(())
                }
            }
            (Type::Pointer(ref a), Type::Pointer(ref b)) => self.unify_raw(a, b),
            (Type::Var(a), ty) | (ty, Type::Var(a)) => self.unify_var_type(a, ty),
            (_, _) => Err(()),
        }
    }

    fn unify_var_var(&mut self, a: TypeVar, b: TypeVar) -> Result<(), ()> {
        let at = self.var_target.get(&a).cloned();
        let bt = self.var_target.get(&b).cloned();
        match (at, bt) {
            (Some(VarTarget::Type(_)), _) | (_, Some(VarTarget::Type(_))) => {
                panic!("cannot unify non-normalized var")
            }
            (None, _) | (Some(VarTarget::Int), Some(_)) => {
                self.var_target.insert(a, VarTarget::Type(Type::Var(b)));
                Ok(())
            }
            (_, None) | (Some(_), Some(VarTarget::Int)) => {
                self.var_target.insert(b, VarTarget::Type(Type::Var(a)));
                Ok(())
            }
            (Some(VarTarget::UnsizedInt(s1)), Some(VarTarget::UnsizedInt(s2))) => if s1 == s2 {
                self.var_target.insert(a, VarTarget::Type(Type::Var(b)));
                Ok(())
            } else {
                Err(())
            },
        }
    }

    fn unify_var_type(&mut self, v: TypeVar, b: Type) -> Result<(), ()> {
        let vt = self.var_target.get(&v).cloned();
        match (vt, b) {
            (Some(VarTarget::Type(_)), _) => panic!("cannot unify non-normalized var"),
            (_, Type::Var(b)) => self.unify_var_var(v, b),
            (None, ty) | (Some(VarTarget::Int), ty @ Type::Int(_, _)) => {
                self.var_target.insert(v, VarTarget::Type(ty));
                Ok(())
            }
            (Some(VarTarget::UnsizedInt(sign)), Type::Int(sign2, size)) => if sign == sign2 {
                self.var_target
                    .insert(v, VarTarget::Type(Type::Int(sign2, size)));
                Ok(())
            } else {
                Err(())
            },
            _ => Err(()),
        }
    }

    fn get_var_type(&self, var: TypeVar) -> Type {
        match self.var_target.get(&var) {
            Some(&VarTarget::Type(ref ty)) => self.shallow_normalize(ty),
            Some(&VarTarget::Int) | Some(&VarTarget::UnsizedInt(_)) | None => Type::Var(var),
        }
    }

    pub fn shallow_normalize(&self, a: &Type) -> Type {
        match a {
            &Type::Var(var) => self.get_var_type(var),
            ty => ty.clone(),
        }
    }

    pub fn normalize(&mut self, a: &Type) -> Result<Type, ()> {
        match self.shallow_normalize(a) {
            Type::Bool => Ok(Type::Bool),
            Type::Concrete(sym, ref params) => {
                let mut normalized = Vec::new();
                for param in &**params {
                    normalized.push(self.normalize(param)?);
                }
                Ok(Type::Concrete(sym, normalized.into()))
            }
            Type::Error => Ok(Type::Error),
            Type::Function(ref params, ref out) => {
                let out = self.normalize(out)?;
                let mut normalized = Vec::new();
                for param in &**params {
                    normalized.push(self.normalize(param)?);
                }
                Ok(Type::Function(normalized.into(), Rc::new(out)))
            }
            ty @ Type::Int(_, _) => Ok(ty),
            Type::Pointer(ref ty) => {
                let ty = self.normalize(ty)?;
                Ok(Type::Pointer(Rc::new(ty)))
            }
            Type::Var(var) => {
                match self.var_target.get(&var) {
                    Some(&VarTarget::Type(_)) => panic!("var not normalized"),
                    Some(&VarTarget::Int) => {
                        return Ok(Type::Int(Signedness::Signed, Size::Bit32));
                    }
                    Some(&VarTarget::UnsizedInt(sign)) => {
                        return Ok(Type::Int(sign, Size::Bit32));
                    }
                    None => {
                        // there is no sensible default
                        // fall though because of borrowck
                    }
                }
                // unify this var with an error to prevent further
                // error reports about same variable
                self.var_target.insert(var, VarTarget::Type(Type::Error));
                Err(())
            }
        }
    }

    pub fn describe_var(&self, var: TypeVar) -> &'static str {
        match self.var_target.get(&var) {
            Some(&VarTarget::Int) => "{int}",
            Some(&VarTarget::UnsizedInt(Signedness::Signed)) => "{signed}",
            Some(&VarTarget::UnsizedInt(Signedness::Unsigned)) => "{unsigned}",
            _ => "_",
        }
    }

    fn commit(&mut self) {
        self.var_target.commit();
    }

    fn rollback(&mut self) {
        self.var_target.rollback();
    }
}
<commit_msg>unify bools properly<commit_after>use std::rc::Rc;
use ast::typed::{Signedness, Size, Type, TypeVar};
use super::rollback_map::Map;

#[derive(Debug, Clone)]
enum VarTarget {
    Type(Type),
    UnsizedInt(Signedness),
    Int,
}

pub struct UnifyTable {
    var_target: Map<TypeVar, VarTarget>,
    next_var: u32,
}

impl UnifyTable {
    pub fn new() -> UnifyTable {
        UnifyTable {
            var_target: Map::new(),
            next_var: 0,
        }
    }

    pub fn fresh_var(&mut self) -> TypeVar {
        let var = TypeVar(self.next_var);
        self.next_var += 1;
        var
    }

    pub fn fresh_int_var(&mut self, sign: Option<Signedness>) -> TypeVar {
        let var = TypeVar(self.next_var);
        match sign {
            Some(sign) => self.var_target.insert(var, VarTarget::UnsizedInt(sign)),
            None => self.var_target.insert(var, VarTarget::Int),
        }
        self.var_target.commit();
        self.next_var += 1;
        var
    }

    pub fn unify(&mut self, a: &Type, b: &Type) -> Result<Type, ()> {
        match self.unify_raw(a, b) {
            Ok(()) => {
                self.commit();
                Ok(a.clone())
            }
            Err(()) => {
                self.rollback();
                Err(())
            }
        }
    }

    fn unify_raw(&mut self, a: &Type, b: &Type) -> Result<(), ()> {
        let a = self.shallow_normalize(a);
        let b = self.shallow_normalize(b);
        match (a, b) {
            (Type::Error, _) | (_, Type::Error) => Ok(()),
            (Type::Concrete(a, ref ap), Type::Concrete(b, ref bp)) => if a == b {
                assert!(ap.len() == bp.len());
                for (a, b) in ap.iter().zip(bp.iter()) {
                    self.unify_raw(a, b)?;
                }
                Ok(())
            } else {
                Err(())
            },
            (Type::Function(ref ap, ref a), Type::Function(ref bp, ref b)) => {
                if ap.len() == bp.len() {
                    for (a, b) in ap.iter().zip(bp.iter()) {
                        self.unify_raw(a, b)?;
                    }
                    self.unify_raw(a, b)
                } else {
                    Err(())
                }
            }
            (Type::Int(sign1, size1), Type::Int(sign2, size2)) => {
                if sign1 == sign2 && size1 == size2 {
                    Ok(())
                } else {
                    Err(())
                }
            }
            (Type::Pointer(ref a), Type::Pointer(ref b)) => self.unify_raw(a, b),
            (Type::Var(a), ty) | (ty, Type::Var(a)) => self.unify_var_type(a, ty),
            (Type::Bool, Type::Bool) => Ok(()),
            (_, _) => Err(()),
        }
    }

    fn unify_var_var(&mut self, a: TypeVar, b: TypeVar) -> Result<(), ()> {
        let at = self.var_target.get(&a).cloned();
        let bt = self.var_target.get(&b).cloned();
        match (at, bt) {
            (Some(VarTarget::Type(_)), _) | (_, Some(VarTarget::Type(_))) => {
                panic!("cannot unify non-normalized var")
            }
            (None, _) | (Some(VarTarget::Int), Some(_)) => {
                self.var_target.insert(a, VarTarget::Type(Type::Var(b)));
                Ok(())
            }
            (_, None) | (Some(_), Some(VarTarget::Int)) => {
                self.var_target.insert(b, VarTarget::Type(Type::Var(a)));
                Ok(())
            }
            (Some(VarTarget::UnsizedInt(s1)), Some(VarTarget::UnsizedInt(s2))) => if s1 == s2 {
                self.var_target.insert(a, VarTarget::Type(Type::Var(b)));
                Ok(())
            } else {
                Err(())
            },
        }
    }

    fn unify_var_type(&mut self, v: TypeVar, b: Type) -> Result<(), ()> {
        let vt = self.var_target.get(&v).cloned();
        match (vt, b) {
            (Some(VarTarget::Type(_)), _) => panic!("cannot unify non-normalized var"),
            (_, Type::Var(b)) => self.unify_var_var(v, b),
            (None, ty) | (Some(VarTarget::Int), ty @ Type::Int(_, _)) => {
                self.var_target.insert(v, VarTarget::Type(ty));
                Ok(())
            }
            (Some(VarTarget::UnsizedInt(sign)), Type::Int(sign2, size)) => if sign == sign2 {
                self.var_target
                    .insert(v, VarTarget::Type(Type::Int(sign2, size)));
                Ok(())
            } else {
                Err(())
            },
            _ => Err(()),
        }
    }

    fn get_var_type(&self, var: TypeVar) -> Type {
        match self.var_target.get(&var) {
            Some(&VarTarget::Type(ref ty)) => self.shallow_normalize(ty),
            Some(&VarTarget::Int) | Some(&VarTarget::UnsizedInt(_)) | None => Type::Var(var),
        }
    }

    pub fn shallow_normalize(&self, a: &Type) -> Type {
        match a {
            &Type::Var(var) => self.get_var_type(var),
            ty => ty.clone(),
        }
    }

    pub fn normalize(&mut self, a: &Type) -> Result<Type, ()> {
        match self.shallow_normalize(a) {
            Type::Bool => Ok(Type::Bool),
            Type::Concrete(sym, ref params) => {
                let mut normalized = Vec::new();
                for param in &**params {
                    normalized.push(self.normalize(param)?);
                }
                Ok(Type::Concrete(sym, normalized.into()))
            }
            Type::Error => Ok(Type::Error),
            Type::Function(ref params, ref out) => {
                let out = self.normalize(out)?;
                let mut normalized = Vec::new();
                for param in &**params {
                    normalized.push(self.normalize(param)?);
                }
                Ok(Type::Function(normalized.into(), Rc::new(out)))
            }
            ty @ Type::Int(_, _) => Ok(ty),
            Type::Pointer(ref ty) => {
                let ty = self.normalize(ty)?;
                Ok(Type::Pointer(Rc::new(ty)))
            }
            Type::Var(var) => {
                match self.var_target.get(&var) {
                    Some(&VarTarget::Type(_)) => panic!("var not normalized"),
                    Some(&VarTarget::Int) => {
                        return Ok(Type::Int(Signedness::Signed, Size::Bit32));
                    }
                    Some(&VarTarget::UnsizedInt(sign)) => {
                        return Ok(Type::Int(sign, Size::Bit32));
                    }
                    None => {
                        // there is no sensible default
                        // fall though because of borrowck
                    }
                }
                // unify this var with an error to prevent further
                // error reports about same variable
                self.var_target.insert(var, VarTarget::Type(Type::Error));
                Err(())
            }
        }
    }

    pub fn describe_var(&self, var: TypeVar) -> &'static str {
        match self.var_target.get(&var) {
            Some(&VarTarget::Int) => "{int}",
            Some(&VarTarget::UnsizedInt(Signedness::Signed)) => "{signed}",
            Some(&VarTarget::UnsizedInt(Signedness::Unsigned)) => "{unsigned}",
            _ => "_",
        }
    }

    fn commit(&mut self) {
        self.var_target.commit();
    }

    fn rollback(&mut self) {
        self.var_target.rollback();
    }
}
<|endoftext|>


<commit_before>// This is a comment, and will be ignored by the compiler
// You can test this code by clicking the "Run" button over there ->
// or if prefer to use your keyboard, you can use the "Ctrl + Enter" shortcut

// This code is editable, feel free to hack it!
// You can always return to the original code by clicking the "Reset" button ->

use std::io::prelude::*;
use std::fs::File;
use std::collections::btree_map::BTreeMap;
use std::cmp::Ordering;

// This is the main function
fn main() {

    let mut f = File::open("day4.txt").unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    let lines = s.lines();

    let mut amount:i32 = 0;
    let ascii_iter = (0..26).map(|x| (x + 'a' as u8) as char);
    let ascii_vec = ascii_iter.collect::<Vec<_>>();
    for line in lines {
      let mut is_checksum = false;
      let mut checksum = String::new();
      let mut str_id = String::new();
      let mut to_test = String::new();
      for ch in line.chars() {
        if ch == '[' {
          is_checksum = true;
        } else if ch == '-' || ch == ']' {
          continue;
        } else if ch.is_digit(10) {
          str_id += &format!("{}",ch);
        } else if is_checksum {
          checksum += &format!("{}",ch);
        } else {
          to_test += &format!("{}",ch);
        }
      }
      let mut count = BTreeMap::new();
      for c in to_test.chars() {
          *count.entry(c).or_insert(0) += 1;
      }
      let mut count_vec: Vec<(&char, &u32)> = count.iter().collect();
      count_vec.sort_by(|a, b| if b.1.cmp(a.1) == Ordering::Equal { a.0.cmp(b.0) }else{ b.1.cmp(a.1)});
      let mut checksum_test = String::new();
      for i in 0..5 {
        checksum_test += &format!("{}",count_vec[i].0);
      }

      if checksum_test == checksum {
        let sector_num = str_id.parse().unwrap();

        // update the count for part 1
        amount += sector_num;

        // generate part 2 output
        let mut to_print = String::new();
        for c in to_test.chars() {
          let mut index:i32 = ascii_vec.iter().position(|&r| r == c).unwrap() as i32;
          index += sector_num;
          index = index % 26;
          to_print += &format!("{}",ascii_vec[index as usize]);
        }

        if to_print == "northpoleobjectstorage" {
          println!("North Pole Objects in sector: {}", sector_num);
        }

      }
    }
    println!("The sum of all valid room sectors is: {:?}",amount );

}
<commit_msg>Day 4 comment cleanup<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::collections::btree_map::BTreeMap;
use std::cmp::Ordering;

fn main() {

    let mut f = File::open("day4.txt").unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    let lines = s.lines();

    let mut amount:i32 = 0;
    let ascii_iter = (0..26).map(|x| (x + 'a' as u8) as char);
    let ascii_vec = ascii_iter.collect::<Vec<_>>();
    for line in lines {
      let mut is_checksum = false;
      let mut checksum = String::new();
      let mut str_id = String::new();
      let mut to_test = String::new();
      for ch in line.chars() {
        if ch == '[' {
          is_checksum = true;
        } else if ch == '-' || ch == ']' {
          continue;
        } else if ch.is_digit(10) {
          str_id += &format!("{}",ch);
        } else if is_checksum {
          checksum += &format!("{}",ch);
        } else {
          to_test += &format!("{}",ch);
        }
      }
      let mut count = BTreeMap::new();
      for c in to_test.chars() {
          *count.entry(c).or_insert(0) += 1;
      }
      let mut count_vec: Vec<(&char, &u32)> = count.iter().collect();
      count_vec.sort_by(|a, b| if b.1.cmp(a.1) == Ordering::Equal { a.0.cmp(b.0) }else{ b.1.cmp(a.1)});
      let mut checksum_test = String::new();
      for i in 0..5 {
        checksum_test += &format!("{}",count_vec[i].0);
      }

      if checksum_test == checksum {
        let sector_num = str_id.parse().unwrap();

        // update the count for part 1
        amount += sector_num;

        // generate part 2 output
        let mut to_print = String::new();
        for c in to_test.chars() {
          let mut index:i32 = ascii_vec.iter().position(|&r| r == c).unwrap() as i32;
          index += sector_num;
          index = index % 26;
          to_print += &format!("{}",ascii_vec[index as usize]);
        }

        if to_print == "northpoleobjectstorage" {
          println!("North Pole Objects in sector: {}", sector_num);
        }

      }
    }
    println!("The sum of all valid room sectors is: {:?}",amount );

}
<|endoftext|>


<commit_before>use std::fs;
use std::collections::HashMap;
use std::path::{Path, PathBuf};

use url::Url;
use sourcemap;

use CliResult;

fn join_url(base_url: &str, url: &str) -> CliResult<String> {
    Ok(Url::parse(base_url)?.join(url)?.to_string())
}

#[derive(PartialEq)]
enum SourceType {
    Script,
    SourceMap,
}

#[derive(PartialEq, Debug)]
enum LogLevel {
    Info,
    Warning,
    Error,
}

impl LogLevel {
    fn is_insignificant(&self) -> bool {
        *self == LogLevel::Info
    }
}

struct Source {
    url: String,
    file_path: PathBuf,
    ty: SourceType,
}

pub struct SourceMapValidator {
    sources: HashMap<String, Source>,
    verbose: bool,
}

struct Log {
    pub failed: bool,
    last_source: Option<String>,
    verbose: bool,
}

impl Log {
    pub fn new(verbose: bool) -> Log {
        Log {
            failed: false,
            last_source: None,
            verbose: verbose,
        }
    }

    pub fn log(&mut self, source: &Source, level: LogLevel, message: String) {
        if self.last_source.as_ref() != Some(&source.url) {
            self.last_source = Some(source.url.clone());
            println!("  {}", source.url);
        }
        if level.is_insignificant() && !self.verbose {
            return;
        }
        println!("    {:?}: {}", level, &message);
        if level == LogLevel::Error {
            self.failed = true;
        }
    }

    pub fn error(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Error, message);
    }

    pub fn warn(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Warning, message);
    }

    pub fn info(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Info, message);
    }
}

impl SourceMapValidator {
    pub fn new(verbose: bool) -> SourceMapValidator {
        SourceMapValidator {
            sources: HashMap::new(),
            verbose: verbose,
        }
    }

    pub fn consider_file(&mut self, path: &Path, url: &str) -> bool {
        let ty = match path.extension().and_then(|x| x.to_str()) {
            Some("js") => SourceType::Script,
            Some("map") => SourceType::SourceMap,
            _ => { return false; }
        };
        self.sources.insert(url.to_owned(), Source {
            url: url.to_owned(),
            file_path: path.to_path_buf(),
            ty: ty,
        });
        true
    }

    fn validate_script(&self, log: &mut Log, source: &Source) -> CliResult<()> {
        let f = fs::File::open(&source.file_path)?;
        let reference = sourcemap::locate_sourcemap_reference(&f)?;
        if let sourcemap::SourceMapRef::LegacyRef(_) = reference {
            log.warn(source, "encountered a legacy reference".into());
        }
        if let Some(url) = reference.get_url() {
            let full_url = join_url(&source.url, url)?;
            log.info(source, format!("sourcemap at {}", full_url));
        } else if source.url.ends_with(".min.js") {
            log.error(source, "missing sourcemap!".into());
        } else {
            log.warn(source, "no sourcemap reference".into());
        }
        Ok(())
    }

    fn validate_sourcemap(&self, log: &mut Log, source: &Source) -> CliResult<()> {
        let f = fs::File::open(&source.file_path)?;
        match sourcemap::decode(&f)? {
            sourcemap::DecodedMap::Regular(sm) => {
                for idx in 0..sm.get_source_count() {
                    let source_url = sm.get_source(idx).unwrap_or("??");
                    if sm.get_source_contents(idx).is_some() ||
                       self.sources.get(source_url).is_some() {
                        log.info(source, format!("found source ({})", source_url));
                    } else {
                        log.warn(source, format!("missing sourcecode ({})", source_url));
                    }
                }
            },
            sourcemap::DecodedMap::Index(_) => {
                log.warn(source, "encountered indexed sourcemap. We
                         cannot validate those.".into());
            }
        }
        Ok(())
    }

    pub fn validate_sources(&self) -> CliResult<()> {
        let mut log = Log::new(self.verbose);
        let mut sources : Vec<_> = self.sources.iter().map(|x| x.1).collect();
        sources.sort_by_key(|x| &x.url);

        for source in sources.iter() {
            if source.ty == SourceType::Script {
                if let Err(err) = self.validate_script(&mut log, &source) {
                    log.error(&source, format!("failed to process: {}", err));
                }
            } else if source.ty == SourceType::SourceMap {
                if let Err(err) = self.validate_sourcemap(&mut log, &source) {
                    log.error(&source, format!("failed to process: {}", err));
                }
            }
        }
        if log.failed {
            fail!("Encountered problems when validating sourcemaps.");
        }
        println!("All Good!");
        Ok(())
    }
}
<commit_msg>If to match<commit_after>use std::fs;
use std::collections::HashMap;
use std::path::{Path, PathBuf};

use url::Url;
use sourcemap;

use CliResult;

fn join_url(base_url: &str, url: &str) -> CliResult<String> {
    Ok(Url::parse(base_url)?.join(url)?.to_string())
}

#[derive(PartialEq)]
enum SourceType {
    Script,
    SourceMap,
}

#[derive(PartialEq, Debug)]
enum LogLevel {
    Info,
    Warning,
    Error,
}

impl LogLevel {
    fn is_insignificant(&self) -> bool {
        *self == LogLevel::Info
    }
}

struct Source {
    url: String,
    file_path: PathBuf,
    ty: SourceType,
}

pub struct SourceMapValidator {
    sources: HashMap<String, Source>,
    verbose: bool,
}

struct Log {
    pub failed: bool,
    last_source: Option<String>,
    verbose: bool,
}

impl Log {
    pub fn new(verbose: bool) -> Log {
        Log {
            failed: false,
            last_source: None,
            verbose: verbose,
        }
    }

    pub fn log(&mut self, source: &Source, level: LogLevel, message: String) {
        if self.last_source.as_ref() != Some(&source.url) {
            self.last_source = Some(source.url.clone());
            println!("  {}", source.url);
        }
        if level.is_insignificant() && !self.verbose {
            return;
        }
        println!("    {:?}: {}", level, &message);
        if level == LogLevel::Error {
            self.failed = true;
        }
    }

    pub fn error(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Error, message);
    }

    pub fn warn(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Warning, message);
    }

    pub fn info(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Info, message);
    }
}

impl SourceMapValidator {
    pub fn new(verbose: bool) -> SourceMapValidator {
        SourceMapValidator {
            sources: HashMap::new(),
            verbose: verbose,
        }
    }

    pub fn consider_file(&mut self, path: &Path, url: &str) -> bool {
        let ty = match path.extension().and_then(|x| x.to_str()) {
            Some("js") => SourceType::Script,
            Some("map") => SourceType::SourceMap,
            _ => { return false; }
        };
        self.sources.insert(url.to_owned(), Source {
            url: url.to_owned(),
            file_path: path.to_path_buf(),
            ty: ty,
        });
        true
    }

    fn validate_script(&self, log: &mut Log, source: &Source) -> CliResult<()> {
        let f = fs::File::open(&source.file_path)?;
        let reference = sourcemap::locate_sourcemap_reference(&f)?;
        if let sourcemap::SourceMapRef::LegacyRef(_) = reference {
            log.warn(source, "encountered a legacy reference".into());
        }
        if let Some(url) = reference.get_url() {
            let full_url = join_url(&source.url, url)?;
            log.info(source, format!("sourcemap at {}", full_url));
        } else if source.url.ends_with(".min.js") {
            log.error(source, "missing sourcemap!".into());
        } else {
            log.warn(source, "no sourcemap reference".into());
        }
        Ok(())
    }

    fn validate_sourcemap(&self, log: &mut Log, source: &Source) -> CliResult<()> {
        let f = fs::File::open(&source.file_path)?;
        match sourcemap::decode(&f)? {
            sourcemap::DecodedMap::Regular(sm) => {
                for idx in 0..sm.get_source_count() {
                    let source_url = sm.get_source(idx).unwrap_or("??");
                    if sm.get_source_contents(idx).is_some() ||
                       self.sources.get(source_url).is_some() {
                        log.info(source, format!("found source ({})", source_url));
                    } else {
                        log.warn(source, format!("missing sourcecode ({})", source_url));
                    }
                }
            },
            sourcemap::DecodedMap::Index(_) => {
                log.warn(source, "encountered indexed sourcemap. We
                         cannot validate those.".into());
            }
        }
        Ok(())
    }

    pub fn validate_sources(&self) -> CliResult<()> {
        let mut log = Log::new(self.verbose);
        let mut sources : Vec<_> = self.sources.iter().map(|x| x.1).collect();
        sources.sort_by_key(|x| &x.url);

        for source in sources.iter() {
            match source.ty {
                SourceType::Script => {
                    if let Err(err) = self.validate_script(&mut log, &source) {
                        log.error(&source, format!("failed to process: {}", err));
                    }
                },
                SourceType::SourceMap => {
                    if let Err(err) = self.validate_sourcemap(&mut log, &source) {
                        log.error(&source, format!("failed to process: {}", err));
                    }
                }
            }
        }
        if log.failed {
            fail!("Encountered problems when validating sourcemaps.");
        }
        println!("All Good!");
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate dummy_lsp;

use dummy_lsp::*;
use std::env;
use std::io;
use std::io::Write;
use std::rc::Rc;

fn main() {
	let ls = Rc::new(DummyLanguageServer{ });

	if env::args().len() == 1  {
		// Use stdin/stdout

		let stdin = std::io::stdin();
		let out_provider = move || std::io::stdout();
		rust_lsp::lsp_server::LSPServer::start_new(ls, &mut stdin.lock(), out_provider);
	} else {
		let mut args = env::args();
		args.next();
		let port = args.next().unwrap();
		tcp_server(port);
	}

}

use std::net::TcpListener;
use std::net::TcpStream;
use std::thread;

fn tcp_server(port_str: String) {
	let port : u16 = port_str.parse::<u16>().expect(&format!("Invalid port number: {}", port_str));
	let listener = TcpListener::bind(("127.0.0.1", port)).unwrap();
	println!("listening on port: {}", port);

	for stream in listener.incoming() {
		match stream {
			Ok(stream) => {
				thread::spawn(move|| {
					handle_client(stream)
				});
			}
			Err(err) => {
				writeln!(&mut io::stderr(), "TCP listen error : {:?}", err).expect("Failed writing to stderr");
			}
		}
	}

	drop(listener);
}

fn handle_client(stream: TcpStream) {
	//FIXME use same server for each connection
	let ls = Rc::new(DummyLanguageServer{ });

	let mut input = io::BufReader::new(stream.try_clone().expect("Failed to clone stream"));

	rust_lsp::lsp_server::LSPServer::start_new(ls, &mut input, || {
		stream
	});
}
<commit_msg>workaround for CDT-GDB bug.<commit_after>extern crate dummy_lsp;

use dummy_lsp::*;
use std::env;
use std::io;
use std::io::Write;
use std::rc::Rc;

fn main() {
	let ls = Rc::new(DummyLanguageServer{ });

	if env::args().len() == 1  {
		// Use stdin/stdout

		let stdin = std::io::stdin();
		let out_provider = move || std::io::stdout();
		rust_lsp::lsp_server::LSPServer::start_new(ls, &mut stdin.lock(), out_provider);
	} else {
		let mut args = env::args();
		args.next();
		let port = args.next().unwrap();
		tcp_server(port);
	}

}

use std::net::TcpListener;
use std::net::TcpStream;
use std::thread;

fn tcp_server(mut port_str: String) {
	println!("starting server on port: {}", port_str);

	// Workaround for a CDT-GDB bug on Windows that adds single quotes to params
	if port_str.starts_with("'") && port_str.ends_with("'"){
		port_str = port_str[1..port_str.len()-1].to_string();
	}

	let port : u16 = port_str.parse::<u16>().expect(&format!("Invalid port number: {}", port_str));
	let listener = TcpListener::bind(("127.0.0.1", port)).unwrap();

	for stream in listener.incoming() {
		match stream {
			Ok(stream) => {
				thread::spawn(move|| {
					handle_client(stream)
				});
			}
			Err(err) => {
				writeln!(&mut io::stderr(), "TCP listen error : {:?}", err).expect("Failed writing to stderr");
			}
		}
	}

	drop(listener);
}

fn handle_client(stream: TcpStream) {
	//FIXME use same server for each connection
	let ls = Rc::new(DummyLanguageServer{ });

	let mut input = io::BufReader::new(stream.try_clone().expect("Failed to clone stream"));

	rust_lsp::lsp_server::LSPServer::start_new(ls, &mut input, || {
		stream
	});
}
<|endoftext|>