<commit_before>use core::ptr::{read, write};

use common::debug;

use drivers::pciconfig::*;

use programs::session::SessionItem;

#[repr(packed)]
struct SETUP {
    request_type: u8,
    request: u8,
    value: u16,
    index: u16,
    len: u16,
}

#[repr(packed)]
struct QTD {
    next: u32,
    next_alt: u32,
    token: u32,
    buffers: [u32; 5],
}

#[repr(packed)]
struct QueueHead {
    next: u32,
    characteristics: u32,
    capabilities: u32,
    qtd_ptr: u32,
    qtd: QTD,
}

pub struct EHCI {
    pub pci: PCIConfig,
    pub base: usize,
    pub memory_mapped: bool,
    pub irq: u8,
}

impl SessionItem for EHCI {
    #[allow(non_snake_case)]
    fn on_irq(&mut self, irq: u8) {
        if irq == self.irq {
            //debug::d("EHCI handle");

            unsafe {
                let CAPLENGTH = self.base as *mut u8;

                let opbase = self.base + read(CAPLENGTH) as usize;

                let USBSTS = (opbase + 4) as *mut u32;
                //debug::d(" USBSTS ");
                //debug::dh(*USBSTS as usize);

                write(USBSTS, 0b111111);

                //debug::d(" USBSTS ");
                //debug::dh(*USBSTS as usize);

                //let FRINDEX = (opbase + 0xC) as *mut u32;
                //debug::d(" FRINDEX ");
                //debug::dh(*FRINDEX as usize);
            }

            //debug::dl();
        }
    }
}

impl EHCI {
    #[allow(non_snake_case)]
    pub unsafe fn init(&mut self) {
        debug::d("EHCI on: ");
        debug::dh(self.base);
        if self.memory_mapped {
            debug::d(" memory mapped");
        } else {
            debug::d(" port mapped");
        }
        debug::d(" IRQ: ");
        debug::dbh(self.irq);

        return;

        /*

        let pci = &mut self.pci;

        pci.flag(4, 4, true); // Bus master

        let CAPLENGTH = self.base as *mut u8;
        let HCSPARAMS = (self.base + 4) as *mut u32;
        let HCCPARAMS = (self.base + 8) as *mut u32;

        debug::d(" CAPLENGTH ");
        debug::dd(read(CAPLENGTH) as usize);

        debug::d(" HCSPARAMS ");
        debug::dh(read(HCSPARAMS) as usize);

        debug::d(" HCCPARAMS ");
        debug::dh(read(HCCPARAMS) as usize);

        let ports = (read(HCSPARAMS) & 0b1111) as usize;
        debug::d(" PORTS ");
        debug::dd(ports);

        let eecp = ((read(HCCPARAMS) >> 8) & 0xFF) as u8;
        debug::d(" EECP ");
        debug::dh(eecp as usize);

        debug::dl();

        if eecp > 0 {
            if pci.read(eecp) & ((1 << 24) | (1 << 16)) == (1 << 16) {
                debug::d("Taking Ownership");
                debug::d(" ");
                debug::dh(pci.read(eecp) as usize);

                pci.flag(eecp, 1 << 24, true);

                debug::d(" ");
                debug::dh(pci.read(eecp) as usize);
                debug::dl();

                debug::d("Waiting");
                debug::d(" ");
                debug::dh(pci.read(eecp) as usize);

                loop {
                    if pci.read(eecp) & ((1 << 24) | (1 << 16)) == (1 << 24) {
                        break;
                    }
                }

                debug::d(" ");
                debug::dh(pci.read(eecp) as usize);
                debug::dl();
            }
        }

        let opbase = self.base + *CAPLENGTH as usize;

        let USBCMD = opbase as *mut u32;
        let USBSTS = (opbase + 4) as *mut u32;
        let USBINTR = (opbase + 8) as *mut u32;
        let FRINDEX = (opbase + 0xC) as *mut u32;
        let CTRLDSSEGMENT = (opbase + 0x10) as *mut u32;
        let PERIODICLISTBASE = (opbase + 0x14) as *mut u32;
        let ASYNCLISTADDR = (opbase + 0x18) as *mut u32;
        let CONFIGFLAG = (opbase + 0x40) as *mut u32;
        let PORTSC = (opbase + 0x44) as *mut u32;

        if read(USBSTS) & (1 << 12) == 0 {
            debug::d("Halting");
            debug::d(" CMD ");
            debug::dh(read(USBCMD) as usize);

            debug::d(" STS ");
            debug::dh(read(USBSTS) as usize);

            write(USBCMD, read(USBCMD) & 0xFFFFFFF0);

            debug::d(" CMD ");
            debug::dh(*USBCMD as usize);

            debug::d(" STS ");
            debug::dh(*USBSTS as usize);
            debug::dl();

            debug::d("Waiting");
            loop {
                if volatile_load(USBSTS) & (1 << 12) == (1 << 12) {
                    break;
                }
            }

            debug::d(" CMD ");
            debug::dh(read(USBCMD) as usize);

            debug::d(" STS ");
            debug::dh(read(USBSTS) as usize);
            debug::dl();
        }

        debug::d("Resetting");
        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);

        write(USBCMD, read(USBCMD) | (1 << 1));

        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);
        debug::dl();

        debug::d("Waiting");
        loop {
            if volatile_load(USBCMD) & (1 << 1) == 0 {
                break;
            }
        }

        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);
        debug::dl();

        debug::d("Enabling");
        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);

        write(USBINTR, 0b111111);

        write(USBCMD, read(USBCMD) | 1);
        write(CONFIGFLAG, 1);

        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);
        debug::dl();

        debug::d("Waiting");
        loop {
            if volatile_load(USBSTS) & (1 << 12) == 0 {
                break;
            }
        }

        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);
        debug::dl();

        let disable = scheduler::start_ints();
        Duration::new(0, 100 * time::NANOS_PER_MILLI).sleep();
        scheduler::end_ints(disable);

        for i in 0..ports as isize {
            debug::dd(i as usize);
            debug::d(": ");
            debug::dh(read(PORTSC.offset(i)) as usize);
            debug::dl();

            if read(PORTSC.offset(i)) & 1 == 1 {
                debug::d("Device on port ");
                debug::dd(i as usize);
                debug::d(" ");
                debug::dh(read(PORTSC.offset(i)) as usize);
                debug::dl();

                if read(PORTSC.offset(i)) & (1 << 1) == (1 << 1) {
                    debug::d("Connection Change");
                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);

                    write(PORTSC.offset(i), read(PORTSC.offset(i)) | (1 << 1));

                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);
                    debug::dl();
                }

                if read(PORTSC.offset(i)) & (1 << 2) == 0 {
                    debug::d("Reset");
                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);

                    write(PORTSC.offset(i), read(PORTSC.offset(i)) | (1 << 8));

                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);

                    write(PORTSC.offset(i),
                          read(PORTSC.offset(i)) & 0xFFFFFEFF);

                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);
                    debug::dl();

                    debug::d("Wait");
                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);

                    loop {
                        if volatile_load(PORTSC.offset(i)) & (1 << 8) == 0 {
                            break;
                        } else {
                            volatile_store(PORTSC.offset(i),
                                           volatile_load(PORTSC.offset(i)) & 0xFFFFFEFF);
                        }
                    }

                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);
                    debug::dl();
                }

                if read(PORTSC.offset(i)) & (1 << 2) == (1 << 2) {
                    debug::d("Port Enabled ");
                    debug::dh(read(PORTSC.offset(i)) as usize);
                    debug::dl();

                    /*
                    let out_qtd = alloc(size_of::<QTD>()) as *mut QTD;
                    ptr::write(out_qtd, QTD {
                        next: 1,
                        next_alt: 1,
                        token: (1 << 31) | (0b11 << 10) | 0x80,
                        buffers: [0, 0, 0, 0, 0]
                    });

                    let in_data = alloc(64) as *mut u8;
                    for i in 0..64 {
                        *in_data.offset(i) = 0;
                    }

                    let in_qtd = alloc(size_of::<QTD>()) as *mut QTD;
                    ptr::write(in_qtd, QTD {
                        next: out_qtd as u32,
                        next_alt: 1,
                        token: (1 << 31) | (64 << 16) | (0b11 << 10) | (0b01 << 8) | 0x80,
                        buffers: [in_data as u32, 0, 0, 0, 0]
                    });

                    let setup_packet = alloc(size_of::<SETUP>()) as *mut SETUP;
                    ptr::write(setup_packet, SETUP {
                        request_type: 0b10000000,
                        request: 6,
                        value: 1 << 8,
                        index: 0,
                        len: 64
                    });

                    let setup_qtd = alloc(size_of::<QTD>()) as *mut QTD;
                    ptr::write(setup_qtd, QTD {
                        next: in_qtd as u32,
                        next_alt: 1,
                        token: ((size_of::<SETUP>() as u32) << 16) | (0b11 << 10) | (0b10 << 8) | 0x80,
                        buffers: [setup_packet as u32, 0, 0, 0, 0]
                    });

                    let queuehead = alloc(size_of::<QueueHead>()) as *mut QueueHead;
                    ptr::write(queuehead, QueueHead {
                        next: 1,
                        characteristics: (64 << 16) | (1 << 15) | (1 << 14) | (0b10 << 12),
                        capabilities: (0b11 << 30),
                        qtd_ptr: setup_qtd as u32,
                        qtd: ptr::read(setup_qtd)
                    });

                    debug::d("Prepare");
                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" PTR ");
                        debug::dh(queuehead as usize);
                    debug::dl();

                    debug::d("Send");
                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);

                        *ASYNCLISTADDR = queuehead as u32;

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);

                        *USBCMD |= (1 << 5);

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);

                        *USBCMD |= 1;

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);
                    debug::dl();

                    debug::d("Wait");
                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);
                        debug::dl();

                        loop {
                            if *USBSTS & 0xA000  == 0 {
                                break;
                            }
                        }

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);
                    debug::dl();

                    debug::d("Stop");
                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);

                        *USBCMD &= 0xFFFFFFFF - (1 << 5);

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);
                    debug::dl();

                    d("Data");
                    for i in 0..64 {
                        debug::d(" ");
                        debug::dbh(*in_data.offset(i));
                    }
                    debug::dl();

                    //Only detect one device for testing
                    break;
                    */
                } else {
                    debug::d("Device not high-speed\n");
                }
            }
        }
        */
    }
}
<commit_msg>Missing newline<commit_after>use core::ptr::{read, write};

