<commit_before>#![allow(ctypes)]
#![no_std]
#![no_main]
#![feature(globs)]
#![feature(asm)]
// Adding pub mod (another fix for this warning) increases footprint, so just
// disble it instead.
#![allow(visible_private_types)]

extern crate core;

use core::prelude::*;
use core::mem::*;

use aspace::AddressSpace;
use con::write;
use dlist::DList;
use process::Process;
use start32::MultiBootInfo;
//use start32::OrigMultiBootInfo;
use start32::PhysAddr;
use start32::MutPhysAddr;
use util::abort;
use x86::idt;
pub use x86::idt::irq_entry;
pub use syscall::syscall;

mod aspace;
#[allow(dead_code)]
mod con;
mod dict;
mod dlist;
mod mboot;
mod mem;
mod process;
mod start32;
mod syscall;
pub mod util;
mod x86;

static log_assoc_procs : bool = false;
static log_page_fault : bool = false;
static log_switch : bool = false;
static mem_test : bool = false;

#[allow(dead_code)]
fn writeMBInfo(infop : *mboot::Info) {
    con::write("Multiboot info at ");
    con::writePtr(infop);
    con::putc('\n');

    let &info = unsafe { &*infop };
    con::write("Flags: ");
    con::writeHex(info.flags as uint);
    con::newline();

    if info.has(mboot::MemorySize) {
        con::writeUInt(info.mem_lower as uint);
        con::write("kB lower memory, ");
        con::writeUInt(info.mem_upper as uint);
        con::write("kB upper memory, ");
        con::writeUInt(((info.mem_lower + info.mem_upper + 1023) / 1024) as uint);
        con::write("MB total.\n");
    }
    if info.has(mboot::CommandLine) {
        let cmdline : *u8 = PhysAddr(info.cmdline as uint);
        con::write("Command line @");
        con::writePtr(cmdline);
        con::write(" (");
        con::writeHex(info.cmdline as uint);
        con::write(") \"");
        con::writeCStr(cmdline);
        con::write("\"\n");
    }
}

pub fn generic_irq_handler(p : &mut Process, vec : u8) {
    write("IRQ! vec=");
    con::writeUInt(vec as uint);
    con::newline();
    cpu().queue(p);
}

pub fn page_fault(p : &mut Process, error : uint) -> ! {
    mod pf_errors {
        #![allow(dead_code)]
        // Error code flags.
        pub static PRESENT : uint = 1;
        pub static WRITE : uint = 2;
        pub static USER : uint = 4;
        pub static RSVD : uint = 8;
        pub static INSTR : uint = 16;
    }

    if log_page_fault {
        write("page fault ");
        con::writeHex(error);
        write(" cr2=");
        con::writePHex(x86::cr2());
        write(" rip=");
        con::writePHex(p.regs.rip as uint);
        write(" in process ");
        con::writeMutPtr(p);
        con::newline();
    }

    if (error & pf_errors::USER) == 0 {
        abort("kernel page fault\n");
    }

    let back = p.aspace().find_add_backing(x86::cr2() & !0xfff);
    // FIXME should return e.g. Option<> so we can detect failures better than
    // just aborting.
    p.aspace().add_pte(back.vaddr(), back.pte());

    cpu().queue(p);
    unsafe { cpu().run(); }
}

pub fn handler_NM() {
    abort("NM");
}

pub fn idle() -> ! {
    loop {
        write("idle\n");
        unsafe { asm!("swapgs; sti; hlt; cli; swapgs" :::: "volatile"); } }
}

pub struct PerCpu {
    selfp : *mut PerCpu,
    stack : *mut u8,
    process : Option<&'static mut Process>,
    //

    // End of assembly-fixed fields.
    memory : mem::PerCpu,
    runqueue : DList<Process>,
}

impl PerCpu {
    unsafe fn new() -> *mut PerCpu {
        let mut mem = mem::PerCpu::new();
        let p : *mut PerCpu = mem.alloc_frame_panic();
        let stack : *mut u8 = mem.alloc_frame_panic();
        *p = PerCpu {
            selfp : p,
            stack : stack,
            memory : mem,
            runqueue : DList::empty(),
            process : None
        };
        return p
    }

    unsafe fn start(&mut self) {
        setup_msrs(self.selfp as uint);
    }

    fn queue(&mut self, p: &mut Process) {
        if !p.is_queued() {
            p.set(process::Queued);
            self.runqueue.append(p);
        }
    }

    unsafe fn run(&mut self) -> ! {
        match self.runqueue.pop() {
            Some(p) => self.switch_to(&mut *p),
            None => idle()
        }
    }

    unsafe fn switch_to(&mut self, p: &mut Process) -> ! {
        if log_switch {
            write("switch_to ");
            con::writeMutPtr(p as *mut Process);
            con::newline();
        }
        p.unset(process::Queued);
        p.set(process::Running);
        self.process = transmute(p as *mut Process);
        // TODO Check fpu_process, see if we need to set/reset TS bit in cr0
        x86::set_cr3(p.cr3);
        extern "C" {
            fn fastret(p : &mut Process) -> !;
            fn slowret(p : &mut Process) -> !;
        }
        if p.is(process::FastRet) {
            p.unset(process::FastRet);
            if log_switch {
                write("fastret to ");
                con::writeHex(p.regs.rip as uint);
                con::newline();
            }
            fastret(p);
        } else {
            if log_switch {
                write("slowret to ");
                con::writeHex(p.regs.rip as uint);
                con::newline();
            }
            slowret(p);
        }
    }

    fn syscall_return(&mut self, p: &mut Process, rax : uint) -> ! {
        p.regs.rax = rax;
        unsafe { self.switch_to(p); }
    }

    #[inline(never)]
    unsafe fn get_process<'a>(&self) -> &'a mut Process {
        &mut **(&self.process as *Option<&'static mut Process> as *Option<&'a mut Process> as **mut Process)
    }

    fn leave_proc(&mut self) {
        unsafe {
            let p = self.get_process();
            p.unset(process::Running);
            //self.process = None;
        }
    }
}

// NB: One of the funky guarantees that Rust gives/requires is that there is
// at most one &mut reference to the same thing at any one time. This function
// can't quite guarantee that...
pub fn cpu() -> &mut PerCpu {
    unsafe {
        let mut ret = 0;
        asm!("movq %gs:($0), $0" : "=r"(ret) : "0"(ret));
        return &mut *(ret as *mut PerCpu);
    }
}

#[lang="exchange_malloc"]
#[inline(always)]
pub fn xmalloc(size : uint, _align: uint) -> *mut u8 {
    malloc(size)
}

pub fn malloc(size : uint) -> *mut u8 {
    if size > 4096 {
        abort("oversized malloc");
    }
    #[inline(never)]
    fn malloc_() -> *mut u8 {
        cpu().memory.alloc_frame_panic()
    }
    malloc_()
}

#[inline(always)]
pub fn alloc<T>() -> *mut T {
    malloc(size_of::<T>()) as *mut T
}

pub fn free<T>(p : *mut T) {
    #[inline(never)]
    fn free_(p: *mut u8) {
        cpu().memory.free_frame(p);
    }
    if p.is_not_null() {
        free_(p as *mut u8);
    }
}

#[lang="exchange_free"]
#[inline(always)]
pub fn xfree(p : *mut u8, _size: uint, _align: uint) {
    free(p);
}

unsafe fn setup_msrs(gs : uint) {
    use x86::msr::*;
    use x86::rflags;
    use x86::efer;
    use x86::seg;
    #[allow(dead_code)]
    extern {
        fn syscall_entry_stub();
        fn syscall_entry_compat();
    }

    wrmsr(STAR, (seg::user_code32_base << 16) | seg::code);
    wrmsr(LSTAR, syscall_entry_stub as uint);
    wrmsr(CSTAR, syscall_entry_compat as uint);
    // FIXME: We want to clear a lot more flags - Direction for instance.
    // FreeBSD sets PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D
    wrmsr(FMASK, rflags::IF | rflags::VM);
    wrmsr(EFER, rdmsr(EFER) | efer::SCE | efer::NXE);
    wrmsr(GSBASE, gs);
}

#[lang="eh_personality"]
fn dummy() {}

#[inline(never)]
fn new_proc_simple(start : uint, end_unaligned : uint) -> *mut Process {
    let end = (end_unaligned + 0xfff) & !0xfff;
    let start_page = start & !0xfff;
    let aspace : *mut AddressSpace = unsafe { transmute(box AddressSpace::new()) };
    let ret : *mut Process = unsafe { transmute(box Process::new(aspace)) };
    unsafe {
        (*ret).regs.rsp = 0x100000;
        (*ret).regs.rip = 0x100000 + (start & 0xfff);
    }

    unsafe {
        use aspace::mapflag::*;
        // Stack at 1MB - 4kB (not executable)
        (*aspace).mapcard_set(0x0ff000, 0, 0, Anon | R | W);
        (*aspace).mapcard_set(0x100000, 0, start_page - 0x100000, Phys | R | X);
        (*aspace).mapcard_set(0x100000 + (end - start_page), 0, 0, 0);
        /*match (*ret).aspace().mapcard_find(0x100000) {
            Some(c) => {
                write("0x100000: ");
                con::writePHex(c.vaddr());
                write(" -> paddr ");
                con::writePHex(c.paddr(0x100000));
                con::newline();
            },
            None => {
                abort("mapcard we added is not there anymore");
            }
        }*/
    }
    return ret;
}

fn assoc_procs(p : &mut Process, i : uint, q : &mut Process, j : uint) {
    if log_assoc_procs {
        con::writeMutPtr(p);
        con::putc(':');
        con::writeUInt(i);
        write(" <-> ");
        con::writeUInt(j);
        con::putc(':');
        con::writeMutPtr(q);
        con::newline();
    }
    p.assoc_handles(j, q, i);
}

fn init_modules(cpu : &mut PerCpu) {
    let &info = start32::MultiBootInfo();
    if !info.has(mboot::Modules) {
        return;
    }
    let mut head = DList::empty();
    let mut count = 0;
    for m in info.modules(start32::PhysAddr).iter() {
        write("Module ");
        con::writeHex(m.start as uint);
        write("..");
        con::writeHex(m.end as uint);
        write(": ");
        con::writeCStr(start32::PhysAddr(m.string as uint));
        con::newline();

        head.append(new_proc_simple(m.start as uint, m.end as uint));
        count += 1;
    }
    con::writeUInt(count);
    con::newline();
    // Now all processes are in our list. We need to remove them before it
    // gets possible to make them runnable.
    let mut i = 0;
    for p in head.iter() {
        i += 1;
        // start iterating at j = i + 1, and q = p.next...
        let mut j = 0;
        for q in head.iter() {
            j += 1;
            if i < j {
                assoc_procs(p, i, q, j);
            }
        }
    }
    while match head.pop() {
        Some(p) => { cpu.queue(unsafe { &mut *p }); true },
        None => false
    } {}
}

pub fn dump_runqueue(queue: &DList<Process>) {
    let mut count = 0;
    for _ in queue.iter() {
        count += 1;
    }
    con::write("runqueue: ");
    con::writeUInt(count);
    con::newline();
    for p in queue.iter() {
        p.dump();
    }
}