use common::debug;

use drivers::pciconfig::*;

use programs::session::SessionItem;

#[repr(packed)]
struct SETUP {
    request_type: u8,
    request: u8,
    value: u16,
    index: u16,
    len: u16,
}

#[repr(packed)]
struct QTD {
    next: u32,
    next_alt: u32,
    token: u32,
    buffers: [u32; 5],
}

#[repr(packed)]
struct QueueHead {
    next: u32,
    characteristics: u32,
    capabilities: u32,
    qtd_ptr: u32,
    qtd: QTD,
}

pub struct EHCI {
    pub pci: PCIConfig,
    pub base: usize,
    pub memory_mapped: bool,
    pub irq: u8,
}

impl SessionItem for EHCI {
    #[allow(non_snake_case)]
    fn on_irq(&mut self, irq: u8) {
        if irq == self.irq {
            //debug::d("EHCI handle");

            unsafe {
                let CAPLENGTH = self.base as *mut u8;

                let opbase = self.base + read(CAPLENGTH) as usize;

                let USBSTS = (opbase + 4) as *mut u32;
                //debug::d(" USBSTS ");
                //debug::dh(*USBSTS as usize);

                write(USBSTS, 0b111111);

                //debug::d(" USBSTS ");
                //debug::dh(*USBSTS as usize);

                //let FRINDEX = (opbase + 0xC) as *mut u32;
                //debug::d(" FRINDEX ");
                //debug::dh(*FRINDEX as usize);
            }

            //debug::dl();
        }
    }
}

impl EHCI {
    #[allow(non_snake_case)]
    pub unsafe fn init(&mut self) {
        debug::d("EHCI on: ");
        debug::dh(self.base);
        if self.memory_mapped {
            debug::d(" memory mapped");
        } else {
            debug::d(" port mapped");
        }
        debug::d(" IRQ: ");
        debug::dbh(self.irq);

        debug::dl();
        return;

        /*

        let pci = &mut self.pci;

        pci.flag(4, 4, true); // Bus master

        let CAPLENGTH = self.base as *mut u8;
        let HCSPARAMS = (self.base + 4) as *mut u32;
        let HCCPARAMS = (self.base + 8) as *mut u32;

        debug::d(" CAPLENGTH ");
        debug::dd(read(CAPLENGTH) as usize);

        debug::d(" HCSPARAMS ");
        debug::dh(read(HCSPARAMS) as usize);

        debug::d(" HCCPARAMS ");
        debug::dh(read(HCCPARAMS) as usize);

        let ports = (read(HCSPARAMS) & 0b1111) as usize;
        debug::d(" PORTS ");
        debug::dd(ports);

        let eecp = ((read(HCCPARAMS) >> 8) & 0xFF) as u8;
        debug::d(" EECP ");
        debug::dh(eecp as usize);

        debug::dl();

        if eecp > 0 {
            if pci.read(eecp) & ((1 << 24) | (1 << 16)) == (1 << 16) {
                debug::d("Taking Ownership");
                debug::d(" ");
                debug::dh(pci.read(eecp) as usize);

                pci.flag(eecp, 1 << 24, true);

                debug::d(" ");
                debug::dh(pci.read(eecp) as usize);
                debug::dl();

                debug::d("Waiting");
                debug::d(" ");
                debug::dh(pci.read(eecp) as usize);

                loop {
                    if pci.read(eecp) & ((1 << 24) | (1 << 16)) == (1 << 24) {
                        break;
                    }
                }

                debug::d(" ");
                debug::dh(pci.read(eecp) as usize);
                debug::dl();
            }
        }

        let opbase = self.base + *CAPLENGTH as usize;

        let USBCMD = opbase as *mut u32;
        let USBSTS = (opbase + 4) as *mut u32;
        let USBINTR = (opbase + 8) as *mut u32;
        let FRINDEX = (opbase + 0xC) as *mut u32;
        let CTRLDSSEGMENT = (opbase + 0x10) as *mut u32;
        let PERIODICLISTBASE = (opbase + 0x14) as *mut u32;
        let ASYNCLISTADDR = (opbase + 0x18) as *mut u32;
        let CONFIGFLAG = (opbase + 0x40) as *mut u32;
        let PORTSC = (opbase + 0x44) as *mut u32;

        if read(USBSTS) & (1 << 12) == 0 {
            debug::d("Halting");
            debug::d(" CMD ");
            debug::dh(read(USBCMD) as usize);

            debug::d(" STS ");
            debug::dh(read(USBSTS) as usize);

            write(USBCMD, read(USBCMD) & 0xFFFFFFF0);

            debug::d(" CMD ");
            debug::dh(*USBCMD as usize);

            debug::d(" STS ");
            debug::dh(*USBSTS as usize);
            debug::dl();

            debug::d("Waiting");
            loop {
                if volatile_load(USBSTS) & (1 << 12) == (1 << 12) {
                    break;
                }
            }

            debug::d(" CMD ");
            debug::dh(read(USBCMD) as usize);

            debug::d(" STS ");
            debug::dh(read(USBSTS) as usize);
            debug::dl();
        }

        debug::d("Resetting");
        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);

        write(USBCMD, read(USBCMD) | (1 << 1));

        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);
        debug::dl();

        debug::d("Waiting");
        loop {
            if volatile_load(USBCMD) & (1 << 1) == 0 {
                break;
            }
        }

        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);
        debug::dl();

        debug::d("Enabling");
        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);

        write(USBINTR, 0b111111);

        write(USBCMD, read(USBCMD) | 1);
        write(CONFIGFLAG, 1);

        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);
        debug::dl();

        debug::d("Waiting");
        loop {
            if volatile_load(USBSTS) & (1 << 12) == 0 {
                break;
            }
        }

        debug::d(" CMD ");
        debug::dh(read(USBCMD) as usize);

        debug::d(" STS ");
        debug::dh(read(USBSTS) as usize);
        debug::dl();

        let disable = scheduler::start_ints();
        Duration::new(0, 100 * time::NANOS_PER_MILLI).sleep();
        scheduler::end_ints(disable);

        for i in 0..ports as isize {
            debug::dd(i as usize);
            debug::d(": ");
            debug::dh(read(PORTSC.offset(i)) as usize);
            debug::dl();

            if read(PORTSC.offset(i)) & 1 == 1 {
                debug::d("Device on port ");
                debug::dd(i as usize);
                debug::d(" ");
                debug::dh(read(PORTSC.offset(i)) as usize);
                debug::dl();

                if read(PORTSC.offset(i)) & (1 << 1) == (1 << 1) {
                    debug::d("Connection Change");
                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);

                    write(PORTSC.offset(i), read(PORTSC.offset(i)) | (1 << 1));

                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);
                    debug::dl();
                }

                if read(PORTSC.offset(i)) & (1 << 2) == 0 {
                    debug::d("Reset");
                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);

                    write(PORTSC.offset(i), read(PORTSC.offset(i)) | (1 << 8));

                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);

                    write(PORTSC.offset(i),
                          read(PORTSC.offset(i)) & 0xFFFFFEFF);

                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);
                    debug::dl();

                    debug::d("Wait");
                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);

                    loop {
                        if volatile_load(PORTSC.offset(i)) & (1 << 8) == 0 {
                            break;
                        } else {
                            volatile_store(PORTSC.offset(i),
                                           volatile_load(PORTSC.offset(i)) & 0xFFFFFEFF);
                        }
                    }

                    debug::d(" ");
                    debug::dh(read(PORTSC.offset(i)) as usize);
                    debug::dl();
                }

                if read(PORTSC.offset(i)) & (1 << 2) == (1 << 2) {
                    debug::d("Port Enabled ");
                    debug::dh(read(PORTSC.offset(i)) as usize);
                    debug::dl();

                    /*
                    let out_qtd = alloc(size_of::<QTD>()) as *mut QTD;
                    ptr::write(out_qtd, QTD {
                        next: 1,
                        next_alt: 1,
                        token: (1 << 31) | (0b11 << 10) | 0x80,
                        buffers: [0, 0, 0, 0, 0]
                    });

                    let in_data = alloc(64) as *mut u8;
                    for i in 0..64 {
                        *in_data.offset(i) = 0;
                    }

                    let in_qtd = alloc(size_of::<QTD>()) as *mut QTD;
                    ptr::write(in_qtd, QTD {
                        next: out_qtd as u32,
                        next_alt: 1,
                        token: (1 << 31) | (64 << 16) | (0b11 << 10) | (0b01 << 8) | 0x80,
                        buffers: [in_data as u32, 0, 0, 0, 0]
                    });

                    let setup_packet = alloc(size_of::<SETUP>()) as *mut SETUP;
                    ptr::write(setup_packet, SETUP {
                        request_type: 0b10000000,
                        request: 6,
                        value: 1 << 8,
                        index: 0,
                        len: 64
                    });

                    let setup_qtd = alloc(size_of::<QTD>()) as *mut QTD;
                    ptr::write(setup_qtd, QTD {
                        next: in_qtd as u32,
                        next_alt: 1,
                        token: ((size_of::<SETUP>() as u32) << 16) | (0b11 << 10) | (0b10 << 8) | 0x80,
                        buffers: [setup_packet as u32, 0, 0, 0, 0]
                    });

                    let queuehead = alloc(size_of::<QueueHead>()) as *mut QueueHead;
                    ptr::write(queuehead, QueueHead {
                        next: 1,
                        characteristics: (64 << 16) | (1 << 15) | (1 << 14) | (0b10 << 12),
                        capabilities: (0b11 << 30),
                        qtd_ptr: setup_qtd as u32,
                        qtd: ptr::read(setup_qtd)
                    });

                    debug::d("Prepare");
                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" PTR ");
                        debug::dh(queuehead as usize);
                    debug::dl();

                    debug::d("Send");
                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);

                        *ASYNCLISTADDR = queuehead as u32;

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);

                        *USBCMD |= (1 << 5);

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);

                        *USBCMD |= 1;

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);
                    debug::dl();

                    debug::d("Wait");
                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);
                        debug::dl();

                        loop {
                            if *USBSTS & 0xA000  == 0 {
                                break;
                            }
                        }

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);
                    debug::dl();

                    debug::d("Stop");
                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);

                        *USBCMD &= 0xFFFFFFFF - (1 << 5);

                        debug::d(" CMD ");
                        debug::dh(*USBCMD as usize);

                        debug::d(" STS ");
                        debug::dh(*USBSTS as usize);
                    debug::dl();

                    d("Data");
                    for i in 0..64 {
                        debug::d(" ");
                        debug::dbh(*in_data.offset(i));
                    }
                    debug::dl();

                    //Only detect one device for testing
                    break;
                    */
                } else {
                    debug::d("Device not high-speed\n");
                }
            }
        }
        */
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use library::*;
use parser::is_empty_c_type;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index
            .iter()
            .filter_map(|(name, &id)| if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            })
            .collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
        self.resolve_class_structs();
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index
            .iter()
            .flat_map(|(name, &id)| {
                let name = name.clone();
                self.namespace(id)
                    .unresolved()
                    .into_iter()
                    .map(move |s| format!("{}.{}", name, s))
            })
            .collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) {
                return;
            }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) => {
                    update_empty_signals_c_types(&mut klass.signals, &c_types)
                }
                Type::Interface(ref mut iface) => {
                    update_empty_signals_c_types(&mut iface.signals, &c_types)
                }
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(
        &self,
        signals: &[Signal],
        c_types: &mut DetectedCTypes,
    ) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) {
                detected = true;
            }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) {
                detected = true;
            }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) {
            detected = true;
        }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) {
            return false;
        }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        let type_ = self.type_(tid);
        type_.get_glib_name().map(
            |glib_name| if self.is_referenced_type(type_) {
                format!("{}*", glib_name)
            } else {
                glib_name.to_string()
            },
        )
    }

    fn is_referenced_type(&self, type_: &Type) -> bool {
        use library::Type::*;
        match *type_ {
            Alias(ref alias) => self.is_referenced_type(self.type_(alias.typ)),
            Record(..) | Union(..) | Class(..) | Interface(..) => true,
            _ => false,
        }
    }

    fn resolve_class_structs(&mut self) {
        // stores pairs of (gtype-struct-c-name, type-name)
        let mut structs_and_types = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in ns.types.iter() {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                match *type_ {
                    Type::Record(ref record) => {
                        if let Some(ref struct_for) = record.gtype_struct_for {
                            if let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for) {
                                structs_and_types.push ((record.c_type.clone(), struct_for_tid));
                            }
                        }
                    },

                    _ => (),
                }
            }
        }

        for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
            match *self.type_mut(struct_for_tid) {
                Type::Class(ref mut klass) => {
                    klass.c_class_type = Some(gtype_struct_c_type);
                },

                Type::Interface(ref mut iface) => {
                    iface.c_class_type = Some(gtype_struct_c_type);
                },

                ref x @ _ => unreachable!("Something other than a class or interface has a class struct: {:?}", x)
            }
        }
    }
}
<commit_msg>Postprocessing: Add a sanity check to correlate type-struct with is-gtype-struct-for<commit_after>use std::collections::HashMap;