#[no_mangle]
pub unsafe fn start64() -> ! {
    con::init(MutPhysAddr(0xb8000), 80, 25);
    con::clear();
    write("Hello World!\n");
    //writeMBInfo(start32::MultiBootInfo());

    x86::lgdt(start32::Gdtr());
    x86::ltr(x86::seg::tss64);

    idt::init();

    mem::global.init(start32::MultiBootInfo(), start32::MemoryStart());
    write("Memory initialized. ");
    mem::global.stat();

    let pcpu = PerCpu::new();
    let ref mut cpu = *pcpu;
    cpu.start();
    if mem_test {
        cpu.memory.test();
        mem::global.stat();
    }

    init_modules(cpu);
    //dump_runqueue(&cpu.runqueue);

//  let mut i = 0;
//  loop {
//      con.writeUInt(i);
//      con.putc('\n');
//      i += 1;
//  }
    cpu.run();
}
<commit_msg>fastret/slowret is not very interesting right now<commit_after>#![allow(ctypes)]
#![no_std]
#![no_main]
#![feature(globs)]
#![feature(asm)]
// Adding pub mod (another fix for this warning) increases footprint, so just
// disble it instead.
#![allow(visible_private_types)]

extern crate core;

use core::prelude::*;
use core::mem::*;

use aspace::AddressSpace;
use con::write;
use dlist::DList;
use process::Process;
use start32::MultiBootInfo;
//use start32::OrigMultiBootInfo;
use start32::PhysAddr;
use start32::MutPhysAddr;
use util::abort;
use x86::idt;
pub use x86::idt::irq_entry;
pub use syscall::syscall;

mod aspace;
#[allow(dead_code)]
mod con;
mod dict;
mod dlist;
mod mboot;
mod mem;
mod process;
mod start32;
mod syscall;
pub mod util;
mod x86;

static log_assoc_procs : bool = false;
static log_page_fault : bool = false;
static log_switch : bool = false;
static mem_test : bool = false;

#[allow(dead_code)]
fn writeMBInfo(infop : *mboot::Info) {
    con::write("Multiboot info at ");
    con::writePtr(infop);
    con::putc('\n');

    let &info = unsafe { &*infop };
    con::write("Flags: ");
    con::writeHex(info.flags as uint);
    con::newline();

    if info.has(mboot::MemorySize) {
        con::writeUInt(info.mem_lower as uint);
        con::write("kB lower memory, ");
        con::writeUInt(info.mem_upper as uint);
        con::write("kB upper memory, ");
        con::writeUInt(((info.mem_lower + info.mem_upper + 1023) / 1024) as uint);
        con::write("MB total.\n");
    }
    if info.has(mboot::CommandLine) {
        let cmdline : *u8 = PhysAddr(info.cmdline as uint);
        con::write("Command line @");
        con::writePtr(cmdline);
        con::write(" (");
        con::writeHex(info.cmdline as uint);
        con::write(") \"");
        con::writeCStr(cmdline);
        con::write("\"\n");
    }
}

pub fn generic_irq_handler(p : &mut Process, vec : u8) {
    write("IRQ! vec=");
    con::writeUInt(vec as uint);
    con::newline();
    cpu().queue(p);
}

pub fn page_fault(p : &mut Process, error : uint) -> ! {
    mod pf_errors {
        #![allow(dead_code)]
        // Error code flags.
        pub static PRESENT : uint = 1;
        pub static WRITE : uint = 2;
        pub static USER : uint = 4;
        pub static RSVD : uint = 8;
        pub static INSTR : uint = 16;
    }

    if log_page_fault {
        write("page fault ");
        con::writeHex(error);
        write(" cr2=");
        con::writePHex(x86::cr2());
        write(" rip=");
        con::writePHex(p.regs.rip as uint);
        write(" in process ");
        con::writeMutPtr(p);
        con::newline();
    }

    if (error & pf_errors::USER) == 0 {
        abort("kernel page fault\n");
    }

    let back = p.aspace().find_add_backing(x86::cr2() & !0xfff);
    // FIXME should return e.g. Option<> so we can detect failures better than
    // just aborting.
    p.aspace().add_pte(back.vaddr(), back.pte());

    cpu().queue(p);
    unsafe { cpu().run(); }
}

pub fn handler_NM() {
    abort("NM");
}

pub fn idle() -> ! {
    loop {
        write("idle\n");
        unsafe { asm!("swapgs; sti; hlt; cli; swapgs" :::: "volatile"); } }
}

pub struct PerCpu {
    selfp : *mut PerCpu,
    stack : *mut u8,
    process : Option<&'static mut Process>,
    //

    // End of assembly-fixed fields.
    memory : mem::PerCpu,
    runqueue : DList<Process>,
}

impl PerCpu {
    unsafe fn new() -> *mut PerCpu {
        let mut mem = mem::PerCpu::new();
        let p : *mut PerCpu = mem.alloc_frame_panic();
        let stack : *mut u8 = mem.alloc_frame_panic();
        *p = PerCpu {
            selfp : p,
            stack : stack,
            memory : mem,
            runqueue : DList::empty(),
            process : None
        };
        return p
    }

    unsafe fn start(&mut self) {
        setup_msrs(self.selfp as uint);
    }

    fn queue(&mut self, p: &mut Process) {
        if !p.is_queued() {
            p.set(process::Queued);
            self.runqueue.append(p);
        }
    }

    unsafe fn run(&mut self) -> ! {
        match self.runqueue.pop() {
            Some(p) => self.switch_to(&mut *p),
            None => idle()
        }
    }

    unsafe fn switch_to(&mut self, p: &mut Process) -> ! {
        if log_switch {
            write("switch_to ");
            con::writeMutPtr(p as *mut Process);
            write(" rip=");
            con::writeHex(p.regs.rip as uint);
            con::newline();
        }
        p.unset(process::Queued);
        p.set(process::Running);
        self.process = transmute(p as *mut Process);
        // TODO Check fpu_process, see if we need to set/reset TS bit in cr0
        x86::set_cr3(p.cr3);
        extern "C" {
            fn fastret(p : &mut Process) -> !;
            fn slowret(p : &mut Process) -> !;
        }
        if p.is(process::FastRet) {
            p.unset(process::FastRet);
            fastret(p);
        } else {
            slowret(p);
        }
    }

    fn syscall_return(&mut self, p: &mut Process, rax : uint) -> ! {
        p.regs.rax = rax;
        unsafe { self.switch_to(p); }
    }

    #[inline(never)]
    unsafe fn get_process<'a>(&self) -> &'a mut Process {
        &mut **(&self.process as *Option<&'static mut Process> as *Option<&'a mut Process> as **mut Process)
    }

    fn leave_proc(&mut self) {
        unsafe {
            let p = self.get_process();
            p.unset(process::Running);
            //self.process = None;
        }
    }
}

// NB: One of the funky guarantees that Rust gives/requires is that there is
// at most one &mut reference to the same thing at any one time. This function
// can't quite guarantee that...
pub fn cpu() -> &mut PerCpu {
    unsafe {
        let mut ret = 0;
        asm!("movq %gs:($0), $0" : "=r"(ret) : "0"(ret));
        return &mut *(ret as *mut PerCpu);
    }
}

#[lang="exchange_malloc"]
#[inline(always)]
pub fn xmalloc(size : uint, _align: uint) -> *mut u8 {
    malloc(size)
}

pub fn malloc(size : uint) -> *mut u8 {
    if size > 4096 {
        abort("oversized malloc");
    }
    #[inline(never)]
    fn malloc_() -> *mut u8 {
        cpu().memory.alloc_frame_panic()
    }
    malloc_()
}

#[inline(always)]
pub fn alloc<T>() -> *mut T {
    malloc(size_of::<T>()) as *mut T
}

pub fn free<T>(p : *mut T) {
    #[inline(never)]
    fn free_(p: *mut u8) {
        cpu().memory.free_frame(p);
    }
    if p.is_not_null() {
        free_(p as *mut u8);
    }
}

#[lang="exchange_free"]
#[inline(always)]
pub fn xfree(p : *mut u8, _size: uint, _align: uint) {
    free(p);
}

unsafe fn setup_msrs(gs : uint) {
    use x86::msr::*;
    use x86::rflags;
    use x86::efer;
    use x86::seg;
    #[allow(dead_code)]
    extern {
        fn syscall_entry_stub();
        fn syscall_entry_compat();
    }

    wrmsr(STAR, (seg::user_code32_base << 16) | seg::code);
    wrmsr(LSTAR, syscall_entry_stub as uint);
    wrmsr(CSTAR, syscall_entry_compat as uint);
    // FIXME: We want to clear a lot more flags - Direction for instance.
    // FreeBSD sets PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D
    wrmsr(FMASK, rflags::IF | rflags::VM);
    wrmsr(EFER, rdmsr(EFER) | efer::SCE | efer::NXE);
    wrmsr(GSBASE, gs);
}

#[lang="eh_personality"]
fn dummy() {}

#[inline(never)]
fn new_proc_simple(start : uint, end_unaligned : uint) -> *mut Process {
    let end = (end_unaligned + 0xfff) & !0xfff;
    let start_page = start & !0xfff;
    let aspace : *mut AddressSpace = unsafe { transmute(box AddressSpace::new()) };
    let ret : *mut Process = unsafe { transmute(box Process::new(aspace)) };
    unsafe {
        (*ret).regs.rsp = 0x100000;
        (*ret).regs.rip = 0x100000 + (start & 0xfff);
    }

    unsafe {
        use aspace::mapflag::*;
        // Stack at 1MB - 4kB (not executable)
        (*aspace).mapcard_set(0x0ff000, 0, 0, Anon | R | W);
        (*aspace).mapcard_set(0x100000, 0, start_page - 0x100000, Phys | R | X);
        (*aspace).mapcard_set(0x100000 + (end - start_page), 0, 0, 0);
        /*match (*ret).aspace().mapcard_find(0x100000) {
            Some(c) => {
                write("0x100000: ");
                con::writePHex(c.vaddr());
                write(" -> paddr ");
                con::writePHex(c.paddr(0x100000));
                con::newline();
            },
            None => {
                abort("mapcard we added is not there anymore");
            }
        }*/
    }
    return ret;
}

fn assoc_procs(p : &mut Process, i : uint, q : &mut Process, j : uint) {
    if log_assoc_procs {
        con::writeMutPtr(p);
        con::putc(':');
        con::writeUInt(i);
        write(" <-> ");
        con::writeUInt(j);
        con::putc(':');
        con::writeMutPtr(q);
        con::newline();
    }
    p.assoc_handles(j, q, i);
}

fn init_modules(cpu : &mut PerCpu) {
    let &info = start32::MultiBootInfo();
    if !info.has(mboot::Modules) {
        return;
    }
    let mut head = DList::empty();
    let mut count = 0;
    for m in info.modules(start32::PhysAddr).iter() {
        write("Module ");
        con::writeHex(m.start as uint);
        write("..");
        con::writeHex(m.end as uint);
        write(": ");
        con::writeCStr(start32::PhysAddr(m.string as uint));
        con::newline();

        head.append(new_proc_simple(m.start as uint, m.end as uint));
        count += 1;
    }
    con::writeUInt(count);
    con::newline();
    // Now all processes are in our list. We need to remove them before it
    // gets possible to make them runnable.
    let mut i = 0;
    for p in head.iter() {
        i += 1;
        // start iterating at j = i + 1, and q = p.next...
        let mut j = 0;
        for q in head.iter() {
            j += 1;
            if i < j {
                assoc_procs(p, i, q, j);
            }
        }
    }
    while match head.pop() {
        Some(p) => { cpu.queue(unsafe { &mut *p }); true },
        None => false
    } {}
}

pub fn dump_runqueue(queue: &DList<Process>) {
    let mut count = 0;
    for _ in queue.iter() {
        count += 1;
    }
    con::write("runqueue: ");
    con::writeUInt(count);
    con::newline();
    for p in queue.iter() {
        p.dump();
    }
}

#[no_mangle]
pub unsafe fn start64() -> ! {
    con::init(MutPhysAddr(0xb8000), 80, 25);
    con::clear();
    write("Hello World!\n");
    //writeMBInfo(start32::MultiBootInfo());

    x86::lgdt(start32::Gdtr());
    x86::ltr(x86::seg::tss64);

    idt::init();

    mem::global.init(start32::MultiBootInfo(), start32::MemoryStart());
    write("Memory initialized. ");
    mem::global.stat();

    let pcpu = PerCpu::new();
    let ref mut cpu = *pcpu;
    cpu.start();
    if mem_test {
        cpu.memory.test();
        mem::global.stat();
    }

    init_modules(cpu);
    //dump_runqueue(&cpu.runqueue);

//  let mut i = 0;
//  loop {
//      con.writeUInt(i);
//      con.putc('\n');
//      i += 1;
//  }
    cpu.run();
}
<|endoftext|>


<commit_before>use std::sync::{Arc, Mutex};

pub struct Persistent<Data, Phantom> {
    data: Arc<Mutex<Data>>
}

impl<D: Send, P> Clone for Persistent<D, P> {
    fn clone(&self) -> Persistent<D, P> {
        Persistent {
            data: self.data.clone()
        }
    }
}

<commit_msg>(feat) Implemented Middleware for Persistent.<commit_after>use iron::{Request, Response, Middleware, Alloy};
use iron::middleware::{Status, Continue};
use std::sync::{Arc, Mutex};

pub struct Persistent<Data, Phantom> {
    data: Arc<Mutex<Data>>
}

impl<D: Send, P> Clone for Persistent<D, P> {
    fn clone(&self) -> Persistent<D, P> {
        Persistent {
            data: self.data.clone()
        }
    }
}

impl<D: Send, P> Middleware for Persistent<D, P> {
    fn enter(&mut self, _: &mut Request,
             _: &mut Response, alloy: &mut Alloy) -> Status {
        alloy.insert::<Persistent<D, P>>(self.clone());
        Continue
    }
}

<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate glium;
extern crate cgmath;

pub mod quads;
pub mod shader;
pub mod texture;

pub use self::quads::*;
pub use self::shader::*;
pub use self::texture::*;

pub fn build_window(title:String) -> glium::Display {
    use glium::DisplayBuild;
    use glium::glutin::GlRequest;
    use glium::glutin::GlProfile;
    use glium::glutin::Api;
    use glium::glutin::WindowBuilder;

    WindowBuilder::new()
        .with_title(title)
        .with_gl_profile(GlProfile::Core)
        .with_gl(GlRequest::Specific(Api::OpenGl,(4,0)))
        .with_depth_buffer(24)
        // .with_vsync()
        .build_glium()
        .unwrap()
}

pub fn translucent_draw_params<'a>() -> glium::DrawParameters<'a> {
    let draw_parameters = glium::DrawParameters {
        depth: glium::Depth {
            test: glium::draw_parameters::DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        blend: glium::Blend::alpha_blending(),
        .. Default::default()
    };
    draw_parameters
}

pub fn opaque_draw_params<'a>() -> glium::DrawParameters<'a> {
    let draw_parameters = glium::DrawParameters {
        depth: glium::Depth {
            test: glium::draw_parameters::DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        .. Default::default()
    };
    draw_parameters
}

pub fn down_size_v3(arr: [f64; 3]) -> [f32; 3] {
    let mut out : [f32; 3] = [0.0; 3];
    for a in 0..3 {
        out[a] = arr[a] as f32
    }
    out
}

pub fn down_size_m4(arr: [[f64; 4];4]) -> [[f32; 4]; 4] {
    let mut out : [[f32; 4]; 4] = [[0.0; 4]; 4];
    for a in 0..4 {
        for b in 0..4 {
            out[a][b] = arr[a][b] as f32
        }
    }

    out
}
<commit_msg>Vsync toggle<commit_after>#![allow(dead_code)]

extern crate glium;
extern crate cgmath;

pub mod quads;
pub mod shader;
pub mod texture;

pub use self::quads::*;
pub use self::shader::*;
pub use self::texture::*;

pub fn build_window(title:String, vsync:bool) -> glium::Display {
    use glium::DisplayBuild;
    use glium::glutin::GlRequest;
    use glium::glutin::GlProfile;
    use glium::glutin::Api;
    use glium::glutin::WindowBuilder;

    let mut builder = WindowBuilder::new()
        .with_title(title)
        .with_gl_profile(GlProfile::Core)
        .with_gl(GlRequest::Specific(Api::OpenGl,(4,0)))
        .with_depth_buffer(24);
    if vsync {
        builder = builder.with_vsync();
    }
    builder.build_glium()
        .unwrap()
}

pub fn translucent_draw_params<'a>() -> glium::DrawParameters<'a> {
    let draw_parameters = glium::DrawParameters {
        depth: glium::Depth {
            test: glium::draw_parameters::DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        blend: glium::Blend::alpha_blending(),
        .. Default::default()
    };
    draw_parameters
}

pub fn opaque_draw_params<'a>() -> glium::DrawParameters<'a> {
    let draw_parameters = glium::DrawParameters {
        depth: glium::Depth {
            test: glium::draw_parameters::DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        .. Default::default()
    };
    draw_parameters
}

pub fn down_size_v3(arr: [f64; 3]) -> [f32; 3] {
    let mut out : [f32; 3] = [0.0; 3];
    for a in 0..3 {
        out[a] = arr[a] as f32
    }
    out
}

pub fn down_size_m4(arr: [[f64; 4];4]) -> [[f32; 4]; 4] {
    let mut out : [[f32; 4]; 4] = [[0.0; 4]; 4];
    for a in 0..4 {
        for b in 0..4 {
            out[a][b] = arr[a][b] as f32
        }
    }

    out
}
<|endoftext|>


<commit_before>//!
//! Flash Memory simulation
//!
//!

use crate::bus::Bus;
use crate::core::fault::Fault;
use byteorder::{ByteOrder, LittleEndian};

#[derive(Debug)]
/// Flash memory with configurable start address and data content
pub struct FlashMemory {
    start_address: u32,
    data: Box<[u8]>,
}

impl FlashMemory {
    /// make a flash data instance with given start address, size and data content
    pub fn new(start_address: u32, size: usize, new_data: &[u8]) -> Self {
        let mut data = vec![0_u8; size].into_boxed_slice();
        data.copy_from_slice(new_data);

        Self {
            start_address: start_address,
            data: data,
        }
    }
}

impl Bus for FlashMemory {
    fn read8(&self, addr: u32) -> Result<u8, Fault> {
        let a = addr - self.start_address;
        Ok(self.data[a as usize])
    }
    fn read16(&self, addr: u32) -> Result<u16, Fault> {
        let a = (addr - self.start_address) as usize;

        Ok(LittleEndian::read_u16(&self.data[a..a + 2]))
    }

    fn read32(&self, addr: u32) -> Result<u32, Fault> {
        let a = (addr - self.start_address) as usize;
        Ok(LittleEndian::read_u32(&self.data[a..a + 4]))
    }

    fn write32(&mut self, _addr: u32, _value: u32) -> Result<(), Fault> {
        Err(Fault::DAccViol)
    }

    fn write16(&mut self, _addr: u32, _value: u16) -> Result<(), Fault> {
        Err(Fault::DAccViol)
    }
    fn write8(&mut self, _addr: u32, _value: u8) -> Result<(), Fault> {
        Err(Fault::DAccViol)
    }

    fn in_range(&self, addr: u32) -> bool {
        if (addr >= self.start_address) && (addr < (self.start_address + self.data.len() as u32)) {
            return true;
        }
        false
    }
}

#[test]
fn test_new() {
    // should be able to make new instance of memory
    let data = [0; 1024];
    let _mem = FlashMemory::new(0, 1024, &data);
}

#[test]
fn test_load() {
    let mem = FlashMemory::new(0, 1024, &vec![42u8; 1024]);
    assert_eq!(mem.read8(0).unwrap(), 42);
    assert_eq!(mem.read16(0).unwrap(), (42 << 8) + 42);
    assert_eq!(
        mem.read32(0).unwrap(),
        (42 << 24) + (42 << 16) + (42 << 8) + 42
    );
}

#[test]
fn test_in_range() {
    {
        /* no offset */
        let mem = FlashMemory::new(0, 1024, &vec![0u8; 1024]);
        assert!(mem.in_range(0));
        assert!(mem.in_range(1023));
        assert!(!mem.in_range(1024));
        assert!(!mem.in_range(0xFFFF_FFFF));
    }

    {
        /* offset of 0x8000_0000 */
        let mem = FlashMemory::new(0x8000_0000, 1024, &vec![0u8; 1024]);
        assert!(mem.in_range(0x8000_0000));
        assert!(mem.in_range(0x8000_0001));
        assert!(!mem.in_range(0x8000_0000 + 1024));
        assert!(!mem.in_range(0x8000_0000 + 0xffff));
    }
}
<commit_msg>Supports lenght for flash memory<commit_after>//!
//! Flash Memory simulation
//!
//!

use crate::bus::Bus;
use crate::core::fault::Fault;
use byteorder::{ByteOrder, LittleEndian};

#[derive(Debug)]
/// Flash memory with configurable start address and data content
pub struct FlashMemory {
    start_address: u32,
    data: Box<[u8]>,
}

impl FlashMemory {
    /// make a flash data instance with given start address, size and data content
    pub fn new(start_address: u32, size: usize, new_data: &[u8]) -> Self {
        let mut data = vec![0_u8; size].into_boxed_slice();
        data.copy_from_slice(new_data);

        Self {
            start_address: start_address,
            data: data,
        }
    }

    ///
    pub fn len(&self) -> usize {
        self.data.len()
    }

    ///
    pub fn is_empty(&self) -> bool {
        self.data.len() == 0
    }
}

impl Bus for FlashMemory {
    fn read8(&self, addr: u32) -> Result<u8, Fault> {
        let a = addr - self.start_address;
        Ok(self.data[a as usize])
    }
    fn read16(&self, addr: u32) -> Result<u16, Fault> {
        let a = (addr - self.start_address) as usize;

        Ok(LittleEndian::read_u16(&self.data[a..a + 2]))
    }

    fn read32(&self, addr: u32) -> Result<u32, Fault> {
        let a = (addr - self.start_address) as usize;
        Ok(LittleEndian::read_u32(&self.data[a..a + 4]))
    }

    fn write32(&mut self, _addr: u32, _value: u32) -> Result<(), Fault> {
        Err(Fault::DAccViol)
    }

    fn write16(&mut self, _addr: u32, _value: u16) -> Result<(), Fault> {
        Err(Fault::DAccViol)
    }
    fn write8(&mut self, _addr: u32, _value: u8) -> Result<(), Fault> {
        Err(Fault::DAccViol)
    }

    fn in_range(&self, addr: u32) -> bool {
        if (addr >= self.start_address) && (addr < (self.start_address + self.data.len() as u32)) {
            return true;
        }
        false
    }
}

#[test]
fn test_new() {
    // should be able to make new instance of memory
    let data = [0; 1024];
    let _mem = FlashMemory::new(0, 1024, &data);
}

#[test]
fn test_load() {
    let mem = FlashMemory::new(0, 1024, &vec![42u8; 1024]);
    assert_eq!(mem.read8(0).unwrap(), 42);
    assert_eq!(mem.read16(0).unwrap(), (42 << 8) + 42);
    assert_eq!(
        mem.read32(0).unwrap(),
        (42 << 24) + (42 << 16) + (42 << 8) + 42
    );
}

#[test]
fn test_in_range() {
    {
        /* no offset */
        let mem = FlashMemory::new(0, 1024, &vec![0u8; 1024]);
        assert!(mem.in_range(0));
        assert!(mem.in_range(1023));
        assert!(!mem.in_range(1024));
        assert!(!mem.in_range(0xFFFF_FFFF));
    }

    {
        /* offset of 0x8000_0000 */
        let mem = FlashMemory::new(0x8000_0000, 1024, &vec![0u8; 1024]);
        assert!(mem.in_range(0x8000_0000));
        assert!(mem.in_range(0x8000_0001));
        assert!(!mem.in_range(0x8000_0000 + 1024));
        assert!(!mem.in_range(0x8000_0000 + 0xffff));
    }
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"]

#[macro_use]
extern crate error_chain;
extern crate itertools;
#[cfg(unix)]
extern crate libc;
extern crate regex;
extern crate rustup_dist;
extern crate rustup_utils;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate tempfile;
extern crate time;
extern crate toml;
extern crate url;

pub use crate::config::*;
pub use crate::errors::*;
pub use crate::notifications::*;
pub use crate::toolchain::*;
pub use rustup_utils::{notify, toml_utils, utils};

// A list of all binaries which Rustup will proxy.
pub static TOOLS: &'static [&'static str] = &[
    "rustc",
    "rustdoc",
    "cargo",
    "rust-lldb",
    "rust-gdb",
    "rls",
    "cargo-clippy",
];

// Tools which are commonly installed by Cargo as well as rustup. We take a bit
// more care with these to ensure we don't overwrite the user's previous
// installation.
pub static DUP_TOOLS: &'static [&'static str] = &["rustfmt", "cargo-fmt"];

fn component_for_bin(binary: &str) -> Option<&'static str> {
    match binary {
        "rustc" | "rustdoc" => Some("rustc"),
        "cargo" => Some("cargo"),
        "rust-lldb" => Some("lldb-preview"),
        "rust-gdb" => Some("gdb-preview"),
        "rls" => Some("rls"),
        "cargo-clippy" => Some("clippy"),
        "rustfmt" | "cargo-fmt" => Some("rustfmt"),
        _ => None,
    }
}

pub mod command;
mod config;
pub mod env_var;
mod errors;
mod install;
mod notifications;
pub mod settings;
pub mod telemetry;
pub mod telemetry_analysis;
mod toolchain;
<commit_msg>Address failing test<commit_after>#![recursion_limit = "1024"]

#[macro_use]
extern crate error_chain;
extern crate itertools;
#[cfg(unix)]
extern crate libc;
extern crate regex;
extern crate rustup_dist;
extern crate rustup_utils;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate tempfile;
extern crate time;
extern crate toml;
extern crate url;

pub use crate::config::*;
pub use crate::errors::*;
pub use crate::notifications::*;
pub use crate::toolchain::*;
pub use rustup_utils::{notify, toml_utils, utils};

// A list of all binaries which Rustup will proxy.
pub static TOOLS: &'static [&'static str] = &[
    "rustc",
    "rustdoc",
    "cargo",
    "rust-lldb",
    "rust-gdb",
    "rls",
    "cargo-clippy",
];

// Tools which are commonly installed by Cargo as well as rustup. We take a bit
// more care with these to ensure we don't overwrite the user's previous
// installation.
pub static DUP_TOOLS: &'static [&'static str] = &["rustfmt", "cargo-fmt"];