use library::*;
use parser::is_empty_c_type;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index
            .iter()
            .filter_map(|(name, &id)| if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            })
            .collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
        self.resolve_class_structs();
        self.correlate_class_structs();
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index
            .iter()
            .flat_map(|(name, &id)| {
                let name = name.clone();
                self.namespace(id)
                    .unresolved()
                    .into_iter()
                    .map(move |s| format!("{}.{}", name, s))
            })
            .collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) {
                return;
            }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) => {
                    update_empty_signals_c_types(&mut klass.signals, &c_types)
                }
                Type::Interface(ref mut iface) => {
                    update_empty_signals_c_types(&mut iface.signals, &c_types)
                }
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(
        &self,
        signals: &[Signal],
        c_types: &mut DetectedCTypes,
    ) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) {
                detected = true;
            }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) {
                detected = true;
            }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) {
            detected = true;
        }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) {
            return false;
        }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        let type_ = self.type_(tid);
        type_.get_glib_name().map(
            |glib_name| if self.is_referenced_type(type_) {
                format!("{}*", glib_name)
            } else {
                glib_name.to_string()
            },
        )
    }

    fn is_referenced_type(&self, type_: &Type) -> bool {
        use library::Type::*;
        match *type_ {
            Alias(ref alias) => self.is_referenced_type(self.type_(alias.typ)),
            Record(..) | Union(..) | Class(..) | Interface(..) => true,
            _ => false,
        }
    }

    fn resolve_class_structs(&mut self) {
        // stores pairs of (gtype-struct-c-name, type-name)
        let mut structs_and_types = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in ns.types.iter() {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                match *type_ {
                    Type::Record(ref record) => {
                        if let Some(ref struct_for) = record.gtype_struct_for {
                            if let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for) {
                                structs_and_types.push ((record.c_type.clone(), struct_for_tid));
                            }
                        }
                    },

                    _ => (),
                }
            }
        }

        for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
            match *self.type_mut(struct_for_tid) {
                Type::Class(ref mut klass) => {
                    klass.c_class_type = Some(gtype_struct_c_type);
                },

                Type::Interface(ref mut iface) => {
                    iface.c_class_type = Some(gtype_struct_c_type);
                },

                ref x @ _ => unreachable!("Something other than a class or interface has a class struct: {:?}", x)
            }
        }
    }

    fn correlate_class_structs(&self) {
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in ns.types.iter() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let mut name;
                let mut type_struct;
                let mut c_class_type;

                match *type_ {
                    Type::Class(ref klass) => {
                        name         = &klass.name;
                        type_struct  = &klass.type_struct;
                        c_class_type = &klass.c_class_type;
                    },

                    Type::Interface(ref iface) => {
                        name         = &iface.name;
                        type_struct  = &iface.type_struct;
                        c_class_type = &iface.c_class_type;
                    },

                    _ => { continue; }
                }

                if let &Some(ref type_struct) = type_struct {
                    let type_struct_tid = self.find_type(ns_id as u16, type_struct);
                    if type_struct_tid.is_none() {
                        panic!("\"{}\" has glib:type-struct=\"{}\" but there is no such record",
                               name,
                               type_struct);
                    }

                    let type_ = self.type_(*type_struct_tid.as_ref().unwrap());

                    match *type_ {
                        Type::Record(ref r) => {
                            if r.gtype_struct_for.as_ref() != Some(name) {
                                if let Some(ref gtype_struct_for) = r.gtype_struct_for {
                                    panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
                                           name,
                                           type_struct,
                                           r.name,
                                           gtype_struct_for);
                                } else {
                                    panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
                                           name,
                                           type_struct,
                                           r.name);
                                }
                            }
                        },

                        _ => { panic!("Element with name=\"{}\" should be a record but it isn't",
                                      type_struct); }
                    }
                } else {
                    if !(type_struct.is_none() && c_class_type.is_none()) {
                        panic!("\"{}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{}\"",
                               name,
                               c_class_type.as_ref().unwrap());
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::interface::{Compiler, Result};
use crate::passes::{self, BoxedResolver, QueryContext};

use rustc_incremental::DepGraphFuture;
use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc::session::config::{OutputFilenames, OutputType};
use rustc::util::common::{time, ErrorReported};
use rustc::arena::Arena;
use rustc::hir;
use rustc::lint;
use rustc::session::Session;
use rustc::lint::LintStore;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::ty::steal::Steal;
use rustc::ty::{AllArenas, ResolverOutputs, GlobalCtxt};
use rustc::dep_graph::DepGraph;
use std::cell::{Ref, RefMut, RefCell};
use std::rc::Rc;
use std::any::Any;
use std::mem;
use syntax::{self, ast};

/// Represent the result of a query.
/// This result can be stolen with the `take` method and returned with the `give` method.
pub struct Query<T> {
    result: RefCell<Option<Result<T>>>,
}

impl<T> Query<T> {
    fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
        let mut result = self.result.borrow_mut();
        if result.is_none() {
            *result = Some(f());
        }
        result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err)
    }

    /// Takes ownership of the query result. Further attempts to take or peek the query
    /// result will panic unless it is returned by calling the `give` method.
    pub fn take(&self) -> T {
        self.result
            .borrow_mut()
            .take()
            .expect("missing query result")
            .unwrap()
    }

    /// Borrows the query result using the RefCell. Panics if the result is stolen.
    pub fn peek(&self) -> Ref<'_, T> {
        Ref::map(self.result.borrow(), |r| {
            r.as_ref().unwrap().as_ref().expect("missing query result")
        })
    }

    /// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
    pub fn peek_mut(&self) -> RefMut<'_, T> {
        RefMut::map(self.result.borrow_mut(), |r| {
            r.as_mut().unwrap().as_mut().expect("missing query result")
        })
    }
}