fn component_for_bin(binary: &str) -> Option<&'static str> {
    use std::env::consts::EXE_SUFFIX;

    let binary_prefix = match binary.find(EXE_SUFFIX) {
        _ if EXE_SUFFIX.is_empty() => binary,
        Some(i) => &binary[..i],
        None => binary,
    };

    match binary_prefix {
        "rustc" | "rustdoc" => Some("rustc"),
        "cargo" => Some("cargo"),
        "rust-lldb" => Some("lldb-preview"),
        "rust-gdb" => Some("gdb-preview"),
        "rls" => Some("rls"),
        "cargo-clippy" => Some("clippy"),
        "rustfmt" | "cargo-fmt" => Some("rustfmt"),
        _ => None,
    }
}

pub mod command;
mod config;
pub mod env_var;
mod errors;
mod install;
mod notifications;
pub mod settings;
pub mod telemetry;
pub mod telemetry_analysis;
mod toolchain;
<|endoftext|>


<commit_before>use reexport::*;
use rustc::lint::*;
use rustc::hir::def::Def;
use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics, NestedVisitorMap};
use std::collections::{HashSet, HashMap};
use syntax::codemap::Span;
use utils::{in_external_macro, span_lint, last_path_segment};
use syntax::symbol::keywords;

/// **What it does:** Checks for lifetime annotations which can be removed by
/// relying on lifetime elision.
///
/// **Why is this bad?** The additional lifetimes make the code look more
/// complicated, while there is nothing out of the ordinary going on. Removing
/// them leads to more readable code.
///
/// **Known problems:** Potential false negatives: we bail out if the function
/// has a `where` clause where lifetimes are mentioned.
///
/// **Example:**
/// ```rust
/// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }
/// ```
declare_lint! {
    pub NEEDLESS_LIFETIMES,
    Warn,
    "using explicit lifetimes for references in function arguments when elision rules \
     would allow omitting them"
}

/// **What it does:** Checks for lifetimes in generics that are never used
/// anywhere else.
///
/// **Why is this bad?** The additional lifetimes make the code look more
/// complicated, while there is nothing out of the ordinary going on. Removing
/// them leads to more readable code.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// fn unused_lifetime<'a>(x: u8) { .. }
/// ```
declare_lint! {
    pub UNUSED_LIFETIMES,
    Warn,
    "unused lifetimes in function definitions"
}

#[derive(Copy,Clone)]
pub struct LifetimePass;

impl LintPass for LifetimePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_LIFETIMES, UNUSED_LIFETIMES)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LifetimePass {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if let ItemFn(ref decl, _, _, _, ref generics, id) = item.node {
            check_fn_inner(cx, decl, Some(id), generics, item.span);
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
        if let ImplItemKind::Method(ref sig, id) = item.node {
            check_fn_inner(cx, &sig.decl, Some(id), &sig.generics, item.span);
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
        if let TraitItemKind::Method(ref sig, ref body) = item.node {
            let body = match *body {
                TraitMethod::Required(_) => None,
                TraitMethod::Provided(id) => Some(id),
            };
            check_fn_inner(cx, &sig.decl, body, &sig.generics, item.span);
        }
    }
}

/// The lifetime of a &-reference.
#[derive(PartialEq, Eq, Hash, Debug)]
enum RefLt {
    Unnamed,
    Static,
    Named(Name),
}

fn check_fn_inner<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, body: Option<BodyId>, generics: &'tcx Generics, span: Span) {
    if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) {
        return;
    }

    let mut bounds_lts = Vec::new();
    for typ in &generics.ty_params {
        for bound in &typ.bounds {
            if let TraitTyParamBound(ref trait_ref, _) = *bound {
                let bounds = trait_ref.trait_ref
                    .path
                    .segments
                    .last()
                    .expect("a path must have at least one segment")
                    .parameters
                    .lifetimes();
                for bound in bounds {
                    if bound.name != "'static" && !bound.is_elided() {
                        return;
                    }
                    bounds_lts.push(bound);
                }
            }
        }
    }
    if could_use_elision(cx, decl, body, &generics.lifetimes, bounds_lts) {
        span_lint(cx,
                  NEEDLESS_LIFETIMES,
                  span,
                  "explicit lifetimes given in parameter types where they could be elided");
    }
    report_extra_lifetimes(cx, decl, generics);
}

fn could_use_elision<'a, 'tcx: 'a>(
    cx: &LateContext<'a, 'tcx>,
    func: &'tcx FnDecl,
    body: Option<BodyId>,
    named_lts: &'tcx [LifetimeDef],
    bounds_lts: Vec<&'tcx Lifetime>,
) -> bool {
    // There are two scenarios where elision works:
    // * no output references, all input references have different LT
    // * output references, exactly one input reference with same LT
    // All lifetimes must be unnamed, 'static or defined without bounds on the
    // level of the current item.

    // check named LTs
    let allowed_lts = allowed_lts_from(named_lts);

    // these will collect all the lifetimes for references in arg/return types
    let mut input_visitor = RefVisitor::new(cx);
    let mut output_visitor = RefVisitor::new(cx);

    // extract lifetimes in input argument types
    for arg in &func.inputs {
        input_visitor.visit_ty(arg);
    }
    // extract lifetimes in output type
    if let Return(ref ty) = func.output {
        output_visitor.visit_ty(ty);
    }

    let input_lts = match input_visitor.into_vec() {
        Some(lts) => lts_from_bounds(lts, bounds_lts.into_iter()),
        None => return false,
    };
    let output_lts = match output_visitor.into_vec() {
        Some(val) => val,
        None => return false,
    };

    if let Some(body_id) = body {
        let mut checker = BodyLifetimeChecker { lifetimes_used_in_body: false };
        checker.visit_expr(&cx.tcx.hir.body(body_id).value);
        if checker.lifetimes_used_in_body {
            return false;
        }
    }

    // check for lifetimes from higher scopes
    for lt in input_lts.iter().chain(output_lts.iter()) {
        if !allowed_lts.contains(lt) {
            return false;
        }
    }

    // no input lifetimes? easy case!
    if input_lts.is_empty() {
        false
    } else if output_lts.is_empty() {
        // no output lifetimes, check distinctness of input lifetimes

        // only unnamed and static, ok
        if input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static) {
            return false;
        }
        // we have no output reference, so we only need all distinct lifetimes
        input_lts.len() == unique_lifetimes(&input_lts)
    } else {
        // we have output references, so we need one input reference,
        // and all output lifetimes must be the same
        if unique_lifetimes(&output_lts) > 1 {
            return false;
        }
        if input_lts.len() == 1 {
            match (&input_lts[0], &output_lts[0]) {
                (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true,
                (&RefLt::Named(_), &RefLt::Unnamed) => true,
                _ => false, // already elided, different named lifetimes
                // or something static going on
            }
        } else {
            false
        }
    }
}

fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> {
    let mut allowed_lts = HashSet::new();
    for lt in named_lts {
        if lt.bounds.is_empty() {
            allowed_lts.insert(RefLt::Named(lt.lifetime.name));
        }
    }
    allowed_lts.insert(RefLt::Unnamed);
    allowed_lts.insert(RefLt::Static);
    allowed_lts
}

fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> {
    for lt in bounds_lts {
        if lt.name != "'static" {
            vec.push(RefLt::Named(lt.name));
        }
    }

    vec
}

/// Number of unique lifetimes in the given vector.
fn unique_lifetimes(lts: &[RefLt]) -> usize {
    lts.iter().collect::<HashSet<_>>().len()
}

/// A visitor usable for `rustc_front::visit::walk_ty()`.
struct RefVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    lts: Vec<RefLt>,
    abort: bool,
}

impl<'v, 't> RefVisitor<'v, 't> {
    fn new(cx: &'v LateContext<'v, 't>) -> RefVisitor<'v, 't> {
        RefVisitor {
            cx: cx,
            lts: Vec::new(),
            abort: false,
        }
    }

    fn record(&mut self, lifetime: &Option<Lifetime>) {
        if let Some(ref lt) = *lifetime {
            if lt.name == "'static" {
                self.lts.push(RefLt::Static);
            } else if lt.is_elided() {
                self.lts.push(RefLt::Unnamed);
            } else {
                self.lts.push(RefLt::Named(lt.name));
            }
        } else {
            self.lts.push(RefLt::Unnamed);
        }
    }

    fn into_vec(self) -> Option<Vec<RefLt>> {
        if self.abort {
            None
        } else {
            Some(self.lts)
        }
    }

    fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) {
        let last_path_segment = &last_path_segment(qpath).parameters;
        if let AngleBracketedParameters(ref params) = *last_path_segment {
            if params.lifetimes.is_empty() {
                match self.cx.tables.qpath_def(qpath, ty.id) {
                    Def::TyAlias(def_id) |
                    Def::Struct(def_id) => {
                        let generics = self.cx.tcx.item_generics(def_id);
                        for _ in generics.regions.as_slice() {
                            self.record(&None);
                        }
                    },
                    Def::Trait(def_id) => {
                        let trait_def = self.cx.tcx.maps.trait_def.borrow()[&def_id];
                        for _ in &self.cx.tcx.item_generics(trait_def.def_id).regions {
                            self.record(&None);
                        }
                    },
                    _ => (),
                }
            }
        }
    }
}

impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
    // for lifetimes as parameters of generics
    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
        self.record(&Some(*lifetime));
    }

    fn visit_ty(&mut self, ty: &'tcx Ty) {
        match ty.node {
            TyRptr(ref lt, _) if lt.is_elided() => {
                self.record(&None);
            },
            TyPath(ref path) => {
                self.collect_anonymous_lifetimes(path, ty);
            },
            TyImplTrait(ref param_bounds) => {
                for bound in param_bounds {
                    if let RegionTyParamBound(_) = *bound {
                        self.record(&None);
                    }
                }
            },
            TyTraitObject(ref bounds, ref lt) => {
                if !lt.is_elided() {
                    self.abort = true;
                }
                for bound in bounds {
                    self.visit_poly_trait_ref(bound, TraitBoundModifier::None);
                }
                return;
            },
            _ => (),
        }
        walk_ty(self, ty);
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to
/// reason about elision.
fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &'tcx WhereClause) -> bool {
    for predicate in &where_clause.predicates {
        match *predicate {
            WherePredicate::RegionPredicate(..) => return true,
            WherePredicate::BoundPredicate(ref pred) => {
                // a predicate like F: Trait or F: for<'a> Trait<'a>
                let mut visitor = RefVisitor::new(cx);
                // walk the type F, it may not contain LT refs
                walk_ty(&mut visitor, &pred.bounded_ty);
                if !visitor.lts.is_empty() {
                    return true;
                }
                // if the bounds define new lifetimes, they are fine to occur
                let allowed_lts = allowed_lts_from(&pred.bound_lifetimes);
                // now walk the bounds
                for bound in pred.bounds.iter() {
                    walk_ty_param_bound(&mut visitor, bound);
                }
                // and check that all lifetimes are allowed
                match visitor.into_vec() {
                    None => return false,
                    Some(lts) => for lt in lts {
                        if !allowed_lts.contains(&lt) {
                            return true;
                        }
                    },
                }
            },
            WherePredicate::EqPredicate(ref pred) => {
                let mut visitor = RefVisitor::new(cx);
                walk_ty(&mut visitor, &pred.lhs_ty);
                walk_ty(&mut visitor, &pred.rhs_ty);
                if !visitor.lts.is_empty() {
                    return true;
                }
            },
        }
    }
    false
}

struct LifetimeChecker {
    map: HashMap<Name, Span>,
}

impl<'tcx> Visitor<'tcx> for LifetimeChecker {
    // for lifetimes as parameters of generics
    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
        self.map.remove(&lifetime.name);
    }

    fn visit_lifetime_def(&mut self, _: &'tcx LifetimeDef) {
        // don't actually visit `<'a>` or `<'a: 'b>`
        // we've already visited the `'a` declarations and
        // don't want to spuriously remove them
        // `'b` in `'a: 'b` is useless unless used elsewhere in
        // a non-lifetime bound
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) {
    let hs = generics.lifetimes
        .iter()
        .map(|lt| (lt.lifetime.name, lt.lifetime.span))
        .collect();
    let mut checker = LifetimeChecker { map: hs };

    walk_generics(&mut checker, generics);
    walk_fn_decl(&mut checker, func);

    for &v in checker.map.values() {
        span_lint(cx, UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition");
    }
}

struct BodyLifetimeChecker {
    lifetimes_used_in_body: bool,
}

impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
    // for lifetimes as parameters of generics
    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
        if lifetime.name != keywords::Invalid.name() && lifetime.name != "'static" {
            self.lifetimes_used_in_body = true;
        }
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}<commit_msg>Add newline at end of file<commit_after>use reexport::*;
use rustc::lint::*;
use rustc::hir::def::Def;
use rustc::hir::*;
use rustc::hir::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics, NestedVisitorMap};
use std::collections::{HashSet, HashMap};
use syntax::codemap::Span;
use utils::{in_external_macro, span_lint, last_path_segment};
use syntax::symbol::keywords;

/// **What it does:** Checks for lifetime annotations which can be removed by
/// relying on lifetime elision.
///
/// **Why is this bad?** The additional lifetimes make the code look more
/// complicated, while there is nothing out of the ordinary going on. Removing
/// them leads to more readable code.
///
/// **Known problems:** Potential false negatives: we bail out if the function
/// has a `where` clause where lifetimes are mentioned.
///
/// **Example:**
/// ```rust
/// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }
/// ```
declare_lint! {
    pub NEEDLESS_LIFETIMES,
    Warn,
    "using explicit lifetimes for references in function arguments when elision rules \
     would allow omitting them"
}

/// **What it does:** Checks for lifetimes in generics that are never used
/// anywhere else.
///
/// **Why is this bad?** The additional lifetimes make the code look more
/// complicated, while there is nothing out of the ordinary going on. Removing
/// them leads to more readable code.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// fn unused_lifetime<'a>(x: u8) { .. }
/// ```
declare_lint! {
    pub UNUSED_LIFETIMES,
    Warn,
    "unused lifetimes in function definitions"
}

#[derive(Copy,Clone)]
pub struct LifetimePass;

impl LintPass for LifetimePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_LIFETIMES, UNUSED_LIFETIMES)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LifetimePass {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if let ItemFn(ref decl, _, _, _, ref generics, id) = item.node {
            check_fn_inner(cx, decl, Some(id), generics, item.span);
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
        if let ImplItemKind::Method(ref sig, id) = item.node {
            check_fn_inner(cx, &sig.decl, Some(id), &sig.generics, item.span);
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
        if let TraitItemKind::Method(ref sig, ref body) = item.node {
            let body = match *body {
                TraitMethod::Required(_) => None,
                TraitMethod::Provided(id) => Some(id),
            };
            check_fn_inner(cx, &sig.decl, body, &sig.generics, item.span);
        }
    }
}

/// The lifetime of a &-reference.
#[derive(PartialEq, Eq, Hash, Debug)]
enum RefLt {
    Unnamed,
    Static,
    Named(Name),
}

fn check_fn_inner<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, body: Option<BodyId>, generics: &'tcx Generics, span: Span) {
    if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) {
        return;
    }

    let mut bounds_lts = Vec::new();
    for typ in &generics.ty_params {
        for bound in &typ.bounds {
            if let TraitTyParamBound(ref trait_ref, _) = *bound {
                let bounds = trait_ref.trait_ref
                    .path
                    .segments
                    .last()
                    .expect("a path must have at least one segment")
                    .parameters
                    .lifetimes();
                for bound in bounds {
                    if bound.name != "'static" && !bound.is_elided() {
                        return;
                    }
                    bounds_lts.push(bound);
                }
            }
        }
    }
    if could_use_elision(cx, decl, body, &generics.lifetimes, bounds_lts) {
        span_lint(cx,
                  NEEDLESS_LIFETIMES,
                  span,
                  "explicit lifetimes given in parameter types where they could be elided");
    }
    report_extra_lifetimes(cx, decl, generics);
}

fn could_use_elision<'a, 'tcx: 'a>(
    cx: &LateContext<'a, 'tcx>,
    func: &'tcx FnDecl,
    body: Option<BodyId>,
    named_lts: &'tcx [LifetimeDef],
    bounds_lts: Vec<&'tcx Lifetime>,
) -> bool {
    // There are two scenarios where elision works:
    // * no output references, all input references have different LT
    // * output references, exactly one input reference with same LT
    // All lifetimes must be unnamed, 'static or defined without bounds on the
    // level of the current item.

    // check named LTs
    let allowed_lts = allowed_lts_from(named_lts);

    // these will collect all the lifetimes for references in arg/return types
    let mut input_visitor = RefVisitor::new(cx);
    let mut output_visitor = RefVisitor::new(cx);

    // extract lifetimes in input argument types
    for arg in &func.inputs {
        input_visitor.visit_ty(arg);
    }
    // extract lifetimes in output type
    if let Return(ref ty) = func.output {
        output_visitor.visit_ty(ty);
    }

    let input_lts = match input_visitor.into_vec() {
        Some(lts) => lts_from_bounds(lts, bounds_lts.into_iter()),
        None => return false,
    };
    let output_lts = match output_visitor.into_vec() {
        Some(val) => val,
        None => return false,
    };

    if let Some(body_id) = body {
        let mut checker = BodyLifetimeChecker { lifetimes_used_in_body: false };
        checker.visit_expr(&cx.tcx.hir.body(body_id).value);
        if checker.lifetimes_used_in_body {
            return false;
        }
    }

    // check for lifetimes from higher scopes
    for lt in input_lts.iter().chain(output_lts.iter()) {
        if !allowed_lts.contains(lt) {
            return false;
        }
    }

    // no input lifetimes? easy case!
    if input_lts.is_empty() {
        false
    } else if output_lts.is_empty() {
        // no output lifetimes, check distinctness of input lifetimes

        // only unnamed and static, ok
        if input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static) {
            return false;
        }
        // we have no output reference, so we only need all distinct lifetimes
        input_lts.len() == unique_lifetimes(&input_lts)
    } else {
        // we have output references, so we need one input reference,
        // and all output lifetimes must be the same
        if unique_lifetimes(&output_lts) > 1 {
            return false;
        }
        if input_lts.len() == 1 {
            match (&input_lts[0], &output_lts[0]) {
                (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true,
                (&RefLt::Named(_), &RefLt::Unnamed) => true,
                _ => false, // already elided, different named lifetimes
                // or something static going on
            }
        } else {
            false
        }
    }
}

fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> {
    let mut allowed_lts = HashSet::new();
    for lt in named_lts {
        if lt.bounds.is_empty() {
            allowed_lts.insert(RefLt::Named(lt.lifetime.name));
        }
    }
    allowed_lts.insert(RefLt::Unnamed);
    allowed_lts.insert(RefLt::Static);
    allowed_lts
}

fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> {
    for lt in bounds_lts {
        if lt.name != "'static" {
            vec.push(RefLt::Named(lt.name));
        }
    }

    vec
}

/// Number of unique lifetimes in the given vector.
fn unique_lifetimes(lts: &[RefLt]) -> usize {
    lts.iter().collect::<HashSet<_>>().len()
}

/// A visitor usable for `rustc_front::visit::walk_ty()`.
struct RefVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    lts: Vec<RefLt>,
    abort: bool,
}

impl<'v, 't> RefVisitor<'v, 't> {
    fn new(cx: &'v LateContext<'v, 't>) -> RefVisitor<'v, 't> {
        RefVisitor {
            cx: cx,
            lts: Vec::new(),
            abort: false,
        }
    }

    fn record(&mut self, lifetime: &Option<Lifetime>) {
        if let Some(ref lt) = *lifetime {
            if lt.name == "'static" {
                self.lts.push(RefLt::Static);
            } else if lt.is_elided() {
                self.lts.push(RefLt::Unnamed);
            } else {
                self.lts.push(RefLt::Named(lt.name));
            }
        } else {
            self.lts.push(RefLt::Unnamed);
        }
    }

    fn into_vec(self) -> Option<Vec<RefLt>> {
        if self.abort {
            None
        } else {
            Some(self.lts)
        }
    }

    fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) {
        let last_path_segment = &last_path_segment(qpath).parameters;
        if let AngleBracketedParameters(ref params) = *last_path_segment {
            if params.lifetimes.is_empty() {
                match self.cx.tables.qpath_def(qpath, ty.id) {
                    Def::TyAlias(def_id) |
                    Def::Struct(def_id) => {
                        let generics = self.cx.tcx.item_generics(def_id);
                        for _ in generics.regions.as_slice() {
                            self.record(&None);
                        }
                    },
                    Def::Trait(def_id) => {
                        let trait_def = self.cx.tcx.maps.trait_def.borrow()[&def_id];
                        for _ in &self.cx.tcx.item_generics(trait_def.def_id).regions {
                            self.record(&None);
                        }
                    },
                    _ => (),
                }
            }
        }
    }
}

impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
    // for lifetimes as parameters of generics
    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
        self.record(&Some(*lifetime));
    }

    fn visit_ty(&mut self, ty: &'tcx Ty) {
        match ty.node {
            TyRptr(ref lt, _) if lt.is_elided() => {
                self.record(&None);
            },
            TyPath(ref path) => {
                self.collect_anonymous_lifetimes(path, ty);
            },
            TyImplTrait(ref param_bounds) => {
                for bound in param_bounds {
                    if let RegionTyParamBound(_) = *bound {
                        self.record(&None);
                    }
                }
            },
            TyTraitObject(ref bounds, ref lt) => {
                if !lt.is_elided() {
                    self.abort = true;
                }
                for bound in bounds {
                    self.visit_poly_trait_ref(bound, TraitBoundModifier::None);
                }
                return;
            },
            _ => (),
        }
        walk_ty(self, ty);
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to
/// reason about elision.
fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &'tcx WhereClause) -> bool {
    for predicate in &where_clause.predicates {
        match *predicate {
            WherePredicate::RegionPredicate(..) => return true,
            WherePredicate::BoundPredicate(ref pred) => {
                // a predicate like F: Trait or F: for<'a> Trait<'a>
                let mut visitor = RefVisitor::new(cx);
                // walk the type F, it may not contain LT refs
                walk_ty(&mut visitor, &pred.bounded_ty);
                if !visitor.lts.is_empty() {
                    return true;
                }
                // if the bounds define new lifetimes, they are fine to occur
                let allowed_lts = allowed_lts_from(&pred.bound_lifetimes);
                // now walk the bounds
                for bound in pred.bounds.iter() {
                    walk_ty_param_bound(&mut visitor, bound);
                }
                // and check that all lifetimes are allowed
                match visitor.into_vec() {
                    None => return false,
                    Some(lts) => for lt in lts {
                        if !allowed_lts.contains(&lt) {
                            return true;
                        }
                    },
                }
            },
            WherePredicate::EqPredicate(ref pred) => {
                let mut visitor = RefVisitor::new(cx);
                walk_ty(&mut visitor, &pred.lhs_ty);
                walk_ty(&mut visitor, &pred.rhs_ty);
                if !visitor.lts.is_empty() {
                    return true;
                }
            },
        }
    }
    false
}

struct LifetimeChecker {
    map: HashMap<Name, Span>,
}

impl<'tcx> Visitor<'tcx> for LifetimeChecker {
    // for lifetimes as parameters of generics
    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
        self.map.remove(&lifetime.name);
    }

    fn visit_lifetime_def(&mut self, _: &'tcx LifetimeDef) {
        // don't actually visit `<'a>` or `<'a: 'b>`
        // we've already visited the `'a` declarations and
        // don't want to spuriously remove them
        // `'b` in `'a: 'b` is useless unless used elsewhere in
        // a non-lifetime bound
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}

fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) {
    let hs = generics.lifetimes
        .iter()
        .map(|lt| (lt.lifetime.name, lt.lifetime.span))
        .collect();
    let mut checker = LifetimeChecker { map: hs };

    walk_generics(&mut checker, generics);
    walk_fn_decl(&mut checker, func);

    for &v in checker.map.values() {
        span_lint(cx, UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition");
    }
}

struct BodyLifetimeChecker {
    lifetimes_used_in_body: bool,
}

impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
    // for lifetimes as parameters of generics
    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
        if lifetime.name != keywords::Invalid.name() && lifetime.name != "'static" {
            self.lifetimes_used_in_body = true;
        }
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}
<|endoftext|>


<commit_before>//! Hyper server bindings for unix domain sockets

// Std lib
use std::error;
use std::fmt;
use std::io;
use std::os::unix::net::SocketAddr;
use std::path::Path;

// Third party
use futures::future::Future;
use futures::stream::Stream;
use hyper::body::Payload;
use hyper::server::conn::Http as HyperHttp;
use hyper::service::{NewService, Service};
use hyper::Body;
use tokio_core::reactor::Core;
use tokio_uds::UnixListener;

/// An instance of a server created through `Http::bind`.
//
/// This structure is used to create instances of Servers to spawn off tasks
/// which handle a connection to an HTTP server.
pub struct Server<S>
where
    S: NewService<ReqBody = Body> + Send + 'static,
{
    new_service: S,
    core: Core,
    listener: UnixListener,
}

impl<S> Server<S>
where
    S: NewService<ReqBody = Body, ResBody = Body, Error = io::Error> + Send + Sync + 'static,
    S::InitError: fmt::Display,
    <S::Service as Service>::Future: Send,
{
    /// Return the path name of the underlying domain socket
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.listener.local_addr()
    }

    /// Start listening for incomming connections
    pub fn run(self) -> io::Result<()> {
        let Server {
            new_service,
            mut core,
            listener,
        } = self;

        let server = listener.incoming().for_each(move |sock| {
            new_service
                .new_service()
                .map_err(|e| {
                    io::Error::new(
                        io::ErrorKind::Other,
                        format!("failed to create service: {}", e),
                    )
                })
                .and_then(|service| {
                    HyperHttp::new()
                        .serve_connection(sock, service)
                        .map_err(|e| {
                            io::Error::new(
                                io::ErrorKind::Other,
                                format!("failed to serve connection: {}", e),
                            )
                        })
                })
        });

        core.run(server)
    }
}

/// A type that provides a factory interface for creating
/// unix socket based Servers
///
/// # examples
///
/// ```no_run
/// extern crate hyper;
/// extern crate hyperlocal;
///
/// //let server = hyperlocal::Http::new().bind(
///  // "path/to/socket",
///  //  || Ok(HelloWorld)
/// //)
///
/// ```
#[derive(Clone)]
pub struct Http;

impl Http {
    /// Creates a new instance of the HTTP protocol, ready to spawn a server or
    /// start accepting connections.
    pub fn new() -> Self {
        Http
    }

    /// Binds a new server instance to a unix domain socket path
    /// If the provided path exists this method will yield an error
    pub fn bind<P, S, B>(&self, path: P, new_service: S) -> io::Result<Server<S>>
    where
        P: AsRef<Path>,
        S: NewService<ReqBody = Body, ResBody = B> + Send + 'static,
        S::Error: Into<Box<error::Error + Send + Sync>>,
        S::Service: Send,
        <S::Service as Service>::Future: Send + 'static,
        B: Payload,
    {
        let core = Core::new()?;
        let listener = UnixListener::bind(path.as_ref())?;

        Ok(Server {
            core,
            listener,
            new_service,
        })
    }
}
<commit_msg>update doc<commit_after>//! Hyper server bindings for unix domain sockets

// Std lib
use std::error;
use std::fmt;
use std::io;
use std::os::unix::net::SocketAddr;
use std::path::Path;

// Third party
use futures::future::Future;
use futures::stream::Stream;
use hyper::body::Payload;
use hyper::server::conn::Http as HyperHttp;
use hyper::service::{NewService, Service};
use hyper::Body;
use tokio_core::reactor::Core;
use tokio_uds::UnixListener;

/// An instance of a server created through `Http::bind`.
//
/// This structure is used to create instances of Servers to spawn off tasks
/// which handle a connection to an HTTP server.
pub struct Server<S>
where
    S: NewService<ReqBody = Body> + Send + 'static,
{
    new_service: S,
    core: Core,
    listener: UnixListener,
}