impl<T> Default for Query<T> {
    fn default() -> Self {
        Query {
            result: RefCell::new(None),
        }
    }
}

pub struct Queries<'tcx> {
    compiler: &'tcx Compiler,
    gcx: Once<GlobalCtxt<'tcx>>,

    all_arenas: AllArenas,
    arena: WorkerLocal<Arena<'tcx>>,

    dep_graph_future: Query<Option<DepGraphFuture>>,
    parse: Query<ast::Crate>,
    crate_name: Query<String>,
    register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
    expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
    dep_graph: Query<DepGraph>,
    lower_to_hir: Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>,
    prepare_outputs: Query<OutputFilenames>,
    global_ctxt: Query<QueryContext<'tcx>>,
    ongoing_codegen: Query<Box<dyn Any>>,
}

impl<'tcx> Queries<'tcx> {
    pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> {
        Queries {
            compiler,
            gcx: Once::new(),
            all_arenas: AllArenas::new(),
            arena: WorkerLocal::new(|_| Arena::default()),
            dep_graph_future: Default::default(),
            parse: Default::default(),
            crate_name: Default::default(),
            register_plugins: Default::default(),
            expansion: Default::default(),
            dep_graph: Default::default(),
            lower_to_hir: Default::default(),
            prepare_outputs: Default::default(),
            global_ctxt: Default::default(),
            ongoing_codegen: Default::default(),
        }
    }

    fn session(&self) -> &Lrc<Session> {
        &self.compiler.sess
    }
    fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
        &self.compiler.codegen_backend()
    }

    pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
        self.dep_graph_future.compute(|| {
            Ok(if self.session().opts.build_dep_graph() {
                Some(rustc_incremental::load_dep_graph(self.session()))
            } else {
                None
            })
        })
    }

    pub fn parse(&self) -> Result<&Query<ast::Crate>> {
        self.parse.compute(|| {
            passes::parse(self.session(), &self.compiler.input).map_err(
                |mut parse_error| {
                    parse_error.emit();
                    ErrorReported
                },
            )
        })
    }

    pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
        self.register_plugins.compute(|| {
            let crate_name = self.crate_name()?.peek().clone();
            let krate = self.parse()?.take();

            let empty: &(dyn Fn(&Session, &mut lint::LintStore) + Sync + Send) = &|_, _| {};
            let result = passes::register_plugins(
                self.session(),
                &*self.codegen_backend().metadata_loader(),
                self.compiler.register_lints
                    .as_ref()
                    .map(|p| &**p)
                    .unwrap_or_else(|| empty),
                krate,
                &crate_name,
            );

            // Compute the dependency graph (in the background). We want to do
            // this as early as possible, to give the DepGraph maximum time to
            // load before dep_graph() is called, but it also can't happen
            // until after rustc_incremental::prepare_session_directory() is
            // called, which happens within passes::register_plugins().
            self.dep_graph_future().ok();

            result
        })
    }

    pub fn crate_name(&self) -> Result<&Query<String>> {
        self.crate_name.compute(|| {
            Ok(match self.compiler.crate_name {
                Some(ref crate_name) => crate_name.clone(),
                None => {
                    let parse_result = self.parse()?;
                    let krate = parse_result.peek();
                    rustc_codegen_utils::link::find_crate_name(
                        Some(self.session()),
                        &krate.attrs,
                        &self.compiler.input
                    )
                }
            })
        })
    }

    pub fn expansion(
        &self
    ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
        self.expansion.compute(|| {
            let crate_name = self.crate_name()?.peek().clone();
            let (krate, lint_store) = self.register_plugins()?.take();
            passes::configure_and_expand(
                self.session().clone(),
                lint_store.clone(),
                self.codegen_backend().metadata_loader(),
                krate,
                &crate_name,
            ).map(|(krate, resolver)| {
                (krate, Steal::new(Rc::new(RefCell::new(resolver))), lint_store)
            })
        })
    }

    pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
        self.dep_graph.compute(|| {
            Ok(match self.dep_graph_future()?.take() {
                None => DepGraph::new_disabled(),
                Some(future) => {
                    let (prev_graph, prev_work_products) =
                        time(self.session(), "blocked while dep-graph loading finishes", || {
                            future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
                                message: format!("could not decode incremental cache: {:?}", e),
                            }).open(self.session())
                        });
                    DepGraph::new(prev_graph, prev_work_products)
                }
            })
        })
    }

    pub fn lower_to_hir(
        &'tcx self,
    ) -> Result<&Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>> {
        self.lower_to_hir.compute(|| {
            let expansion_result = self.expansion()?;
            let peeked = expansion_result.peek();
            let krate = &peeked.0;
            let resolver = peeked.1.steal();
            let lint_store = &peeked.2;
            let hir = resolver.borrow_mut().access(|resolver| {
                passes::lower_to_hir(
                    self.session(),
                    lint_store,
                    resolver,
                    &*self.dep_graph()?.peek(),
                    &krate
                )
            })?;
            let hir = self.arena.alloc(hir);
            Ok((hir, Steal::new(BoxedResolver::to_resolver_outputs(resolver))))
        })
    }

    pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
        self.prepare_outputs.compute(|| {
            let expansion_result = self.expansion()?;
            let (krate, boxed_resolver, _) = &*expansion_result.peek();
            let crate_name = self.crate_name()?;
            let crate_name = crate_name.peek();
            passes::prepare_outputs(
                self.session(), self.compiler, &krate, &boxed_resolver, &crate_name
            )
        })
    }

    pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
        self.global_ctxt.compute(|| {
            let crate_name = self.crate_name()?.peek().clone();
            let outputs = self.prepare_outputs()?.peek().clone();
            let lint_store = self.expansion()?.peek().2.clone();
            let hir = self.lower_to_hir()?.peek();
            let (ref hir_forest, ref resolver_outputs) = &*hir;
            Ok(passes::create_global_ctxt(
                self.compiler,
                lint_store,
                hir_forest,
                resolver_outputs.steal(),
                outputs,
                &crate_name,
                &self.gcx,
                &self.all_arenas,
                &self.arena,
            ))
        })
    }

    pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
        self.ongoing_codegen.compute(|| {
            let outputs = self.prepare_outputs()?;
            self.global_ctxt()?.peek_mut().enter(|tcx| {
                tcx.analysis(LOCAL_CRATE).ok();

                // Don't do code generation if there were any errors
                self.session().compile_status()?;

                Ok(passes::start_codegen(
                    &***self.codegen_backend(),
                    tcx,
                    &*outputs.peek()
                ))
            })
        })
    }

    pub fn linker(&'tcx self) -> Result<Linker> {
        let dep_graph = self.dep_graph()?;
        let prepare_outputs = self.prepare_outputs()?;
        let ongoing_codegen = self.ongoing_codegen()?;

        let sess = self.session().clone();
        let codegen_backend = self.codegen_backend().clone();

        Ok(Linker {
            sess,
            dep_graph: dep_graph.peek().clone(),
            prepare_outputs: prepare_outputs.take(),
            ongoing_codegen: ongoing_codegen.take(),
            codegen_backend,
        })
    }
}