impl<S> Server<S>
where
    S: NewService<ReqBody = Body, ResBody = Body, Error = io::Error> + Send + Sync + 'static,
    S::InitError: fmt::Display,
    <S::Service as Service>::Future: Send,
{
    /// Return the of the underlying socket address this server is listening on
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.listener.local_addr()
    }

    /// Start listening for incomming connections
    pub fn run(self) -> io::Result<()> {
        let Server {
            new_service,
            mut core,
            listener,
        } = self;

        let server = listener.incoming().for_each(move |sock| {
            new_service
                .new_service()
                .map_err(|e| {
                    io::Error::new(
                        io::ErrorKind::Other,
                        format!("failed to create service: {}", e),
                    )
                })
                .and_then(|service| {
                    HyperHttp::new()
                        .serve_connection(sock, service)
                        .map_err(|e| {
                            io::Error::new(
                                io::ErrorKind::Other,
                                format!("failed to serve connection: {}", e),
                            )
                        })
                })
        });

        core.run(server)
    }
}

/// A type that provides a factory interface for creating
/// unix socket based Servers
///
/// # examples
///
/// ```no_run
/// extern crate hyper;
/// extern crate hyperlocal;
///
/// //let server = hyperlocal::Http::new().bind(
///  // "path/to/socket",
///  //  || Ok(HelloWorld)
/// //)
///
/// ```
#[derive(Clone)]
pub struct Http;

impl Http {
    /// Creates a new instance of the HTTP protocol, ready to spawn a server or
    /// start accepting connections.
    pub fn new() -> Self {
        Http
    }

    /// Binds a new server instance to a unix domain socket path
    /// If the provided path exists this method will yield an error
    pub fn bind<P, S, B>(&self, path: P, new_service: S) -> io::Result<Server<S>>
    where
        P: AsRef<Path>,
        S: NewService<ReqBody = Body, ResBody = B> + Send + 'static,
        S::Error: Into<Box<error::Error + Send + Sync>>,
        S::Service: Send,
        <S::Service as Service>::Future: Send + 'static,
        B: Payload,
    {
        let core = Core::new()?;
        let listener = UnixListener::bind(path.as_ref())?;

        Ok(Server {
            core,
            listener,
            new_service,
        })
    }
}
<|endoftext|>


<commit_before>use ritual_common::errors::{bail, err_msg, Result, ResultExt};

use crate::config::Config;
use crate::cpp_checker::cpp_checker_step;
use crate::cpp_explicit_destructors::add_explicit_destructors_step;
use crate::cpp_ffi_generator::cpp_ffi_generator_step;
use crate::cpp_parser::cpp_parser_step;
use crate::cpp_template_instantiator::find_template_instantiations_step;
use crate::cpp_template_instantiator::instantiate_templates_step;
use crate::crate_writer::crate_writer_step;
use crate::database::{CppDatabaseItem, Database};
use crate::rust_name_resolver::clear_rust_info_step;
use crate::rust_name_resolver::rust_name_resolver_step;
use crate::type_allocation_places::choose_allocation_places_step;
use crate::workspace::Workspace;
use itertools::Itertools;
use log::{error, info};
use ritual_common::utils::MapIfOk;
use std::cmp::Ordering;
use std::fmt;
use std::iter::once;
use std::path::PathBuf;
//use cpp_post_processor::cpp_post_process;

/// Creates output and cache directories if they don't exist.
/// Returns `Err` if any path in `config` is invalid or relative.
fn check_all_paths(config: &Config) -> Result<()> {
    let check_dir = |path: &PathBuf| -> Result<()> {
        if !path.is_absolute() {
            bail!(
                "Only absolute paths allowed. Relative path: {}",
                path.display()
            );
        }
        if !path.exists() {
            bail!("Directory doesn't exist: {}", path.display());
        }
        if !path.is_dir() {
            bail!("Path is not a directory: {}", path.display());
        }
        Ok(())
    };

    if let Some(path) = config.crate_template_path() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().include_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().lib_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().framework_paths() {
        check_dir(path)?;
    }
    for path in config.target_include_paths() {
        check_dir(path)?;
    }
    Ok(())
}

pub struct ProcessorData<'a> {
    pub workspace: &'a mut Workspace,
    pub config: &'a Config,
    pub current_database: &'a mut Database,
    pub dep_databases: &'a [Database],
}

impl<'a> ProcessorData<'a> {
    pub fn all_databases(&self) -> Vec<&Database> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .collect()
    }
    pub fn all_items(&self) -> Vec<&CppDatabaseItem> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .flat_map(|d| d.cpp_items.iter())
            .collect()
    }
}

pub struct ProcessingStep {
    pub name: String,
    pub is_const: bool,
    pub function: Box<Fn(&mut ProcessorData) -> Result<()>>,
}

impl fmt::Debug for ProcessingStep {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ProcessingStep")
            .field("name", &self.name)
            .field("is_const", &self.is_const)
            .finish()
    }
}

#[derive(Debug)]
pub struct ProcessingSteps {
    all_steps: Vec<ProcessingStep>,
    main_procedure: Vec<String>,
}

impl Default for ProcessingSteps {
    fn default() -> Self {
        let main_steps = vec![
            cpp_parser_step(),
            add_explicit_destructors_step(),
            choose_allocation_places_step(),
            find_template_instantiations_step(),
            instantiate_templates_step(),
            cpp_ffi_generator_step(),
            // TODO: generate_slot_wrappers
            cpp_checker_step(),
            rust_name_resolver_step(),
            crate_writer_step(),
        ];

        let main_procedure = main_steps.iter().map(|s| s.name.clone()).collect();

        let mut all_steps = main_steps;
        all_steps.extend(vec![
            steps::print_database(),
            steps::clear_ffi(),
            clear_rust_info_step(),
        ]);
        Self {
            all_steps,
            main_procedure,
        }
    }
}

impl ProcessingSteps {
    pub fn add_after(&mut self, after: &[&str], step: ProcessingStep) -> Result<()> {
        let indexes: Vec<usize> = after.iter().map_if_ok(|s| {
            self.main_procedure
                .iter()
                .position(|a| a == s)
                .ok_or_else(|| err_msg(format!("requested step not found: {}", s)))
        })?;

        let max_index = indexes
            .into_iter()
            .max()
            .ok_or_else(|| err_msg("no steps provided"))?;
        self.main_procedure.insert(max_index + 1, step.name.clone());
        self.all_steps.push(step);
        Ok(())
    }
}

impl ProcessingStep {
    pub fn new<S: Into<String>, F: 'static + Fn(&mut ProcessorData) -> Result<()>>(
        name: S,
        function: F,
    ) -> ProcessingStep {
        ProcessingStep {
            name: name.into(),
            is_const: false,
            function: Box::new(function),
        }
    }
    pub fn new_const<S: Into<String>, F: 'static + Fn(&mut ProcessorData) -> Result<()>>(
        name: S,
        function: F,
    ) -> ProcessingStep {
        let name = name.into();
        ProcessingStep {
            name,
            is_const: true,
            function: Box::new(function),
        }
    }
}

mod steps {
    use crate::processor::ProcessingStep;
    use log::trace;

    pub fn print_database() -> ProcessingStep {
        ProcessingStep::new_const("print_database", |data| {
            for item in &data.current_database.cpp_items {
                trace!(
                    "[database_item] cpp_data={}; source={:?}",
                    item.cpp_data.to_string(),
                    item.source
                );
                for ffi_item in &item.ffi_items {
                    trace!("[database_item]   ffi_item={:?}", ffi_item);
                }
            }
            Ok(())
        })
    }
    pub fn clear_ffi() -> ProcessingStep {
        ProcessingStep::new("clear_ffi", |data| {
            for item in &mut data.current_database.cpp_items {
                item.ffi_items.clear();
                item.is_cpp_ffi_processed = false;
            }
            data.current_database.next_ffi_id = 0;
            Ok(())
        })
    }
}

#[derive(Debug)]
struct MainItemRef<'a> {
    step: &'a ProcessingStep,
    run_after: &'a [String],
}

impl PartialEq for MainItemRef<'_> {
    fn eq(&self, other: &MainItemRef) -> bool {
        self.step.name == other.step.name
    }
}

impl PartialOrd for MainItemRef<'_> {
    fn partial_cmp(&self, other: &MainItemRef) -> Option<Ordering> {
        if self.run_after.contains(&other.step.name) {
            Some(Ordering::Greater)
        } else {
            Some(Ordering::Less)
        }
    }
}
impl Eq for MainItemRef<'_> {}
impl Ord for MainItemRef<'_> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn process(workspace: &mut Workspace, config: &Config, step_names: &[String]) -> Result<()> {
    info!("Processing crate: {}", config.crate_properties().name());
    check_all_paths(&config)?;

    // TODO: allow to remove any prefix through `Config` (#25)
    #[allow(unused_variables)]
    let remove_qt_prefix = config.crate_properties().name().starts_with("qt_");

    info!("Loading current crate data");
    let mut current_database = workspace
        .load_or_create_crate(config.crate_properties().name())
        .with_context(|_| "failed to load current crate data")?;

    if !config.dependent_cpp_crates().is_empty() {
        info!("Loading dependencies");
    }
    let dependent_cpp_crates = config.dependent_cpp_crates().iter().map_if_ok(|name| {
        workspace
            .load_crate(name)
            .with_context(|_| "failed to load dependency")
    })?;

    let mut current_database_saved = true;

    if current_database.crate_version != config.crate_properties().version() {
        current_database.crate_version = config.crate_properties().version().to_string();
        current_database_saved = false;
    }

    let mut steps_result = Ok(());

    for step_name in step_names {
        if steps_result.is_err() {
            break;
        }

        let step_names = if step_name == "main" {
            config.processing_steps().main_procedure.clone()
        } else {
            vec![step_name.to_string()]
        };

        for step_name in step_names {
            let step = if let Some(item) = config
                .processing_steps()
                .all_steps
                .iter()
                .find(|item| item.name == step_name)
            {
                item
            } else {
                bail!(
                    "Unknown operation: {}. Supported operations: main, {}.",
                    step_name,
                    config
                        .processing_steps()
                        .all_steps
                        .iter()
                        .map(|item| &item.name)
                        .join(", ")
                );
            };

            info!("Running processing step: {}", &step.name);

            let mut data = ProcessorData {
                workspace,
                current_database: &mut current_database,
                dep_databases: &dependent_cpp_crates,
                config,
            };

            if !step.is_const {
                current_database_saved = false;
            }

            if let Err(err) = (step.function)(&mut data) {
                steps_result = Err(err);
                error!("Step failed! Aborting...");
                break;
            }
        }
    }

    /*
    if exec_config.write_dependencies_local_paths {
    log::status(
    "Output Cargo.toml file will contain local paths of used dependencies \
      (use --no-local-paths to disable).",
    );
    } else {
    log::status(
    "Local paths will not be written to the output crate. Make sure all dependencies \
      are published before trying to compile the crate.",
    );
    }

    */

    /*
    parser_cpp_data.detect_signals_and_slots(
      &dependent_cpp_crates,
    )?;
    // TODO: rename `cpp_data_filters` to `parser_cpp_data_filters`
    if config.has_cpp_data_filters() {
      log::status("Running custom filters for C++ parser data");
      for filter in config.cpp_data_filters() {
        filter(&mut parser_cpp_data).with_context(
          || "cpp_data_filter failed",
        )?;
      }
    }

    log::status("Post-processing parse result");
    let r = cpp_post_process(
      parser_cpp_data,
      dependent_cpp_crates,
      config.type_allocation_places(),
    )?;

    //...

    */

    for database in dependent_cpp_crates {
        workspace.put_crate(database, true);
    }

    if !current_database_saved {
        info!("Saving data");
    }

    workspace.put_crate(current_database, current_database_saved);
    workspace.save_data()?;

    steps_result
}
<commit_msg>add step for building generated crate<commit_after>use ritual_common::errors::{bail, err_msg, Result, ResultExt};