pub struct Linker {
    sess: Lrc<Session>,
    dep_graph: DepGraph,
    prepare_outputs: OutputFilenames,
    ongoing_codegen: Box<dyn Any>,
    codegen_backend: Lrc<Box<dyn CodegenBackend>>,
}

impl Linker {
    pub fn link(self) -> Result<()> {
        self.codegen_backend.join_codegen_and_link(
            self.ongoing_codegen,
            &self.sess,
            &self.dep_graph,
            &self.prepare_outputs,
        ).map_err(|_| ErrorReported)
    }
}

impl Compiler {
    pub fn enter<F, T>(&self, f: F) -> T
        where F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T
    {
        let queries = Queries::new(&self);
        let ret = f(&queries);

        if self.session().opts.debugging_opts.query_stats {
            if let Ok(gcx) = queries.global_ctxt() {
                gcx.peek().print_stats();
            }
        }

        ret
    }

    // This method is different to all the other methods in `Compiler` because
    // it lacks a `Queries` entry. It's also not currently used. It does serve
    // as an example of how `Compiler` can be used, with additional steps added
    // between some passes. And see `rustc_driver::run_compiler` for a more
    // complex example.
    pub fn compile(&self) -> Result<()> {
        let linker = self.enter(|queries| {
            queries.prepare_outputs()?;

            if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
                && self.session().opts.output_types.len() == 1
            {
                return Ok(None)
            }

            queries.global_ctxt()?;

            // Drop AST after creating GlobalCtxt to free memory.
            mem::drop(queries.expansion()?.take());

            queries.ongoing_codegen()?;

            let linker = queries.linker()?;
            Ok(Some(linker))
        })?;

        if let Some(linker) = linker {
            linker.link()?
        }

        Ok(())
    }
}
<commit_msg>Fix Query type docs<commit_after>use crate::interface::{Compiler, Result};
use crate::passes::{self, BoxedResolver, QueryContext};

use rustc_incremental::DepGraphFuture;
use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc::session::config::{OutputFilenames, OutputType};
use rustc::util::common::{time, ErrorReported};
use rustc::arena::Arena;
use rustc::hir;
use rustc::lint;
use rustc::session::Session;
use rustc::lint::LintStore;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::ty::steal::Steal;
use rustc::ty::{AllArenas, ResolverOutputs, GlobalCtxt};
use rustc::dep_graph::DepGraph;
use std::cell::{Ref, RefMut, RefCell};
use std::rc::Rc;
use std::any::Any;
use std::mem;
use syntax::{self, ast};

/// Represent the result of a query.
/// This result can be stolen with the `take` method and generated with the `compute` method.
pub struct Query<T> {
    result: RefCell<Option<Result<T>>>,
}

impl<T> Query<T> {
    fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
        let mut result = self.result.borrow_mut();
        if result.is_none() {
            *result = Some(f());
        }
        result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err)
    }

    /// Takes ownership of the query result. Further attempts to take or peek the query
    /// result will panic unless it is generated by calling the `compute` method.
    pub fn take(&self) -> T {
        self.result
            .borrow_mut()
            .take()
            .expect("missing query result")
            .unwrap()
    }

    /// Borrows the query result using the RefCell. Panics if the result is stolen.
    pub fn peek(&self) -> Ref<'_, T> {
        Ref::map(self.result.borrow(), |r| {
            r.as_ref().unwrap().as_ref().expect("missing query result")
        })
    }

    /// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
    pub fn peek_mut(&self) -> RefMut<'_, T> {
        RefMut::map(self.result.borrow_mut(), |r| {
            r.as_mut().unwrap().as_mut().expect("missing query result")
        })
    }
}

impl<T> Default for Query<T> {
    fn default() -> Self {
        Query {
            result: RefCell::new(None),
        }
    }
}

pub struct Queries<'tcx> {
    compiler: &'tcx Compiler,
    gcx: Once<GlobalCtxt<'tcx>>,

    all_arenas: AllArenas,
    arena: WorkerLocal<Arena<'tcx>>,

    dep_graph_future: Query<Option<DepGraphFuture>>,
    parse: Query<ast::Crate>,
    crate_name: Query<String>,
    register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
    expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
    dep_graph: Query<DepGraph>,
    lower_to_hir: Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>,
    prepare_outputs: Query<OutputFilenames>,
    global_ctxt: Query<QueryContext<'tcx>>,
    ongoing_codegen: Query<Box<dyn Any>>,
}

impl<'tcx> Queries<'tcx> {
    pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> {
        Queries {
            compiler,
            gcx: Once::new(),
            all_arenas: AllArenas::new(),
            arena: WorkerLocal::new(|_| Arena::default()),
            dep_graph_future: Default::default(),
            parse: Default::default(),
            crate_name: Default::default(),
            register_plugins: Default::default(),
            expansion: Default::default(),
            dep_graph: Default::default(),
            lower_to_hir: Default::default(),
            prepare_outputs: Default::default(),
            global_ctxt: Default::default(),
            ongoing_codegen: Default::default(),
        }
    }

    fn session(&self) -> &Lrc<Session> {
        &self.compiler.sess
    }
    fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
        &self.compiler.codegen_backend()
    }

    pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
        self.dep_graph_future.compute(|| {
            Ok(if self.session().opts.build_dep_graph() {
                Some(rustc_incremental::load_dep_graph(self.session()))
            } else {
                None
            })
        })
    }

    pub fn parse(&self) -> Result<&Query<ast::Crate>> {
        self.parse.compute(|| {
            passes::parse(self.session(), &self.compiler.input).map_err(
                |mut parse_error| {
                    parse_error.emit();
                    ErrorReported
                },
            )
        })
    }

    pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
        self.register_plugins.compute(|| {
            let crate_name = self.crate_name()?.peek().clone();
            let krate = self.parse()?.take();

            let empty: &(dyn Fn(&Session, &mut lint::LintStore) + Sync + Send) = &|_, _| {};
            let result = passes::register_plugins(
                self.session(),
                &*self.codegen_backend().metadata_loader(),
                self.compiler.register_lints
                    .as_ref()
                    .map(|p| &**p)
                    .unwrap_or_else(|| empty),
                krate,
                &crate_name,
            );

            // Compute the dependency graph (in the background). We want to do
            // this as early as possible, to give the DepGraph maximum time to
            // load before dep_graph() is called, but it also can't happen
            // until after rustc_incremental::prepare_session_directory() is
            // called, which happens within passes::register_plugins().
            self.dep_graph_future().ok();

            result
        })
    }

    pub fn crate_name(&self) -> Result<&Query<String>> {
        self.crate_name.compute(|| {
            Ok(match self.compiler.crate_name {
                Some(ref crate_name) => crate_name.clone(),
                None => {
                    let parse_result = self.parse()?;
                    let krate = parse_result.peek();
                    rustc_codegen_utils::link::find_crate_name(
                        Some(self.session()),
                        &krate.attrs,
                        &self.compiler.input
                    )
                }
            })
        })
    }

    pub fn expansion(
        &self
    ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
        self.expansion.compute(|| {
            let crate_name = self.crate_name()?.peek().clone();
            let (krate, lint_store) = self.register_plugins()?.take();
            passes::configure_and_expand(
                self.session().clone(),
                lint_store.clone(),
                self.codegen_backend().metadata_loader(),
                krate,
                &crate_name,
            ).map(|(krate, resolver)| {
                (krate, Steal::new(Rc::new(RefCell::new(resolver))), lint_store)
            })
        })
    }

    pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
        self.dep_graph.compute(|| {
            Ok(match self.dep_graph_future()?.take() {
                None => DepGraph::new_disabled(),
                Some(future) => {
                    let (prev_graph, prev_work_products) =
                        time(self.session(), "blocked while dep-graph loading finishes", || {
                            future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
                                message: format!("could not decode incremental cache: {:?}", e),
                            }).open(self.session())
                        });
                    DepGraph::new(prev_graph, prev_work_products)
                }
            })
        })
    }

    pub fn lower_to_hir(
        &'tcx self,
    ) -> Result<&Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>> {
        self.lower_to_hir.compute(|| {
            let expansion_result = self.expansion()?;
            let peeked = expansion_result.peek();
            let krate = &peeked.0;
            let resolver = peeked.1.steal();
            let lint_store = &peeked.2;
            let hir = resolver.borrow_mut().access(|resolver| {
                passes::lower_to_hir(
                    self.session(),
                    lint_store,
                    resolver,
                    &*self.dep_graph()?.peek(),
                    &krate
                )
            })?;
            let hir = self.arena.alloc(hir);
            Ok((hir, Steal::new(BoxedResolver::to_resolver_outputs(resolver))))
        })
    }

    pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
        self.prepare_outputs.compute(|| {
            let expansion_result = self.expansion()?;
            let (krate, boxed_resolver, _) = &*expansion_result.peek();
            let crate_name = self.crate_name()?;
            let crate_name = crate_name.peek();
            passes::prepare_outputs(
                self.session(), self.compiler, &krate, &boxed_resolver, &crate_name
            )
        })
    }

    pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
        self.global_ctxt.compute(|| {
            let crate_name = self.crate_name()?.peek().clone();
            let outputs = self.prepare_outputs()?.peek().clone();
            let lint_store = self.expansion()?.peek().2.clone();
            let hir = self.lower_to_hir()?.peek();
            let (ref hir_forest, ref resolver_outputs) = &*hir;
            Ok(passes::create_global_ctxt(
                self.compiler,
                lint_store,
                hir_forest,
                resolver_outputs.steal(),
                outputs,
                &crate_name,
                &self.gcx,
                &self.all_arenas,
                &self.arena,
            ))
        })
    }

    pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
        self.ongoing_codegen.compute(|| {
            let outputs = self.prepare_outputs()?;
            self.global_ctxt()?.peek_mut().enter(|tcx| {
                tcx.analysis(LOCAL_CRATE).ok();

                // Don't do code generation if there were any errors
                self.session().compile_status()?;

                Ok(passes::start_codegen(
                    &***self.codegen_backend(),
                    tcx,
                    &*outputs.peek()
                ))
            })
        })
    }

    pub fn linker(&'tcx self) -> Result<Linker> {
        let dep_graph = self.dep_graph()?;
        let prepare_outputs = self.prepare_outputs()?;
        let ongoing_codegen = self.ongoing_codegen()?;

        let sess = self.session().clone();
        let codegen_backend = self.codegen_backend().clone();

        Ok(Linker {
            sess,
            dep_graph: dep_graph.peek().clone(),
            prepare_outputs: prepare_outputs.take(),
            ongoing_codegen: ongoing_codegen.take(),
            codegen_backend,
        })
    }
}

pub struct Linker {
    sess: Lrc<Session>,
    dep_graph: DepGraph,
    prepare_outputs: OutputFilenames,
    ongoing_codegen: Box<dyn Any>,
    codegen_backend: Lrc<Box<dyn CodegenBackend>>,
}

impl Linker {
    pub fn link(self) -> Result<()> {
        self.codegen_backend.join_codegen_and_link(
            self.ongoing_codegen,
            &self.sess,
            &self.dep_graph,
            &self.prepare_outputs,
        ).map_err(|_| ErrorReported)
    }
}

impl Compiler {
    pub fn enter<F, T>(&self, f: F) -> T
        where F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T
    {
        let queries = Queries::new(&self);
        let ret = f(&queries);

        if self.session().opts.debugging_opts.query_stats {
            if let Ok(gcx) = queries.global_ctxt() {
                gcx.peek().print_stats();
            }
        }

        ret
    }