use crate::config::Config;
use crate::cpp_checker::cpp_checker_step;
use crate::cpp_explicit_destructors::add_explicit_destructors_step;
use crate::cpp_ffi_generator::cpp_ffi_generator_step;
use crate::cpp_parser::cpp_parser_step;
use crate::cpp_template_instantiator::find_template_instantiations_step;
use crate::cpp_template_instantiator::instantiate_templates_step;
use crate::crate_writer::crate_writer_step;
use crate::database::{CppDatabaseItem, Database};
use crate::rust_name_resolver::clear_rust_info_step;
use crate::rust_name_resolver::rust_name_resolver_step;
use crate::type_allocation_places::choose_allocation_places_step;
use crate::workspace::Workspace;
use itertools::Itertools;
use log::{error, info};
use ritual_common::utils::MapIfOk;
use std::cmp::Ordering;
use std::fmt;
use std::iter::once;
use std::path::PathBuf;
//use cpp_post_processor::cpp_post_process;

/// Creates output and cache directories if they don't exist.
/// Returns `Err` if any path in `config` is invalid or relative.
fn check_all_paths(config: &Config) -> Result<()> {
    let check_dir = |path: &PathBuf| -> Result<()> {
        if !path.is_absolute() {
            bail!(
                "Only absolute paths allowed. Relative path: {}",
                path.display()
            );
        }
        if !path.exists() {
            bail!("Directory doesn't exist: {}", path.display());
        }
        if !path.is_dir() {
            bail!("Path is not a directory: {}", path.display());
        }
        Ok(())
    };

    if let Some(path) = config.crate_template_path() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().include_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().lib_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().framework_paths() {
        check_dir(path)?;
    }
    for path in config.target_include_paths() {
        check_dir(path)?;
    }
    Ok(())
}

pub struct ProcessorData<'a> {
    pub workspace: &'a mut Workspace,
    pub config: &'a Config,
    pub current_database: &'a mut Database,
    pub dep_databases: &'a [Database],
}

impl<'a> ProcessorData<'a> {
    pub fn all_databases(&self) -> Vec<&Database> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .collect()
    }
    pub fn all_items(&self) -> Vec<&CppDatabaseItem> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .flat_map(|d| d.cpp_items.iter())
            .collect()
    }
}

pub struct ProcessingStep {
    pub name: String,
    pub is_const: bool,
    pub function: Box<Fn(&mut ProcessorData) -> Result<()>>,
}

impl fmt::Debug for ProcessingStep {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ProcessingStep")
            .field("name", &self.name)
            .field("is_const", &self.is_const)
            .finish()
    }
}

#[derive(Debug)]
pub struct ProcessingSteps {
    all_steps: Vec<ProcessingStep>,
    main_procedure: Vec<String>,
}

impl Default for ProcessingSteps {
    fn default() -> Self {
        let main_steps = vec![
            cpp_parser_step(),
            add_explicit_destructors_step(),
            choose_allocation_places_step(),
            find_template_instantiations_step(),
            instantiate_templates_step(),
            cpp_ffi_generator_step(),
            // TODO: generate_slot_wrappers
            cpp_checker_step(),
            rust_name_resolver_step(),
            crate_writer_step(),
            steps::build_crate(),
        ];

        let main_procedure = main_steps.iter().map(|s| s.name.clone()).collect();

        let mut all_steps = main_steps;
        all_steps.extend(vec![
            steps::print_database(),
            steps::clear_ffi(),
            clear_rust_info_step(),
        ]);
        Self {
            all_steps,
            main_procedure,
        }
    }
}

impl ProcessingSteps {
    pub fn add_after(&mut self, after: &[&str], step: ProcessingStep) -> Result<()> {
        let indexes: Vec<usize> = after.iter().map_if_ok(|s| {
            self.main_procedure
                .iter()
                .position(|a| a == s)
                .ok_or_else(|| err_msg(format!("requested step not found: {}", s)))
        })?;

        let max_index = indexes
            .into_iter()
            .max()
            .ok_or_else(|| err_msg("no steps provided"))?;
        self.main_procedure.insert(max_index + 1, step.name.clone());
        self.all_steps.push(step);
        Ok(())
    }
}

impl ProcessingStep {
    pub fn new<S: Into<String>, F: 'static + Fn(&mut ProcessorData) -> Result<()>>(
        name: S,
        function: F,
    ) -> ProcessingStep {
        ProcessingStep {
            name: name.into(),
            is_const: false,
            function: Box::new(function),
        }
    }
    pub fn new_const<S: Into<String>, F: 'static + Fn(&mut ProcessorData) -> Result<()>>(
        name: S,
        function: F,
    ) -> ProcessingStep {
        let name = name.into();
        ProcessingStep {
            name,
            is_const: true,
            function: Box::new(function),
        }
    }
}

mod steps {
    use crate::processor::ProcessingStep;
    use log::trace;
    use ritual_common::utils::run_command;
    use std::process::Command;

    pub fn print_database() -> ProcessingStep {
        ProcessingStep::new_const("print_database", |data| {
            for item in &data.current_database.cpp_items {
                trace!(
                    "[database_item] cpp_data={}; source={:?}",
                    item.cpp_data.to_string(),
                    item.source
                );
                for ffi_item in &item.ffi_items {
                    trace!("[database_item]   ffi_item={:?}", ffi_item);
                }
            }
            Ok(())
        })
    }

    pub fn clear_ffi() -> ProcessingStep {
        ProcessingStep::new("clear_ffi", |data| {
            for item in &mut data.current_database.cpp_items {
                item.ffi_items.clear();
                item.is_cpp_ffi_processed = false;
            }
            data.current_database.next_ffi_id = 0;
            Ok(())
        })
    }

    pub fn build_crate() -> ProcessingStep {
        ProcessingStep::new("build_crate", |data| {
            let path = data
                .workspace
                .crate_path(&data.current_database.crate_name)?;
            for cargo_cmd in &["update", "build", /*"test",*/ "doc"] {
                let mut command = Command::new("cargo");
                command.arg(cargo_cmd);
                command.current_dir(&path);
                run_command(&mut command)?;
            }
            Ok(())
        })
    }
}

#[derive(Debug)]
struct MainItemRef<'a> {
    step: &'a ProcessingStep,
    run_after: &'a [String],
}

impl PartialEq for MainItemRef<'_> {
    fn eq(&self, other: &MainItemRef) -> bool {
        self.step.name == other.step.name
    }
}

impl PartialOrd for MainItemRef<'_> {
    fn partial_cmp(&self, other: &MainItemRef) -> Option<Ordering> {
        if self.run_after.contains(&other.step.name) {
            Some(Ordering::Greater)
        } else {
            Some(Ordering::Less)
        }
    }
}
impl Eq for MainItemRef<'_> {}
impl Ord for MainItemRef<'_> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn process(workspace: &mut Workspace, config: &Config, step_names: &[String]) -> Result<()> {
    info!("Processing crate: {}", config.crate_properties().name());
    check_all_paths(&config)?;

    // TODO: allow to remove any prefix through `Config` (#25)
    #[allow(unused_variables)]
    let remove_qt_prefix = config.crate_properties().name().starts_with("qt_");

    info!("Loading current crate data");
    let mut current_database = workspace
        .load_or_create_crate(config.crate_properties().name())
        .with_context(|_| "failed to load current crate data")?;

    if !config.dependent_cpp_crates().is_empty() {
        info!("Loading dependencies");
    }
    let dependent_cpp_crates = config.dependent_cpp_crates().iter().map_if_ok(|name| {
        workspace
            .load_crate(name)
            .with_context(|_| "failed to load dependency")
    })?;

    let mut current_database_saved = true;

    if current_database.crate_version != config.crate_properties().version() {
        current_database.crate_version = config.crate_properties().version().to_string();
        current_database_saved = false;
    }

    let mut steps_result = Ok(());

    for step_name in step_names {
        if steps_result.is_err() {
            break;
        }

        let step_names = if step_name == "main" {
            config.processing_steps().main_procedure.clone()
        } else if step_name.starts_with("from:") {
            let start_step = &step_name["from:".len()..];
            let start_index = config
                .processing_steps()
                .main_procedure
                .iter()
                .position(|s| s == start_step)
                .ok_or_else(|| err_msg(format!("requested step not found: {}", start_step)))?;
            config.processing_steps().main_procedure[start_index..].to_vec()
        } else {
            vec![step_name.to_string()]
        };

        for step_name in step_names {
            let step = if let Some(item) = config
                .processing_steps()
                .all_steps
                .iter()
                .find(|item| item.name == step_name)
            {
                item
            } else {
                bail!(
                    "Unknown operation: {}. Supported operations: main, {}.",
                    step_name,
                    config
                        .processing_steps()
                        .all_steps
                        .iter()
                        .map(|item| &item.name)
                        .join(", ")
                );
            };

            info!("Running processing step: {}", &step.name);

            let mut data = ProcessorData {
                workspace,
                current_database: &mut current_database,
                dep_databases: &dependent_cpp_crates,
                config,
            };

            if !step.is_const {
                current_database_saved = false;
            }

            if let Err(err) = (step.function)(&mut data) {
                steps_result = Err(err);
                error!("Step failed! Aborting...");
                break;
            }
        }
    }

    /*
    if exec_config.write_dependencies_local_paths {
    log::status(
    "Output Cargo.toml file will contain local paths of used dependencies \
      (use --no-local-paths to disable).",
    );
    } else {
    log::status(
    "Local paths will not be written to the output crate. Make sure all dependencies \
      are published before trying to compile the crate.",
    );
    }

    */

    /*
    parser_cpp_data.detect_signals_and_slots(
      &dependent_cpp_crates,
    )?;
    // TODO: rename `cpp_data_filters` to `parser_cpp_data_filters`
    if config.has_cpp_data_filters() {
      log::status("Running custom filters for C++ parser data");
      for filter in config.cpp_data_filters() {
        filter(&mut parser_cpp_data).with_context(
          || "cpp_data_filter failed",
        )?;
      }
    }

    log::status("Post-processing parse result");
    let r = cpp_post_process(
      parser_cpp_data,
      dependent_cpp_crates,
      config.type_allocation_places(),
    )?;

    //...

    */

    for database in dependent_cpp_crates {
        workspace.put_crate(database, true);
    }

    if !current_database_saved {
        info!("Saving data");
    }

    workspace.put_crate(current_database, current_database_saved);
    workspace.save_data()?;

    steps_result
}
<|endoftext|>