    // This method is different to all the other methods in `Compiler` because
    // it lacks a `Queries` entry. It's also not currently used. It does serve
    // as an example of how `Compiler` can be used, with additional steps added
    // between some passes. And see `rustc_driver::run_compiler` for a more
    // complex example.
    pub fn compile(&self) -> Result<()> {
        let linker = self.enter(|queries| {
            queries.prepare_outputs()?;

            if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
                && self.session().opts.output_types.len() == 1
            {
                return Ok(None)
            }

            queries.global_ctxt()?;

            // Drop AST after creating GlobalCtxt to free memory.
            mem::drop(queries.expansion()?.take());

            queries.ongoing_codegen()?;

            let linker = queries.linker()?;
            Ok(Some(linker))
        })?;

        if let Some(linker) = linker {
            linker.link()?
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>
use std::{cmp, fmt};

#[derive(Copy,Clone)]
struct Stats {
    health: i32,
    attack: i32,
    defence: i32,
}

impl Stats {
    fn add_item(&mut self, item: &Item) {
        self.attack += item.damage;
        self.defence += item.armor;
    }
}

#[derive(PartialEq,Eq)]
struct Item {
    name: String,
    cost: i32,
    damage: i32,
    armor: i32,
}

impl Item {
    fn new(name: &str, cost: i32, damage: i32, armor: i32 ) -> Item {
        Item{name: String::from(name), cost: cost, damage: damage, armor: armor}
    }
}

impl fmt::Display for Item {
    // This trait requires `fmt` with this exact signature.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Write strictly the first element into the supplied output
        // stream: `f`. Returns `fmt::Result` which indicates whether the
        // operation succeeded or failed. Note that `write!` uses syntax which
        // is very similar to `println!`.
        write!(f, "{}", self.name)
    }
}

// Player 1 attacks first, and thus wins on ties.
// Returns 1 if player 1 wins, 2 if player 2 wins.
fn player_wins(player: Stats, boss: Stats, verbose: bool) -> bool {
    let player_hp_loss_per_hit = cmp::max(1, boss.attack - player.defence);
    let boss_hp_loss_per_hit = cmp::max(1, player.attack - boss.defence);

    // Solve the linear equation { hp = hp_loss*num_hits + 100 } for num_hits to find the winner.
    let boss_dead_after = 100.0/boss_hp_loss_per_hit as f32;
    let player_dead_after = 100.0/player_hp_loss_per_hit as f32;

    if verbose {
        println!("player hp loss {}, boss hp loss {}", player_hp_loss_per_hit, boss_hp_loss_per_hit);
        println!("boss dead after {} hits, player dead after {} hits", boss_dead_after, player_dead_after);
    }

    boss_dead_after <= player_dead_after
}

fn main() {
    println!("Hello, world!");

    let weapons = vec![
        Item::new("no weapon",        0, 0, 0),
        Item::new("Dagger",      8, 4, 0),
        Item::new("Shortsword", 10, 5, 0),
        Item::new("Warhammer",  25, 6, 0),
        Item::new("Longsword",  40, 7, 0),
        Item::new("Greataxe",   74, 8, 0),
    ];

    let armors = vec![
        Item::new("no armor",         0, 0, 0),
        Item::new("Leather",     13, 0, 1),
        Item::new("Chainmail",   31, 0, 2),
        Item::new("Splintmail",  53, 0, 3),
        Item::new("Bandedmail",  75, 0, 4),
        Item::new("Platemail",  102, 0, 5),
    ];

    let rings = vec![
        Item::new("no ring",        0, 0, 0),
        Item::new("Damage +1",  25, 1, 0),
        Item::new("Damage +2",  50, 2, 0),
        Item::new("Damage +3", 100, 3, 0),
        Item::new("Defence +1", 20, 0, 1),
        Item::new("Defence +2", 50, 0, 2),
        Item::new("Defence +3", 80, 0, 3),
    ];

    // Hit Points: 100
    // Damage: 8
    // Armor: 2
    let boss = Stats {health: 100, attack: 8, defence: 2};

    let base_player = Stats {health: 100, attack: 0, defence: 0};

    let mut lowest_cost = i32::max_value();

    // There are few enough possible combinations for a brute-force search.
    for weapon in &weapons {
        for armor in &armors {
            for ring1 in &rings {
                for ring2 in &rings {
                    if ring1 != ring2 {
                        let mut player = base_player;
                        player.add_item(&weapon);
                        player.add_item(&armor);
                        player.add_item(&ring1);
                        player.add_item(&ring2);
                        let cost = weapon.cost + armor.cost + ring1.cost + ring2.cost;

                        let victory = player_wins(player, boss, false);

                        if victory && cost < lowest_cost {
                            player_wins(player, boss, true);
                            println!("Victory! for {} gold with {}, {}, {}, {},", cost, weapon, armor, ring1, ring2);
                            println!("");
                            lowest_cost = cost;
                        }
                    }
                }
            }
        }
    }

    // Solution for part 1 is 91 gold.
    assert_eq!(lowest_cost, 91);
}
<commit_msg>Added day 21, part 2<commit_after>
use std::{cmp, fmt};

#[derive(Copy,Clone)]
struct Stats {
    health: i32,
    attack: i32,
    defence: i32,
}

impl Stats {
    fn add_item(&mut self, item: &Item) {
        self.attack += item.damage;
        self.defence += item.armor;
    }
}

#[derive(PartialEq,Eq)]
struct Item {
    name: String,
    cost: i32,
    damage: i32,
    armor: i32,
}

impl Item {
    fn new(name: &str, cost: i32, damage: i32, armor: i32 ) -> Item {
        Item{name: String::from(name), cost: cost, damage: damage, armor: armor}
    }
}

impl fmt::Display for Item {
    // This trait requires `fmt` with this exact signature.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Write strictly the first element into the supplied output
        // stream: `f`. Returns `fmt::Result` which indicates whether the
        // operation succeeded or failed. Note that `write!` uses syntax which
        // is very similar to `println!`.
        write!(f, "{}", self.name)
    }
}

// Player 1 attacks first, and thus wins on ties.
// Returns 1 if player 1 wins, 2 if player 2 wins.
fn player_wins(player: Stats, boss: Stats, verbose: bool) -> bool {
    let player_hp_loss_per_hit = cmp::max(1, boss.attack - player.defence);
    let boss_hp_loss_per_hit = cmp::max(1, player.attack - boss.defence);

    // Solve the linear equation { hp = hp_loss*num_hits + 100 } for num_hits to find the winner.
    let boss_dead_after = 100.0/boss_hp_loss_per_hit as f32;
    let player_dead_after = 100.0/player_hp_loss_per_hit as f32;

    if verbose {
        println!("player hp loss {}, boss hp loss {}", player_hp_loss_per_hit, boss_hp_loss_per_hit);
        println!("boss dead after {} hits, player dead after {} hits", boss_dead_after, player_dead_after);
    }

    boss_dead_after <= player_dead_after
}

fn main() {
    println!("Hello, world!");

    let weapons = vec![
        Item::new("Dagger",      8, 4, 0),
        Item::new("Shortsword", 10, 5, 0),
        Item::new("Warhammer",  25, 6, 0),
        Item::new("Longsword",  40, 7, 0),
        Item::new("Greataxe",   74, 8, 0),
    ];

    let armors = vec![
        Item::new("no armor",     0, 0, 0), // Armor is optional
        Item::new("Leather",     13, 0, 1),
        Item::new("Chainmail",   31, 0, 2),
        Item::new("Splintmail",  53, 0, 3),
        Item::new("Bandedmail",  75, 0, 4),
        Item::new("Platemail",  102, 0, 5),
    ];

    let rings = vec![
        Item::new("no ring",     0, 0, 0),  // Rings are optional
        Item::new("no ring",     0, 0, 0),
        Item::new("Damage +1",  25, 1, 0),
        Item::new("Damage +2",  50, 2, 0),
        Item::new("Damage +3", 100, 3, 0),
        Item::new("Defence +1", 20, 0, 1),
        Item::new("Defence +2", 50, 0, 2),
        Item::new("Defence +3", 80, 0, 3),
    ];

    // Hit Points: 100
    // Damage: 8
    // Armor: 2
    let boss = Stats {health: 100, attack: 8, defence: 2};

    let base_player = Stats {health: 100, attack: 0, defence: 0};

    let mut lowest_cost_to_win = i32::max_value();
    let mut highest_cost_and_lose = 0;

    // There are few enough possible combinations for a brute-force search for the lowest cost to win.
    for weapon in &weapons {
        for armor in &armors {
            for ring1 in &rings {
                for ring2 in &rings {
                    if ring1 != ring2 {
                        let mut player = base_player;
                        player.add_item(&weapon);
                        player.add_item(&armor);
                        player.add_item(&ring1);
                        player.add_item(&ring2);
                        let cost = weapon.cost + armor.cost + ring1.cost + ring2.cost;

                        let victory = player_wins(player, boss, false);

                        if victory && cost < lowest_cost_to_win {
                            //player_wins(player, boss, true);
                            println!("Victory! for {} gold with {}, {}, {}, {},", cost, weapon, armor, ring1, ring2);
                            lowest_cost_to_win = cost;
                        }

                        if !victory && cost > highest_cost_and_lose {
                            //player_wins(player, boss, true);
                            println!("Loss! for {} gold with {}, {}, {}, {},", cost, weapon, armor, ring1, ring2);
                            //println!("");
                            highest_cost_and_lose = cost;
                        }
                    }
                }
            }
        }
    }

    println!("Lowest cost to win is {} gold", lowest_cost_to_win);
    println!("Highest cost to still loose is {} gold", highest_cost_and_lose);
    println!("");

    // Solution for part 1 is 91 gold.
    assert_eq!(lowest_cost_to_win, 91);

    // Solution for part 2 is 158 gold.
    assert_eq!(highest_cost_and_lose, 158);
}
<|endoftext|>