<commit_before>
pub mod condition;
pub mod executor;
pub mod instruction;
pub mod operation;
pub mod register;
pub mod bits;

use bus::Bus;
use core::executor::execute;
use decoder::{decode_16, decode_32, is_thumb32};
use core::register::{Reg, PSR, Epsr, Apsr, Control};
use core::instruction::Instruction;
use std::fmt;
use semihosting::SemihostingCommand;
use semihosting::SemihostingResponse;

pub enum ProcessorMode {
    ThreadMode,
    HandlerMode,
}

pub enum ThumbCode {
    Thumb32 { half_word: u16, half_word2: u16 },
    Thumb16 { half_word: u16 },
}

impl From<u16> for ThumbCode {
    fn from(value : u16) -> Self{
        ThumbCode::Thumb16 {half_word : value}
    }
}

impl From<u32> for ThumbCode {
    fn from(value : u32)-> Self{
        ThumbCode::Thumb32 {half_word : (value & 0xffff) as u16, half_word2: ((value >> 16)& 0xffff) as u16}
    }
}
impl fmt::Display for ThumbCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThumbCode::Thumb16 {half_word} => write!(f, "0x{:x}", half_word),
            ThumbCode::Thumb32 {half_word, half_word2}=> write!(f, "0x{:x}{:x}", half_word2, half_word),
        }
    }
}

pub struct Core<'a, T: Bus + 'a> {

    /* 13 of 32-bit general purpose registers. */
    r0_12: [u32; 13],

    msp: u32, //MSP, virtual reg r[13]
    psp: u32, //PSP, virtual reg r[13]
    lr: u32,
    pc: u32,

    // TODO, vtor is in SCS
    vtor : u32,

    /* Processor state register, status flags. */
    psr: PSR,

    /* interrupt primary mask, a 1 bit mask register for
       global interrupt masking. */
    primask: bool,

    /* Control bits: currently used stack and execution privilege if core.mode == ThreadMode */
    control: Control,

    /* Processor mode: either handler or thread mode. */
    mode: ProcessorMode,

    /* Bus to which the core is connected. */
    pub bus: &'a mut T,

    /* Is the core simulation currently running or not.*/
    pub running : bool
}

impl<'a, T: Bus> Core<'a, T> {
    pub fn new(bus: &'a mut T) -> Core<'a, T> {
        Core {
            mode: ProcessorMode::ThreadMode,
            vtor : 0,
            psr: PSR { value: 0 },
            primask: false,
            control: Control { n_priv: false, sp_sel : false},
            r0_12: [0; 13],
            pc : 0,
            msp : 0,
            psp : 0,
            lr : 0,
            bus: bus,
            running : true
        }
    }

    //
    // Getter for registers
    //
    pub fn get_r(&self, r : &Reg) -> u32 {
        match *r {
                Reg::R0|Reg::R1|Reg::R2|Reg::R3|Reg::R4|Reg::R5|Reg::R6|Reg::R7|Reg::R8|Reg::R9|Reg::R10|Reg::R11|Reg::R12 => {
                    let reg : usize = From::from(*r);
                    self.r0_12[reg]
                },
    Reg::SP => if self.control.sp_sel {self.psp} else { self.msp},
    Reg::LR => self.lr,
    Reg::PC => self.pc

        }
    }
    //
    // Setter for registers
    //
    pub fn set_r(&mut self, r : &Reg, value: u32) {
        match *r {
                Reg::R0|Reg::R1|Reg::R2|Reg::R3|Reg::R4|Reg::R5|Reg::R6|Reg::R7|Reg::R8|Reg::R9|Reg::R10|Reg::R11|Reg::R12 => {
                    let reg : usize = From::from(*r);
                    self.r0_12[reg] = value;},
    Reg::SP => if self.control.sp_sel {self.psp = value} else { self.msp = value},
    Reg::LR => self.lr = value,
    Reg::PC => self.pc = value

        };
    }

    pub fn set_msp(&mut self, value: u32) {
        self.msp = value;
    }

    pub fn set_psp(&mut self, value: u32) {
        self.psp = value;
    }

    pub fn add_pc(&mut self, value: u32) {
        self.pc += value;
    }

    //
    // Setter for registers
    //
    pub fn add_r(&mut self, r : &Reg, value: u32) {
        match *r {
                Reg::R0|Reg::R1|Reg::R2|Reg::R3|Reg::R4|Reg::R5|Reg::R6|Reg::R7|Reg::R8|Reg::R9|Reg::R10|Reg::R11|Reg::R12 => {
                    let reg : usize = From::from(*r);
                    self.r0_12[reg] += value;},
    Reg::SP => if self.control.sp_sel {self.psp = value} else { self.msp += value},
    Reg::LR => self.lr += value,
    Reg::PC => self.pc += value

        };
    }

    //
    // Reset Exception
    //
    pub fn reset(&mut self) {

        // All basic registers to zero.
        self.r0_12[0] = 0;
        self.r0_12[1] = 0;
        self.r0_12[2] = 0;
        self.r0_12[3] = 0;
        self.r0_12[4] = 0;
        self.r0_12[5] = 0;
        self.r0_12[6] = 0;
        self.r0_12[7] = 0;
        self.r0_12[8] = 0;
        self.r0_12[9] = 0;
        self.r0_12[10] = 0;
        self.r0_12[11] = 0;

        // Main stack pointer is read via vector table
        let vtor = self.vtor;
        let sp = self.bus.read32(vtor) & 0xffff_fffc;
        self.set_msp(sp);

        // Process stack pointer to zero
        self.set_psp(0);

        // Link Register
        self.lr = 0;

        // Mode
        self.mode = ProcessorMode::ThreadMode;

        // Apsr, ipsr
        self.psr = PSR {value : 0};
        self.primask = false;
        self.control.sp_sel = false;
        self.control.n_priv = false;

        //TODO self.scs.reset();
        //TODOself.exceptions.clear();

        //self.event_reg.clear();

        let reset_vector = self.bus.read32(vtor + 4);

        self.set_r(&Reg::PC, reset_vector & 0xffff_fffe);
        self.psr.set_t((reset_vector & 1) == 1);
    }

/*
    pub fn exception_entry(&mut self, exception_number : u32, return_address : u32)
    {
        // push stack
        let (frameptr, frameptralign) = if self.control.sp_sel && self.mode == ProcessorMode::ThreadMode
        {
            let align = self.psp<2>; ??
            self.psp = (self.psp -0x20) & (4 ^ 0xFFFF_FFFF);
            (self.psp, align)
        }
        else
        {
            let align = self.msp<2>; ??
            self.msp = (self.msp - 0x20)& (4 ^ 0xFFFF_FFFF);
            (self.msp, align)
        }

        self.bus.write32(frameptr, self.get_r(Reg::R0));
        self.bus.write32(frameptr+0x4, self.get_r(Reg::R1));
        self.bus.write32(frameptr+0x8, self.get_r(Reg::R2));
        self.bus.write32(frameptr+0xc, self.get_r(Reg::R3));
        self.bus.write32(frameptr+0x10, self.get_r(Reg::R12));
        self.bus.write32(frameptr+0x14, self.get_r(Reg::LR));
        self.bus.write32(frameptr+0x18, return_address;
        self.bus.write32(frameptr+0x1c, psr..frameptralign..psr);

        if self.mode == ProcessorMode::ThreadMode
        {
            self.lr = 0xFFFF_FFF1;
        }
        else
        {
            if self.control.sp_sel == false
            {
                self.lr = 0xFFFF_FFF9;
            }
            else
            {
                self.lr = 0xFFFF_FFFD;
            }
        }

        //
        self.mode == ProcessorMode::HandlerMode;
        self.psr.set_ipsr(exception_number);
        self.control.sp_sel = false;
        self.exception_active[exception_number] = true;
        self.scs.update_status_regs();
        self.set_event_register();
        //instruction_sync_barrier();

        let vtor = self.vtor;
        let start = self.bus.read32(vtor + (exception_number * 4));
        self.set_r(Reg::PC, start);
    }
        */

    // Fetch next Thumb2-coded instruction from current
    // PC location. Depending on instruction type, fetches
    // one or two half-words.
    pub fn fetch(&mut self) -> ThumbCode {
        let hw = self.bus.read16(self.pc);

        if is_thumb32(hw) {
            let hw2 = self.bus.read16(self.pc + 2);
            ThumbCode::Thumb32 {
                half_word: hw,
                half_word2: hw2,
            }
        } else {
            ThumbCode::Thumb16 { half_word: hw }
        }
    }

    // Decode ThumbCode into Instruction
    pub fn decode(&self, code: &ThumbCode) -> Instruction {
        match *code {
            ThumbCode::Thumb32 { half_word, half_word2 } => decode_32(half_word, half_word2),
            ThumbCode::Thumb16 { half_word } => decode_16(half_word),
        }
    }

    // Run single instruction on core
    // bkpt_func:
    pub fn step<F>(&mut self, instruction: &Instruction, semihost_func: F)
        where F: FnMut(&SemihostingCommand) -> SemihostingResponse
    {

        execute(self, instruction, semihost_func);
    }
}

impl<'a, T: Bus> fmt::Display for Core<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "PC:{:08X} {}{}{}{}{} R0:{:08X} R1:{:08X} R2:{:08X} R3:{:08X} R4:{:08X} R5:{:08X} \
                  R6:{:08X} R7:{:08X} R8:{:08X} R9:{:08X} R10:{:08X} R11:{:08X} R12:{:08X} SP:{:08X} LR:{:08X}",
                 self.get_r(&Reg::PC),
                 if self.psr.get_z() {'Z'} else {'z'},
                 if self.psr.get_n() {'N'} else {'n'},
                 if self.psr.get_c() {'C'} else {'c'},
                 if self.psr.get_v() {'V'} else {'v'},
                 if self.psr.get_q() {'Q'} else {'q'},
                 self.get_r(&Reg::R0),
                 self.get_r(&Reg::R1),
                 self.get_r(&Reg::R2),
                 self.get_r(&Reg::R3),
                 self.get_r(&Reg::R4),
                 self.get_r(&Reg::R5),
                 self.get_r(&Reg::R6),
                 self.get_r(&Reg::R7),
                 self.get_r(&Reg::R8),
                 self.get_r(&Reg::R9),
                 self.get_r(&Reg::R10),
                 self.get_r(&Reg::R11),
                 self.get_r(&Reg::R12),
                 self.get_r(&Reg::SP),
                 self.get_r(&Reg::LR))
    }
}

<commit_msg>reformat code<commit_after>pub mod condition;
pub mod executor;
pub mod instruction;
pub mod operation;
pub mod register;
pub mod bits;

use bus::Bus;
use core::executor::execute;
use decoder::{decode_16, decode_32, is_thumb32};
use core::register::{Apsr, Control, Epsr, Reg, PSR};
use core::instruction::Instruction;
use std::fmt;
use semihosting::SemihostingCommand;
use semihosting::SemihostingResponse;

pub enum ProcessorMode {
    ThreadMode,
    HandlerMode,
}

pub enum ThumbCode {
    Thumb32 { half_word: u16, half_word2: u16 },
    Thumb16 { half_word: u16 },
}

impl From<u16> for ThumbCode {
    fn from(value: u16) -> Self {
        ThumbCode::Thumb16 { half_word: value }
    }
}

impl From<u32> for ThumbCode {
    fn from(value: u32) -> Self {
        ThumbCode::Thumb32 {
            half_word: (value & 0xffff) as u16,
            half_word2: ((value >> 16) & 0xffff) as u16,
        }
    }
}
impl fmt::Display for ThumbCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThumbCode::Thumb16 { half_word } => write!(f, "0x{:x}", half_word),
            ThumbCode::Thumb32 {
                half_word,
                half_word2,
            } => write!(f, "0x{:x}{:x}", half_word2, half_word),
        }
    }
}

pub struct Core<'a, T: Bus + 'a> {
    /* 13 of 32-bit general purpose registers. */
    r0_12: [u32; 13],

    msp: u32, //MSP, virtual reg r[13]
    psp: u32, //PSP, virtual reg r[13]
    lr: u32,
    pc: u32,

    // TODO, vtor is in SCS
    vtor: u32,

    /* Processor state register, status flags. */
    psr: PSR,

    /* interrupt primary mask, a 1 bit mask register for
       global interrupt masking. */
    primask: bool,

    /* Control bits: currently used stack and execution privilege if core.mode == ThreadMode */
    control: Control,

    /* Processor mode: either handler or thread mode. */
    mode: ProcessorMode,

    /* Bus to which the core is connected. */
    pub bus: &'a mut T,

    /* Is the core simulation currently running or not.*/
    pub running: bool,
}

impl<'a, T: Bus> Core<'a, T> {
    pub fn new(bus: &'a mut T) -> Core<'a, T> {
        Core {
            mode: ProcessorMode::ThreadMode,
            vtor: 0,
            psr: PSR { value: 0 },
            primask: false,
            control: Control {
                n_priv: false,
                sp_sel: false,
            },
            r0_12: [0; 13],
            pc: 0,
            msp: 0,
            psp: 0,
            lr: 0,
            bus: bus,
            running: true,
        }
    }

    //
    // Getter for registers
    //
    pub fn get_r(&self, r: &Reg) -> u32 {
        match *r {
            Reg::R0
            | Reg::R1
            | Reg::R2
            | Reg::R3
            | Reg::R4
            | Reg::R5
            | Reg::R6
            | Reg::R7
            | Reg::R8
            | Reg::R9
            | Reg::R10
            | Reg::R11
            | Reg::R12 => {
                let reg: usize = From::from(*r);
                self.r0_12[reg]
            }
            Reg::SP => if self.control.sp_sel {
                self.psp
            } else {
                self.msp
            },
            Reg::LR => self.lr,
            Reg::PC => self.pc,
        }
    }
    //
    // Setter for registers
    //
    pub fn set_r(&mut self, r: &Reg, value: u32) {
        match *r {
            Reg::R0
            | Reg::R1
            | Reg::R2
            | Reg::R3
            | Reg::R4
            | Reg::R5
            | Reg::R6
            | Reg::R7
            | Reg::R8
            | Reg::R9
            | Reg::R10
            | Reg::R11
            | Reg::R12 => {
                let reg: usize = From::from(*r);
                self.r0_12[reg] = value;
            }
            Reg::SP => if self.control.sp_sel {
                self.psp = value
            } else {
                self.msp = value
            },
            Reg::LR => self.lr = value,
            Reg::PC => self.pc = value,
        };
    }

    pub fn set_msp(&mut self, value: u32) {
        self.msp = value;
    }

    pub fn set_psp(&mut self, value: u32) {
        self.psp = value;
    }

    pub fn add_pc(&mut self, value: u32) {
        self.pc += value;
    }

    pub fn get_pc(&mut self) -> u32 {
        self.pc
    }

    //
    // Setter for registers
    //
    pub fn add_r(&mut self, r: &Reg, value: u32) {
        match *r {
            Reg::R0
            | Reg::R1
            | Reg::R2
            | Reg::R3
            | Reg::R4
            | Reg::R5
            | Reg::R6
            | Reg::R7
            | Reg::R8
            | Reg::R9
            | Reg::R10
            | Reg::R11
            | Reg::R12 => {
                let reg: usize = From::from(*r);
                self.r0_12[reg] += value;
            }
            Reg::SP => if self.control.sp_sel {
                self.psp = value
            } else {
                self.msp += value
            },
            Reg::LR => self.lr += value,
            Reg::PC => self.pc += value,
        };
    }

    //
    // Reset Exception
    //
    pub fn reset(&mut self) {
        // All basic registers to zero.
        self.r0_12[0] = 0;
        self.r0_12[1] = 0;
        self.r0_12[2] = 0;
        self.r0_12[3] = 0;
        self.r0_12[4] = 0;
        self.r0_12[5] = 0;
        self.r0_12[6] = 0;
        self.r0_12[7] = 0;
        self.r0_12[8] = 0;
        self.r0_12[9] = 0;
        self.r0_12[10] = 0;
        self.r0_12[11] = 0;

        // Main stack pointer is read via vector table
        let vtor = self.vtor;
        let sp = self.bus.read32(vtor) & 0xffff_fffc;
        self.set_msp(sp);

        // Process stack pointer to zero
        self.set_psp(0);

        // Link Register
        self.lr = 0;

        // Mode
        self.mode = ProcessorMode::ThreadMode;

        // Apsr, ipsr
        self.psr = PSR { value: 0 };
        self.primask = false;
        self.control.sp_sel = false;
        self.control.n_priv = false;

        //TODO self.scs.reset();
        //TODOself.exceptions.clear();

        //self.event_reg.clear();

        let reset_vector = self.bus.read32(vtor + 4);

        self.set_r(&Reg::PC, reset_vector & 0xffff_fffe);
        self.psr.set_t((reset_vector & 1) == 1);
    }

    /*
    pub fn exception_entry(&mut self, exception_number : u32, return_address : u32)
    {
        // push stack
        let (frameptr, frameptralign) = if self.control.sp_sel && self.mode == ProcessorMode::ThreadMode
        {
            let align = self.psp<2>; ??
            self.psp = (self.psp -0x20) & (4 ^ 0xFFFF_FFFF);
            (self.psp, align)
        }
        else
        {
            let align = self.msp<2>; ??
            self.msp = (self.msp - 0x20)& (4 ^ 0xFFFF_FFFF);
            (self.msp, align)
        }

        self.bus.write32(frameptr, self.get_r(Reg::R0));
        self.bus.write32(frameptr+0x4, self.get_r(Reg::R1));
        self.bus.write32(frameptr+0x8, self.get_r(Reg::R2));
        self.bus.write32(frameptr+0xc, self.get_r(Reg::R3));
        self.bus.write32(frameptr+0x10, self.get_r(Reg::R12));
        self.bus.write32(frameptr+0x14, self.get_r(Reg::LR));
        self.bus.write32(frameptr+0x18, return_address;
        self.bus.write32(frameptr+0x1c, psr..frameptralign..psr);

        if self.mode == ProcessorMode::ThreadMode
        {
            self.lr = 0xFFFF_FFF1;
        }
        else
        {
            if self.control.sp_sel == false
            {
                self.lr = 0xFFFF_FFF9;
            }
            else
            {
                self.lr = 0xFFFF_FFFD;
            }
        }

        //
        self.mode == ProcessorMode::HandlerMode;
        self.psr.set_ipsr(exception_number);
        self.control.sp_sel = false;
        self.exception_active[exception_number] = true;
        self.scs.update_status_regs();
        self.set_event_register();
        //instruction_sync_barrier();

        let vtor = self.vtor;
        let start = self.bus.read32(vtor + (exception_number * 4));
        self.set_r(Reg::PC, start);
    }
        */

    // Fetch next Thumb2-coded instruction from current
    // PC location. Depending on instruction type, fetches
    // one or two half-words.
    pub fn fetch(&mut self) -> ThumbCode {
        let hw = self.bus.read16(self.pc);

        if is_thumb32(hw) {
            let hw2 = self.bus.read16(self.pc + 2);
            ThumbCode::Thumb32 {
                half_word: hw,
                half_word2: hw2,
            }
        } else {
            ThumbCode::Thumb16 { half_word: hw }
        }
    }

    // Decode ThumbCode into Instruction
    pub fn decode(&self, code: &ThumbCode) -> Instruction {
        match *code {
            ThumbCode::Thumb32 {
                half_word,
                half_word2,
            } => decode_32(half_word, half_word2),
            ThumbCode::Thumb16 { half_word } => decode_16(half_word),
        }
    }

    // Run single instruction on core
    // bkpt_func:
    pub fn step<F>(&mut self, instruction: &Instruction, semihost_func: F)
    where
        F: FnMut(&SemihostingCommand) -> SemihostingResponse,
    {
        execute(self, instruction, semihost_func);
    }
}

impl<'a, T: Bus> fmt::Display for Core<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PC:{:08X} {}{}{}{}{} R0:{:08X} R1:{:08X} R2:{:08X} R3:{:08X} R4:{:08X} R5:{:08X} \
                  R6:{:08X} R7:{:08X} R8:{:08X} R9:{:08X} R10:{:08X} R11:{:08X} R12:{:08X} SP:{:08X} LR:{:08X}",
                 self.get_r(&Reg::PC),
                 if self.psr.get_z() {'Z'} else {'z'},
                 if self.psr.get_n() {'N'} else {'n'},
                 if self.psr.get_c() {'C'} else {'c'},
                 if self.psr.get_v() {'V'} else {'v'},
                 if self.psr.get_q() {'Q'} else {'q'},
                 self.get_r(&Reg::R0),
                 self.get_r(&Reg::R1),
                 self.get_r(&Reg::R2),
                 self.get_r(&Reg::R3),
                 self.get_r(&Reg::R4),
                 self.get_r(&Reg::R5),
                 self.get_r(&Reg::R6),
                 self.get_r(&Reg::R7),
                 self.get_r(&Reg::R8),
                 self.get_r(&Reg::R9),
                 self.get_r(&Reg::R10),
                 self.get_r(&Reg::R11),
                 self.get_r(&Reg::R12),
                 self.get_r(&Reg::SP),
                 self.get_r(&Reg::LR))
    }
}
<|endoftext|>


<commit_before>//! Scan the file looking for pointer-sized values that fall within an
//! executable section. Then, step backwards and ensure that the target
//! looks like either:
//!
//!   1. the end of a function, or
//!   2. filler between functions
//!
//! This analysis pass should be particularly useful for finding callbacks,
//! such as the start address passed to `CreateThread`.
//!
//! TODO: but doesn't help find callbacks referenced relatively - need
//! disassembly for this.
//!
//! This analysis pass is also good at handling global vtables.
//! Its especially important when CFGuard metadata is not present.
//!
//! Assumes:
//!   - pointers are 32-bits on x32 and 64-bits on x64 (*not* 32-bits on x64)

use anyhow::Result;
use byteorder::ByteOrder;
use log::debug;

use crate::{aspace::AddressSpace, loader::pe::PE, module::Permissions, VA};

pub fn find_pe_nonrelocated_executable_pointers(pe: &PE) -> Result<Vec<VA>> {
    let mut candidates: Vec<VA> = vec![];

    let min_addr = pe.module.address_space.base_address;
    let max_addr = pe
        .module
        .sections
        .iter()
        .map(|section| section.virtual_range.end)
        .max()
        .unwrap();

    // look for hardcoded pointers into the executable section of the PE.
    // note: this often finds jump tables, too. more filtering is below.
    // note: also finds many exception handlers. see filtering below.
    for section in pe.module.sections.iter() {
        let vstart: VA = section.virtual_range.start;
        let vsize = (section.virtual_range.end - section.virtual_range.start) as usize;
        let sec_buf = pe.module.address_space.read_bytes(vstart, vsize)?;

        debug!(
            "pointers: scanning section {:#x}-{:#x}",
            section.virtual_range.start, section.virtual_range.end
        );

        if let crate::module::Arch::X64 = pe.module.arch {
            candidates.extend(
                sec_buf
                    // using windows for unaligned pointers
                    .windows(8)
                    .map(|b| byteorder::LittleEndian::read_u64(b) as VA)
                    // naive range filter that is very fast
                    .filter(|&va| va >= min_addr && va < max_addr)
                    .filter(|&va| pe.module.probe_va(va, Permissions::X)),
            )
        } else {
            candidates.extend(
                sec_buf
                    // using windows for unaligned pointers
                    .windows(4)
                    .map(|b| byteorder::LittleEndian::read_u32(b) as VA)
                    // naive range filter that is very fast
                    .filter(|&va| va >= min_addr && va < max_addr)
                    .filter(|&va| pe.module.probe_va(va, Permissions::X)),
            )
        }
    }

    // CC debug filler, x86win_patterns.xml#L4
    const CC: u8 = 0xCC;
    // NOP filler, x86win_patterns.xml#L6
    const NOP: u8 = 0x90;
    // RET(N) of prior function, x86win_patterns.xml#L7
    const RET: u8 = 0xC3;

    // now, assert that the prior byte must be a either a RET or filler byte.
    // this should filter out almost all jump tables, etc.
    // should also filter out almost all exception handlers, too.
    // should not be an ASCII string (as seen in 32-bit kernel32)
    Ok(candidates
        .into_iter()
        .filter(|&va| {
            if let Ok(b) = pe.module.address_space.read_u8(va - 1) {
                matches!(b, CC | NOP | RET)
            } else {
                false
            }
        })
        .filter(|&va| {
            if let Ok(ptr) = pe.module.read_va_at_va(va) {
                // the candidate is valid pointer, so its probably not an instruction.
                !pe.module.probe_va(ptr, Permissions::R)
            } else {
                true
            }
        })
        .filter(|&va| matches!(pe.module.address_space.read_ascii(va), Err(_)))
        .collect())
}
<commit_msg>analysis: pointers: improve checks for candidates<commit_after>//! Scan the file looking for pointer-sized values that fall within an
//! executable section. Then, step backwards and ensure that the target
//! looks like either:
//!
//!   1. the end of a function, or
//!   2. filler between functions
//!
//! This analysis pass should be particularly useful for finding callbacks,
//! such as the start address passed to `CreateThread`.
//!
//! TODO: but doesn't help find callbacks referenced relatively - need
//! disassembly for this.
//!
//! This analysis pass is also good at handling global vtables.
//! Its especially important when CFGuard metadata is not present.
//!
//! Assumes:
//!   - pointers are 32-bits on x32 and 64-bits on x64 (*not* 32-bits on x64)

use anyhow::Result;
use byteorder::ByteOrder;
use log::debug;

use crate::{aspace::AddressSpace, loader::pe::PE, module::Permissions, VA};

pub fn find_pe_nonrelocated_executable_pointers(pe: &PE) -> Result<Vec<VA>> {
    let mut candidates: Vec<VA> = vec![];

    let min_addr = pe.module.address_space.base_address;
    let max_addr = pe
        .module
        .sections
        .iter()
        .map(|section| section.virtual_range.end)
        .max()
        .unwrap();

    // look for hardcoded pointers into the executable section of the PE.
    // note: this often finds jump tables, too. more filtering is below.
    // note: also finds many exception handlers. see filtering below.
    for section in pe.module.sections.iter() {
        let vstart: VA = section.virtual_range.start;
        let vsize = (section.virtual_range.end - section.virtual_range.start) as usize;
        let sec_buf = pe.module.address_space.read_bytes(vstart, vsize)?;

        debug!(
            "pointers: scanning section {:#x}-{:#x}",
            section.virtual_range.start, section.virtual_range.end
        );

        if let crate::module::Arch::X64 = pe.module.arch {
            candidates.extend(
                sec_buf
                    // using windows for unaligned pointers
                    .windows(8)
                    .map(|b| byteorder::LittleEndian::read_u64(b) as VA)
                    // naive range filter that is very fast
                    .filter(|&va| va >= min_addr && va < max_addr)
                    .filter(|&va| pe.module.probe_va(va, Permissions::X)),
            )
        } else {
            candidates.extend(
                sec_buf
                    // using windows for unaligned pointers
                    .windows(4)
                    .map(|b| byteorder::LittleEndian::read_u32(b) as VA)
                    // naive range filter that is very fast
                    .filter(|&va| va >= min_addr && va < max_addr)
                    .filter(|&va| pe.module.probe_va(va, Permissions::X)),
            )
        }
    }

    // CC debug filler, x86win_patterns.xml#L4
    const CC: u8 = 0xCC;
    // NOP filler, x86win_patterns.xml#L6
    const NOP: u8 = 0x90;
    // RET of prior function, x86win_patterns.xml#L7
    const RET: u8 = 0xC3;
    const RET_FAR: u8 = 0xCB;
    // RETN of prior function, two byte immediate follows
    const RETN: u8 = 0xC2;

    // now, assert that the prior byte must be a either a RET or filler byte.
    // this should filter out almost all jump tables, etc.
    // should also filter out almost all exception handlers, too.
    // should not be an ASCII string (as seen in 32-bit kernel32)
    Ok(candidates
        .into_iter()
        .filter(|&va| {
            let mut buf = [0u8; 3];
            if matches!(pe.module.address_space.read_into(va - 3, &mut buf), Ok(_)) {
                // va - 3
                if buf[0] == RETN {
                    return true;
                }

                // va - 1
                match buf[2] {
                    CC => return true,
                    NOP => return true,
                    RET => return true,
                    RET_FAR => return true,
                    _ => (),
                }

                debug!("pointers: candidate does not follow ret/filler byte: {:#x}", va);
                false
            } else {
                true
            }
        })
        .filter(|&va| {
            if let Ok(ptr) = pe.module.read_va_at_va(va) {
                // the candidate is valid pointer, so its probably not an instruction.
                if pe.module.probe_va(ptr, Permissions::R) {
                    debug!("pointers: candidate is a valid pointer: {:#x}", va);
                    false
                } else {
                    true
                }
            } else {
                true
            }
        })
        .filter(|&va| {
            if matches!(pe.module.address_space.read_ascii(va), Ok(_)) {
                debug!("pointers: candidate is a string: {:#x}", va);
                false
            } else {
                true
            }
        })
        .map(|va| {
            debug!("pointers: valid candidate: {:#x}", va);
            va
        })
        .collect())
}
<|endoftext|>


<commit_before>//! `completions` crate provides utilities for generating completions of user input.

mod config;
mod item;
mod context;
mod patterns;
mod generated_lint_completions;
#[cfg(test)]
mod test_utils;
mod render;

mod completions;

use completions::flyimport::position_for_import;
use ide_db::{
    base_db::FilePosition,
    helpers::{
        import_assets::{LocatedImport, NameToImport},
        insert_use::ImportScope,
    },
    items_locator, RootDatabase,
};
use text_edit::TextEdit;

use crate::{completions::Completions, context::CompletionContext, item::CompletionKind};

pub use crate::{
    config::CompletionConfig,
    item::{CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit, InsertTextFormat},
};

//FIXME: split the following feature into fine-grained features.

// Feature: Magic Completions
//
// In addition to usual reference completion, rust-analyzer provides some ✨magic✨
// completions as well:
//
// Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
// is placed at the appropriate position. Even though `if` is easy to type, you
// still want to complete it, to get ` { }` for free! `return` is inserted with a
// space or `;` depending on the return type of the function.
//
// When completing a function call, `()` are automatically inserted. If a function
// takes arguments, the cursor is positioned inside the parenthesis.
//
// There are postfix completions, which can be triggered by typing something like
// `foo().if`. The word after `.` determines postfix completion. Possible variants are:
//
// - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result`
// - `expr.match` -> `match expr {}`
// - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
// - `expr.ref` -> `&expr`
// - `expr.refm` -> `&mut expr`
// - `expr.let` -> `let $0 = expr;`
// - `expr.letm` -> `let mut $0 = expr;`
// - `expr.not` -> `!expr`
// - `expr.dbg` -> `dbg!(expr)`
// - `expr.dbgr` -> `dbg!(&expr)`
// - `expr.call` -> `(expr)`
//
// There also snippet completions:
//
// .Expressions
// - `pd` -> `eprintln!(" = {:?}", );`
// - `ppd` -> `eprintln!(" = {:#?}", );`
//
// .Items
// - `tfn` -> `#[test] fn feature(){}`
// - `tmod` ->
// ```rust
// #[cfg(test)]
// mod tests {
//     use super::*;
//
//     #[test]
//     fn test_name() {}
// }
// ```
//
// And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities.
// Those are the additional completion options with automatic `use` import and options from all project importable items,
// fuzzy matched agains the completion imput.
//
// image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[]

/// Main entry point for completion. We run completion as a two-phase process.
///
/// First, we look at the position and collect a so-called `CompletionContext.
/// This is a somewhat messy process, because, during completion, syntax tree is
/// incomplete and can look really weird.
///
/// Once the context is collected, we run a series of completion routines which
/// look at the context and produce completion items. One subtlety about this
/// phase is that completion engine should not filter by the substring which is
/// already present, it should give all possible variants for the identifier at
/// the caret. In other words, for
///
/// ```no_run
/// fn f() {
///     let foo = 92;
///     let _ = bar$0
/// }
/// ```
///
/// `foo` *should* be present among the completion variants. Filtering by
/// identifier prefix/fuzzy match should be done higher in the stack, together
/// with ordering of completions (currently this is done by the client).
///
/// # Hypothetical Completion Problem
///
/// There's a curious unsolved problem in the current implementation. Often, you
/// want to compute completions on a *slightly different* text document.
///
/// In the simplest case, when the code looks like `let x = `, you want to
/// insert a fake identifier to get a better syntax tree: `let x = complete_me`.
///
/// We do this in `CompletionContext`, and it works OK-enough for *syntax*
/// analysis. However, we might want to, eg, ask for the type of `complete_me`
/// variable, and that's where our current infrastructure breaks down. salsa
/// doesn't allow such "phantom" inputs.
///
/// Another case where this would be instrumental is macro expansion. We want to
/// insert a fake ident and re-expand code. There's `expand_hypothetical` as a
/// work-around for this.
///
/// A different use-case is completion of injection (examples and links in doc
/// comments). When computing completion for a path in a doc-comment, you want
/// to inject a fake path expression into the item being documented and complete
/// that.
///
/// IntelliJ has CodeFragment/Context infrastructure for that. You can create a
/// temporary PSI node, and say that the context ("parent") of this node is some
/// existing node. Asking for, eg, type of this `CodeFragment` node works
/// correctly, as the underlying infrastructure makes use of contexts to do
/// analysis.
pub fn completions(
    db: &RootDatabase,
    config: &CompletionConfig,
    position: FilePosition,
) -> Option<Completions> {
    let ctx = CompletionContext::new(db, position, config)?;

    if ctx.no_completion_required() {
        // No work required here.
        return None;
    }

    let mut acc = Completions::default();
    completions::attribute::complete_attribute(&mut acc, &ctx);
    completions::fn_param::complete_fn_param(&mut acc, &ctx);
    completions::keyword::complete_expr_keyword(&mut acc, &ctx);
    completions::keyword::complete_use_tree_keyword(&mut acc, &ctx);
    completions::snippet::complete_expr_snippet(&mut acc, &ctx);
    completions::snippet::complete_item_snippet(&mut acc, &ctx);
    completions::qualified_path::complete_qualified_path(&mut acc, &ctx);
    completions::unqualified_path::complete_unqualified_path(&mut acc, &ctx);
    completions::dot::complete_dot(&mut acc, &ctx);
    completions::record::complete_record(&mut acc, &ctx);
    completions::pattern::complete_pattern(&mut acc, &ctx);
    completions::postfix::complete_postfix(&mut acc, &ctx);
    completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
    completions::trait_impl::complete_trait_impl(&mut acc, &ctx);
    completions::mod_::complete_mod(&mut acc, &ctx);
    completions::flyimport::import_on_the_fly(&mut acc, &ctx);
    completions::lifetime::complete_lifetime(&mut acc, &ctx);
    completions::lifetime::complete_label(&mut acc, &ctx);

    Some(acc)
}

/// Resolves additional completion data at the position given.
pub fn resolve_completion_edits(
    db: &RootDatabase,
    config: &CompletionConfig,
    position: FilePosition,
    full_import_path: &str,
    imported_name: String,
) -> Option<Vec<TextEdit>> {
    let ctx = CompletionContext::new(db, position, config)?;
    let position_for_import = position_for_import(&ctx, None)?;
    let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?;

    let current_module = ctx.sema.scope(position_for_import).module()?;
    let current_crate = current_module.krate();

    let (import_path, item_to_import) = items_locator::items_with_name(
        &ctx.sema,
        current_crate,
        NameToImport::Exact(imported_name),
        items_locator::AssocItemSearch::Include,
        Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
    )
    .filter_map(|candidate| {
        current_module
            .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
            .zip(Some(candidate))
    })
    .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?;
    let import =
        LocatedImport::new(import_path.clone(), item_to_import, item_to_import, Some(import_path));

    ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit])
}

#[cfg(test)]
mod tests {
    use crate::test_utils::{self, TEST_CONFIG};

    struct DetailAndDocumentation<'a> {
        detail: &'a str,
        documentation: &'a str,
    }

    fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
        let (db, position) = test_utils::position(ra_fixture);
        let config = TEST_CONFIG;
        let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into();
        for item in completions {
            if item.detail() == Some(expected.detail) {
                let opt = item.documentation();
                let doc = opt.as_ref().map(|it| it.as_str());
                assert_eq!(doc, Some(expected.documentation));
                return;
            }
        }
        panic!("completion detail not found: {}", expected.detail)
    }

    fn check_no_completion(ra_fixture: &str) {
        let (db, position) = test_utils::position(ra_fixture);
        let config = TEST_CONFIG;

        let completions: Option<Vec<String>> = crate::completions(&db, &config, position)
            .and_then(|completions| {
                let completions: Vec<_> = completions.into();
                if completions.is_empty() {
                    None
                } else {
                    Some(completions)
                }
            })
            .map(|completions| {
                completions.into_iter().map(|completion| format!("{:?}", completion)).collect()
            });

        // `assert_eq` instead of `assert!(completions.is_none())` to get the list of completions if test will panic.
        assert_eq!(completions, None, "Completions were generated, but weren't expected");
    }

    #[test]
    fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
        check_detail_and_documentation(
            r#"
macro_rules! bar {
    () => {
        struct Bar;
        impl Bar {
            #[doc = "Do the foo"]
            fn foo(&self) {}
        }
    }
}

bar!();

fn foo() {
    let bar = Bar;
    bar.fo$0;
}
"#,
            DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" },
        );
    }

    #[test]
    fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() {
        check_detail_and_documentation(
            r#"
macro_rules! bar {
    () => {
        struct Bar;
        impl Bar {
            /// Do the foo
            fn foo(&self) {}
        }
    }
}

bar!();

fn foo() {
    let bar = Bar;
    bar.fo$0;
}
"#,
            DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" },
        );
    }

    #[test]
    fn test_no_completions_required() {
        // There must be no hint for 'in' keyword.
        check_no_completion(r#"fn foo() { for i i$0 }"#);
        // After 'in' keyword hints may be spawned.
        check_detail_and_documentation(
            r#"
/// Do the foo
fn foo() -> &'static str { "foo" }

fn bar() {
    for c in fo$0
}
"#,
            DetailAndDocumentation { detail: "fn() -> &str", documentation: "Do the foo" },
        );
    }
}
<commit_msg>Corrected 2 typos on line 83<commit_after>//! `completions` crate provides utilities for generating completions of user input.

mod config;
mod item;
mod context;
mod patterns;
mod generated_lint_completions;
#[cfg(test)]
mod test_utils;
mod render;

mod completions;

use completions::flyimport::position_for_import;
use ide_db::{
    base_db::FilePosition,
    helpers::{
        import_assets::{LocatedImport, NameToImport},
        insert_use::ImportScope,
    },
    items_locator, RootDatabase,
};
use text_edit::TextEdit;

use crate::{completions::Completions, context::CompletionContext, item::CompletionKind};

pub use crate::{
    config::CompletionConfig,
    item::{CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit, InsertTextFormat},
};

//FIXME: split the following feature into fine-grained features.

// Feature: Magic Completions
//
// In addition to usual reference completion, rust-analyzer provides some ✨magic✨
// completions as well:
//
// Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
// is placed at the appropriate position. Even though `if` is easy to type, you
// still want to complete it, to get ` { }` for free! `return` is inserted with a
// space or `;` depending on the return type of the function.
//
// When completing a function call, `()` are automatically inserted. If a function
// takes arguments, the cursor is positioned inside the parenthesis.
//
// There are postfix completions, which can be triggered by typing something like
// `foo().if`. The word after `.` determines postfix completion. Possible variants are:
//
// - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result`
// - `expr.match` -> `match expr {}`
// - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
// - `expr.ref` -> `&expr`
// - `expr.refm` -> `&mut expr`
// - `expr.let` -> `let $0 = expr;`
// - `expr.letm` -> `let mut $0 = expr;`
// - `expr.not` -> `!expr`
// - `expr.dbg` -> `dbg!(expr)`
// - `expr.dbgr` -> `dbg!(&expr)`
// - `expr.call` -> `(expr)`
//
// There also snippet completions:
//
// .Expressions
// - `pd` -> `eprintln!(" = {:?}", );`
// - `ppd` -> `eprintln!(" = {:#?}", );`
//
// .Items
// - `tfn` -> `#[test] fn feature(){}`
// - `tmod` ->
// ```rust
// #[cfg(test)]
// mod tests {
//     use super::*;
//
//     #[test]
//     fn test_name() {}
// }
// ```
//
// And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities.
// Those are the additional completion options with automatic `use` import and options from all project importable items,
// fuzzy matched against the completion input.
//
// image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[]

/// Main entry point for completion. We run completion as a two-phase process.
///
/// First, we look at the position and collect a so-called `CompletionContext.
/// This is a somewhat messy process, because, during completion, syntax tree is
/// incomplete and can look really weird.
///
/// Once the context is collected, we run a series of completion routines which
/// look at the context and produce completion items. One subtlety about this
/// phase is that completion engine should not filter by the substring which is
/// already present, it should give all possible variants for the identifier at
/// the caret. In other words, for
///
/// ```no_run
/// fn f() {
///     let foo = 92;
///     let _ = bar$0
/// }
/// ```
///
/// `foo` *should* be present among the completion variants. Filtering by
/// identifier prefix/fuzzy match should be done higher in the stack, together
/// with ordering of completions (currently this is done by the client).
///
/// # Hypothetical Completion Problem
///
/// There's a curious unsolved problem in the current implementation. Often, you
/// want to compute completions on a *slightly different* text document.
///
/// In the simplest case, when the code looks like `let x = `, you want to
/// insert a fake identifier to get a better syntax tree: `let x = complete_me`.
///
/// We do this in `CompletionContext`, and it works OK-enough for *syntax*
/// analysis. However, we might want to, eg, ask for the type of `complete_me`
/// variable, and that's where our current infrastructure breaks down. salsa
/// doesn't allow such "phantom" inputs.
///
/// Another case where this would be instrumental is macro expansion. We want to
/// insert a fake ident and re-expand code. There's `expand_hypothetical` as a
/// work-around for this.
///
/// A different use-case is completion of injection (examples and links in doc
/// comments). When computing completion for a path in a doc-comment, you want
/// to inject a fake path expression into the item being documented and complete
/// that.
///
/// IntelliJ has CodeFragment/Context infrastructure for that. You can create a
/// temporary PSI node, and say that the context ("parent") of this node is some
/// existing node. Asking for, eg, type of this `CodeFragment` node works
/// correctly, as the underlying infrastructure makes use of contexts to do
/// analysis.
pub fn completions(
    db: &RootDatabase,
    config: &CompletionConfig,
    position: FilePosition,
) -> Option<Completions> {
    let ctx = CompletionContext::new(db, position, config)?;

    if ctx.no_completion_required() {
        // No work required here.
        return None;
    }

    let mut acc = Completions::default();
    completions::attribute::complete_attribute(&mut acc, &ctx);
    completions::fn_param::complete_fn_param(&mut acc, &ctx);
    completions::keyword::complete_expr_keyword(&mut acc, &ctx);
    completions::keyword::complete_use_tree_keyword(&mut acc, &ctx);
    completions::snippet::complete_expr_snippet(&mut acc, &ctx);
    completions::snippet::complete_item_snippet(&mut acc, &ctx);
    completions::qualified_path::complete_qualified_path(&mut acc, &ctx);
    completions::unqualified_path::complete_unqualified_path(&mut acc, &ctx);
    completions::dot::complete_dot(&mut acc, &ctx);
    completions::record::complete_record(&mut acc, &ctx);
    completions::pattern::complete_pattern(&mut acc, &ctx);
    completions::postfix::complete_postfix(&mut acc, &ctx);
    completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
    completions::trait_impl::complete_trait_impl(&mut acc, &ctx);
    completions::mod_::complete_mod(&mut acc, &ctx);
    completions::flyimport::import_on_the_fly(&mut acc, &ctx);
    completions::lifetime::complete_lifetime(&mut acc, &ctx);
    completions::lifetime::complete_label(&mut acc, &ctx);

    Some(acc)
}

/// Resolves additional completion data at the position given.
pub fn resolve_completion_edits(
    db: &RootDatabase,
    config: &CompletionConfig,
    position: FilePosition,
    full_import_path: &str,
    imported_name: String,
) -> Option<Vec<TextEdit>> {
    let ctx = CompletionContext::new(db, position, config)?;
    let position_for_import = position_for_import(&ctx, None)?;
    let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?;

    let current_module = ctx.sema.scope(position_for_import).module()?;
    let current_crate = current_module.krate();

    let (import_path, item_to_import) = items_locator::items_with_name(
        &ctx.sema,
        current_crate,
        NameToImport::Exact(imported_name),
        items_locator::AssocItemSearch::Include,
        Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
    )
    .filter_map(|candidate| {
        current_module
            .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
            .zip(Some(candidate))
    })
    .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?;
    let import =
        LocatedImport::new(import_path.clone(), item_to_import, item_to_import, Some(import_path));

    ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit])
}

#[cfg(test)]
mod tests {
    use crate::test_utils::{self, TEST_CONFIG};

    struct DetailAndDocumentation<'a> {
        detail: &'a str,
        documentation: &'a str,
    }

    fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
        let (db, position) = test_utils::position(ra_fixture);
        let config = TEST_CONFIG;
        let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into();
        for item in completions {
            if item.detail() == Some(expected.detail) {
                let opt = item.documentation();
                let doc = opt.as_ref().map(|it| it.as_str());
                assert_eq!(doc, Some(expected.documentation));
                return;
            }
        }
        panic!("completion detail not found: {}", expected.detail)
    }

    fn check_no_completion(ra_fixture: &str) {
        let (db, position) = test_utils::position(ra_fixture);
        let config = TEST_CONFIG;

        let completions: Option<Vec<String>> = crate::completions(&db, &config, position)
            .and_then(|completions| {
                let completions: Vec<_> = completions.into();
                if completions.is_empty() {
                    None
                } else {
                    Some(completions)
                }
            })
            .map(|completions| {
                completions.into_iter().map(|completion| format!("{:?}", completion)).collect()
            });

        // `assert_eq` instead of `assert!(completions.is_none())` to get the list of completions if test will panic.
        assert_eq!(completions, None, "Completions were generated, but weren't expected");
    }

    #[test]
    fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
        check_detail_and_documentation(
            r#"
macro_rules! bar {
    () => {
        struct Bar;
        impl Bar {
            #[doc = "Do the foo"]
            fn foo(&self) {}
        }
    }
}

bar!();

fn foo() {
    let bar = Bar;
    bar.fo$0;
}
"#,
            DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" },
        );
    }

    #[test]
    fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() {
        check_detail_and_documentation(
            r#"
macro_rules! bar {
    () => {
        struct Bar;
        impl Bar {
            /// Do the foo
            fn foo(&self) {}
        }
    }
}

bar!();

fn foo() {
    let bar = Bar;
    bar.fo$0;
}
"#,
            DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" },
        );
    }

    #[test]
    fn test_no_completions_required() {
        // There must be no hint for 'in' keyword.
        check_no_completion(r#"fn foo() { for i i$0 }"#);
        // After 'in' keyword hints may be spawned.
        check_detail_and_documentation(
            r#"
/// Do the foo
fn foo() -> &'static str { "foo" }

fn bar() {
    for c in fo$0
}
"#,
            DetailAndDocumentation { detail: "fn() -> &str", documentation: "Do the foo" },
        );
    }
}
<|endoftext|>


<commit_before>use backend::Backend;
use connection::Connection;
use dsl::Limit;
use query_builder::{AsQuery, QueryFragment, QueryId};
use query_source::Queryable;
use result::{first_or_not_found, QueryResult};
use super::LimitDsl;
use types::HasSqlType;

pub trait LoadQuery<Conn, U>: LoadDsl<Conn> {
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<U>>;
}

impl<Conn, T, U> LoadQuery<Conn, U> for T
where
    Conn: Connection,
    Conn::Backend: HasSqlType<T::SqlType>,
    T: AsQuery,
    T::Query: QueryFragment<Conn::Backend> + QueryId,
    U: Queryable<T::SqlType, Conn::Backend>,
{
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<U>> {
        conn.query_by_index(self)
    }
}

/// Methods to execute a query given a connection. These are automatically implemented for the
/// various query types.
pub trait LoadDsl<Conn>: Sized {
    /// Executes the given query, returning a `Vec` with the returned rows.
    fn load<U>(self, conn: &Conn) -> QueryResult<Vec<U>>
    where
        Self: LoadQuery<Conn, U>,
    {
        self.internal_load(conn)
    }

    /// Runs the command, and returns the affected row. `Err(NotFound)` will be
    /// returned if the query affected 0 rows. You can call `.optional()` on the
    /// result of this if the command was optional to get back a
    /// `Result<Option<U>>`
    fn get_result<U>(self, conn: &Conn) -> QueryResult<U>
    where
        Self: LoadQuery<Conn, U>,
    {
        first_or_not_found(self.load(conn))
    }

    /// Runs the command, returning an `Vec` with the affected rows.
    fn get_results<U>(self, conn: &Conn) -> QueryResult<Vec<U>>
    where
        Self: LoadQuery<Conn, U>,
    {
        self.load(conn)
    }
}

impl<Conn, T> LoadDsl<Conn> for T
where
    // These constraints are fairly redundant with `Self: LoadQuery`,
    // But since `LoadQuery` has a second type parameter, it can't be
    // used to prove impls on things like `SupportsReturningClause` are disjoint.
    // If disjointness on associated types ever lands, we can drop all of these
    // except `T: AsQuery`
    Conn: Connection,
    Conn::Backend: HasSqlType<T::SqlType>,
    T: AsQuery,
    T::Query: QueryFragment<Conn::Backend> + QueryId,
{
}

pub trait FirstDsl<Conn>: LimitDsl + LoadDsl<Conn> {
    /// Attempts to load a single record. Returns `Ok(record)` if found, and
    /// `Err(NotFound)` if no results are returned. If the query truly is
    /// optional, you can call `.optional()` on the result of this to get a
    /// `Result<Option<U>>`.
    fn first<U>(self, conn: &Conn) -> QueryResult<U>
    where
        Limit<Self>: LoadQuery<Conn, U>,
    {
        self.limit(1).get_result(conn)
    }
}

impl<Conn, T: LimitDsl + LoadDsl<Conn>> FirstDsl<Conn> for T {}

pub trait ExecuteDsl<Conn: Connection<Backend = DB>, DB: Backend = <Conn as Connection>::Backend>
    : Sized {
    /// Executes the given command, returning the number of rows affected. Used
    /// in conjunction with
    /// [`update`](/diesel/fn.update.html) and
    /// [`delete`](/diesel/fn.delete.html)
    fn execute(self, conn: &Conn) -> QueryResult<usize>;
}

impl<Conn, T> ExecuteDsl<Conn> for T
where
    Conn: Connection,
    T: QueryFragment<Conn::Backend> + QueryId,
{
    fn execute(self, conn: &Conn) -> QueryResult<usize> {
        conn.execute_returning_count(&self)
    }
}
<commit_msg>Add an example for FirstDsl::first<commit_after>use backend::Backend;
use connection::Connection;
use dsl::Limit;
use query_builder::{AsQuery, QueryFragment, QueryId};
use query_source::Queryable;
use result::{first_or_not_found, QueryResult};
use super::LimitDsl;
use types::HasSqlType;

pub trait LoadQuery<Conn, U>: LoadDsl<Conn> {
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<U>>;
}

impl<Conn, T, U> LoadQuery<Conn, U> for T
where
    Conn: Connection,
    Conn::Backend: HasSqlType<T::SqlType>,
    T: AsQuery,
    T::Query: QueryFragment<Conn::Backend> + QueryId,
    U: Queryable<T::SqlType, Conn::Backend>,
{
    fn internal_load(self, conn: &Conn) -> QueryResult<Vec<U>> {
        conn.query_by_index(self)
    }
}

/// Methods to execute a query given a connection. These are automatically implemented for the
/// various query types.
pub trait LoadDsl<Conn>: Sized {
    /// Executes the given query, returning a `Vec` with the returned rows.
    fn load<U>(self, conn: &Conn) -> QueryResult<Vec<U>>
    where
        Self: LoadQuery<Conn, U>,
    {
        self.internal_load(conn)
    }

    /// Runs the command, and returns the affected row. `Err(NotFound)` will be
    /// returned if the query affected 0 rows. You can call `.optional()` on the
    /// result of this if the command was optional to get back a
    /// `Result<Option<U>>`
    fn get_result<U>(self, conn: &Conn) -> QueryResult<U>
    where
        Self: LoadQuery<Conn, U>,
    {
        first_or_not_found(self.load(conn))
    }

    /// Runs the command, returning an `Vec` with the affected rows.
    fn get_results<U>(self, conn: &Conn) -> QueryResult<Vec<U>>
    where
        Self: LoadQuery<Conn, U>,
    {
        self.load(conn)
    }
}

impl<Conn, T> LoadDsl<Conn> for T
where
    // These constraints are fairly redundant with `Self: LoadQuery`,
    // But since `LoadQuery` has a second type parameter, it can't be
    // used to prove impls on things like `SupportsReturningClause` are disjoint.
    // If disjointness on associated types ever lands, we can drop all of these
    // except `T: AsQuery`
    Conn: Connection,
    Conn::Backend: HasSqlType<T::SqlType>,
    T: AsQuery,
    T::Query: QueryFragment<Conn::Backend> + QueryId,
{
}

pub trait FirstDsl<Conn>: LimitDsl + LoadDsl<Conn> {
    /// Attempts to load a single record. Returns `Ok(record)` if found, and
    /// `Err(NotFound)` if no results are returned. If the query truly is
    /// optional, you can call `.optional()` on the result of this to get a
    /// `Result<Option<U>>`.
    ///
    /// # Example:
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel_codegen;
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// # use diesel::NotFound;
    /// table! {
    ///     users {
    ///         id -> Integer,
    ///         name -> VarChar,
    ///     }
    /// }
    ///
    /// #[derive(Queryable, PartialEq, Debug)]
    /// struct User {
    ///     id: i32,
    ///     name: String,
    /// }
    ///
    /// # fn main() {
    /// #   let connection = establish_connection();
    /// let user1 = NewUser { name: "Sean".into() };
    /// let user2 = NewUser { name: "Pascal".into() };
    /// diesel::insert(&vec![user1, user2]).into(users::table).execute(&connection).unwrap();
    ///
    /// let user = users::table.order(users::id.asc()).first(&connection);
    /// assert_eq!(Ok(User { id: 1, name: "Sean".into() }), user);
    /// let user = users::table.filter(users::name.eq("Foo")).first::<User>(&connection);
    /// assert_eq!(Err(NotFound), user);
    /// # }
    /// ```
    fn first<U>(self, conn: &Conn) -> QueryResult<U>
    where
        Limit<Self>: LoadQuery<Conn, U>,
    {
        self.limit(1).get_result(conn)
    }
}

impl<Conn, T: LimitDsl + LoadDsl<Conn>> FirstDsl<Conn> for T {}

pub trait ExecuteDsl<Conn: Connection<Backend = DB>, DB: Backend = <Conn as Connection>::Backend>
    : Sized {
    /// Executes the given command, returning the number of rows affected. Used
    /// in conjunction with
    /// [`update`](/diesel/fn.update.html) and
    /// [`delete`](/diesel/fn.delete.html)
    fn execute(self, conn: &Conn) -> QueryResult<usize>;
}

impl<Conn, T> ExecuteDsl<Conn> for T
where
    Conn: Connection,
    T: QueryFragment<Conn::Backend> + QueryId,
{
    fn execute(self, conn: &Conn) -> QueryResult<usize> {
        conn.execute_returning_count(&self)
    }
}
<|endoftext|>


<commit_before>#[allow(dead_code)]
mod demo;
#[allow(dead_code)]
mod util;

use crate::demo::{ui, App};
use argh::FromArgs;
use crossterm::{
    event::{self, Event as CEvent, KeyCode},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::{
    error::Error,
    io::{stdout, Write},
    sync::mpsc,
    thread,
    time::{Duration, Instant},
};
use tui::{backend::CrosstermBackend, Terminal};

enum Event<I> {
    Input(I),
    Tick,
}

/// Crossterm demo
#[derive(Debug, FromArgs)]
struct Cli {
    /// time in ms between two ticks.
    #[argh(option, default = "250")]
    tick_rate: u64,
    /// whether unicode symbols are used to improve the overall look of the app
    #[argh(option, default = "true")]
    enhanced_graphics: bool,
}

fn main() -> Result<(), Box<dyn Error>> {
    let cli: Cli = argh::from_env();

    enable_raw_mode()?;

    let mut stdout = stdout();
    execute!(stdout, EnterAlternateScreen)?;

    let backend = CrosstermBackend::new(stdout);

    let mut terminal = Terminal::new(backend)?;
    terminal.hide_cursor()?;

    // Setup input handling
    let (tx, rx) = mpsc::channel();

    let tick_rate = Duration::from_millis(cli.tick_rate);
    thread::spawn(move || {
        let mut last_tick = Instant::now();
        loop {
            // poll for tick rate duration, if no events, sent tick event.
            if event::poll(tick_rate - last_tick.elapsed()).unwrap() {
                if let CEvent::Key(key) = event::read().unwrap() {
                    tx.send(Event::Input(key)).unwrap();
                }
            }
            if last_tick.elapsed() >= tick_rate {
                tx.send(Event::Tick).unwrap();
                last_tick = Instant::now();
            }
        }
    });

    let mut app = App::new("Crossterm Demo", cli.enhanced_graphics);

    terminal.clear()?;

    loop {
        terminal.draw(|mut f| ui::draw(&mut f, &mut app))?;
        match rx.recv()? {
            Event::Input(event) => match event.code {
                KeyCode::Char('q') => {
                    disable_raw_mode()?;
                    execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
                    terminal.show_cursor()?;
                    break;
                }
                KeyCode::Char(c) => app.on_key(c),
                KeyCode::Left => app.on_left(),
                KeyCode::Up => app.on_up(),
                KeyCode::Right => app.on_right(),
                KeyCode::Down => app.on_down(),
                _ => {}
            },
            Event::Tick => {
                app.on_tick();
            }
        }
        if app.should_quit {
            break;
        }
    }

    Ok(())
}
<commit_msg>feat(examples): enable mouse capture to make crossterm demo on par with termion<commit_after>#[allow(dead_code)]
mod demo;
#[allow(dead_code)]
mod util;

use crate::demo::{ui, App};
use argh::FromArgs;
use crossterm::{
    event::{self, DisableMouseCapture, EnableMouseCapture, Event as CEvent, KeyCode},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::{
    error::Error,
    io::{stdout, Write},
    sync::mpsc,
    thread,
    time::{Duration, Instant},
};
use tui::{backend::CrosstermBackend, Terminal};

enum Event<I> {
    Input(I),
    Tick,
}

/// Crossterm demo
#[derive(Debug, FromArgs)]
struct Cli {
    /// time in ms between two ticks.
    #[argh(option, default = "250")]
    tick_rate: u64,
    /// whether unicode symbols are used to improve the overall look of the app
    #[argh(option, default = "true")]
    enhanced_graphics: bool,
}

fn main() -> Result<(), Box<dyn Error>> {
    let cli: Cli = argh::from_env();

    enable_raw_mode()?;

    let mut stdout = stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;

    let backend = CrosstermBackend::new(stdout);

    let mut terminal = Terminal::new(backend)?;
    terminal.hide_cursor()?;

    // Setup input handling
    let (tx, rx) = mpsc::channel();

    let tick_rate = Duration::from_millis(cli.tick_rate);
    thread::spawn(move || {
        let mut last_tick = Instant::now();
        loop {
            // poll for tick rate duration, if no events, sent tick event.
            if event::poll(tick_rate - last_tick.elapsed()).unwrap() {
                if let CEvent::Key(key) = event::read().unwrap() {
                    tx.send(Event::Input(key)).unwrap();
                }
            }
            if last_tick.elapsed() >= tick_rate {
                tx.send(Event::Tick).unwrap();
                last_tick = Instant::now();
            }
        }
    });

    let mut app = App::new("Crossterm Demo", cli.enhanced_graphics);

    terminal.clear()?;

    loop {
        terminal.draw(|mut f| ui::draw(&mut f, &mut app))?;
        match rx.recv()? {
            Event::Input(event) => match event.code {
                KeyCode::Char('q') => {
                    disable_raw_mode()?;
                    execute!(
                        terminal.backend_mut(),
                        LeaveAlternateScreen,
                        DisableMouseCapture
                    )?;
                    terminal.show_cursor()?;
                    break;
                }
                KeyCode::Char(c) => app.on_key(c),
                KeyCode::Left => app.on_left(),
                KeyCode::Up => app.on_up(),
                KeyCode::Right => app.on_right(),
                KeyCode::Down => app.on_down(),
                _ => {}
            },
            Event::Tick => {
                app.on_tick();
            }
        }
        if app.should_quit {
            break;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::result;

use analysis::ref_mode::RefMode;
use env::Env;
use library::{self, Nullable};
use super::conversion_type::ConversionType;
use traits::*;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TypeError {
    Ignored(String),
    Mismatch(String),
    Unimplemented(String),
}

pub type Result = result::Result<String, TypeError>;

fn into_inner(res: Result) -> String {
    use self::TypeError::*;
    match res {
        Ok(s) |
            Err(Ignored(s)) |
            Err(Mismatch(s)) |
            Err(Unimplemented(s)) => s,
    }
}

impl IntoString for Result {
    fn into_string(self) -> String {
        use self::TypeError::*;
        match self {
            Ok(s) => s,
            Err(Ignored(s)) => format!("/*Ignored*/{}", s),
            Err(Mismatch(s)) => format!("/*Metadata mismatch*/{}", s),
            Err(Unimplemented(s)) => format!("/*Unimplemented*/{}", s),
        }
    }
}

impl MapAny<String> for Result {
    fn map_any<F: FnOnce(String) -> String>(self, op: F) -> Result {
        use self::TypeError::*;
        match self {
            Ok(s) => Ok(op(s)),
            Err(Ignored(s)) => Err(Ignored(op(s))),
            Err(Mismatch(s)) => Err(Mismatch(op(s))),
            Err(Unimplemented(s)) => Err(Unimplemented(op(s))),
        }
    }
}

pub fn rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::None)
}

pub fn bounds_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::ByRefFake)
}

fn rust_type_full(env: &Env, type_id: library::TypeId, nullable: Nullable, ref_mode: RefMode) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let mut skip_option = false;
    let type_ = env.library.type_(type_id);
    let mut rust_type = match *type_ {
        Fundamental(fund) => {
            let ok = |s: &str| Ok(s.into());
            let err = |s: &str| Err(TypeError::Unimplemented(s.into()));
            match fund {
                None => err("()"),
                Boolean => ok("bool"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("i32"),      //maybe dependent on target system
                UInt => ok("u32"),     //maybe dependent on target system

                Float => ok("f32"),
                Double => ok("f64"),

                UniChar => ok("char"),
                Utf8 => if ref_mode.is_ref() { ok("str") } else { ok("String") },
                Filename => {
                    if ref_mode.is_ref() {
                        ok("std::path::Path")
                    }
                    else {
                        ok("std::path::PathBuf")
                    }
                }
                Type => ok("glib::types::Type"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        },
        Alias(ref alias) => {
            rust_type_full(env, alias.typ, nullable, ref_mode)
                .map_any(|_| alias.name.clone())
        }
        Enumeration(..) |
            Bitfield(..) => Ok(type_.get_name().to_owned()),
        Record(..) |
            Class(..) |
            Interface(..) => {
            let name = type_.get_name().to_owned();
            if env.type_status(&type_id.full_name(&env.library)).ignored() {
                Err(TypeError::Ignored(name))
            }
            else {
                Ok(name)
            }
        }
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid)
            if ConversionType::of(&env.library, inner_tid) == ConversionType::Pointer => {
            skip_option = true;
            let inner_ref_mode = match *env.library.type_(inner_tid) {
                Class(..) |
                    Interface(..) => RefMode::None,
                _ => ref_mode,
            };
            rust_type_full(env, inner_tid, Nullable(false), inner_ref_mode)
                .map_any(|s| if ref_mode.is_ref() {
                    format!("[{}]", s)
                } else {
                    format!("Vec<{}>", s)
                })
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    };

    if type_id.ns_id != library::MAIN_NAMESPACE && type_id.ns_id != library::INTERNAL_NAMESPACE
        && !implemented_in_main_namespace(&env.library, type_id) {
        if env.type_status(&type_id.full_name(&env.library)).ignored() {
            rust_type = Err(TypeError::Ignored(into_inner(rust_type)));
        }
        rust_type = rust_type.map_any(|s| format!("{}::{}",
            env.namespaces[type_id.ns_id].higher_crate_name, s));
    }

    match ref_mode {
        RefMode::None | RefMode::ByRefFake => {}
        RefMode::ByRef | RefMode::ByRefImmut => rust_type = rust_type.map_any(|s| format!("&{}", s)),
        RefMode::ByRefMut => rust_type = rust_type.map_any(|s| format!("&mut {}", s)),
    }
    if *nullable && !skip_option {
        match ConversionType::of(&env.library, type_id) {
            ConversionType::Pointer
                | ConversionType::Scalar => {
                rust_type = rust_type.map_any(|s| format!("Option<{}>", s))
            }
            _ => (),
        }
    }

    rust_type
}

pub fn used_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    match *env.library.type_(type_id) {
        Fundamental(library::Fundamental::Type) |
            Alias(..) |
            Bitfield(..) |
            Record(..) |
            Class(..) |
            Enumeration(..) |
            Interface(..) => rust_type(env, type_id),
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid) => used_rust_type(env, inner_tid),
        _ => Err(TypeError::Ignored("Don't need use".to_owned())),
    }
}

pub fn parameter_rust_type(env: &Env, type_id:library::TypeId,
                           direction: library::ParameterDirection, nullable: Nullable,
                           ref_mode: RefMode) -> Result {
    use library::Type::*;
    let type_ = env.library.type_(type_id);
    let rust_type = rust_type_full(env, type_id, nullable, ref_mode);
    match *type_ {
        Fundamental(fund) => {
            if fund == library::Fundamental::Utf8 || fund == library::Fundamental::Filename {
                match direction {
                    library::ParameterDirection::In |
                        library::ParameterDirection::Return => rust_type,
                    _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
                }
            } else {
                rust_type.map_any(|s| format_parameter(s, direction))
            }
        }
        Alias(ref alias) => {
            rust_type.and_then(|s| {
                parameter_rust_type(env, alias.typ, direction, nullable, ref_mode)
                    .map_any(|_| s)
            })
                .map_any(|s| format_parameter(s, direction))
        }

        Enumeration(..) |
            Bitfield(..) => rust_type.map_any(|s| format_parameter(s, direction)),

        Record(..) => {
            if direction == library::ParameterDirection::InOut {
                Err(TypeError::Unimplemented(into_inner(rust_type)))
            } else {
                rust_type
            }
        }

        Class(..) |
            Interface (..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Out |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }

        List(..) |
            SList(..) |
            CArray(..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    }
}

#[inline]
fn format_parameter(rust_type: String, direction: library::ParameterDirection) -> String {
    if direction.is_out() {
        format!("&mut {}", rust_type)
    } else {
        rust_type
    }
}

fn implemented_in_main_namespace(library: &library::Library, type_id: library::TypeId) -> bool {
    match &*type_id.full_name(library) {
        "GLib.Error" => return true,
        _ => (),
    }
    if library.namespace(library::MAIN_NAMESPACE).name != "Gtk" {
        return false;
    }
    match &*type_id.full_name(library) {
        "Gdk.Rectangle" => true,
        _ => false,
    }
}
<commit_msg>Reflect the VariantType/VariantTy duality<commit_after>use std::result;

use analysis::ref_mode::RefMode;
use env::Env;
use library::{self, Nullable};
use super::conversion_type::ConversionType;
use traits::*;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TypeError {
    Ignored(String),
    Mismatch(String),
    Unimplemented(String),
}

pub type Result = result::Result<String, TypeError>;

fn into_inner(res: Result) -> String {
    use self::TypeError::*;
    match res {
        Ok(s) |
            Err(Ignored(s)) |
            Err(Mismatch(s)) |
            Err(Unimplemented(s)) => s,
    }
}

impl IntoString for Result {
    fn into_string(self) -> String {
        use self::TypeError::*;
        match self {
            Ok(s) => s,
            Err(Ignored(s)) => format!("/*Ignored*/{}", s),
            Err(Mismatch(s)) => format!("/*Metadata mismatch*/{}", s),
            Err(Unimplemented(s)) => format!("/*Unimplemented*/{}", s),
        }
    }
}

impl MapAny<String> for Result {
    fn map_any<F: FnOnce(String) -> String>(self, op: F) -> Result {
        use self::TypeError::*;
        match self {
            Ok(s) => Ok(op(s)),
            Err(Ignored(s)) => Err(Ignored(op(s))),
            Err(Mismatch(s)) => Err(Mismatch(op(s))),
            Err(Unimplemented(s)) => Err(Unimplemented(op(s))),
        }
    }
}

pub fn rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::None)
}

pub fn bounds_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::ByRefFake)
}

fn rust_type_full(env: &Env, type_id: library::TypeId, nullable: Nullable, ref_mode: RefMode) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let ok = |s: &str| Ok(s.into());
    let err = |s: &str| Err(TypeError::Unimplemented(s.into()));
    let mut skip_option = false;
    let type_ = env.library.type_(type_id);
    let mut rust_type = match *type_ {
        Fundamental(fund) => {
            match fund {
                None => err("()"),
                Boolean => ok("bool"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("i32"),      //maybe dependent on target system
                UInt => ok("u32"),     //maybe dependent on target system

                Float => ok("f32"),
                Double => ok("f64"),

                UniChar => ok("char"),
                Utf8 => if ref_mode.is_ref() { ok("str") } else { ok("String") },
                Filename => {
                    if ref_mode.is_ref() {
                        ok("std::path::Path")
                    }
                    else {
                        ok("std::path::PathBuf")
                    }
                }
                Type => ok("glib::types::Type"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        },
        Alias(ref alias) => {
            rust_type_full(env, alias.typ, nullable, ref_mode)
                .map_any(|_| alias.name.clone())
        }
        Record(library::Record { ref c_type, .. }) if c_type == "GVariantType" => {
            if ref_mode.is_ref() { ok("VariantTy") } else { ok("VariantType") }
        }
        Enumeration(..) |
            Bitfield(..) => Ok(type_.get_name().to_owned()),
        Record(..) |
            Class(..) |
            Interface(..) => {
            let name = type_.get_name().to_owned();
            if env.type_status(&type_id.full_name(&env.library)).ignored() {
                Err(TypeError::Ignored(name))
            }
            else {
                Ok(name)
            }
        }
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid)
            if ConversionType::of(&env.library, inner_tid) == ConversionType::Pointer => {
            skip_option = true;
            let inner_ref_mode = match *env.library.type_(inner_tid) {
                Class(..) |
                    Interface(..) => RefMode::None,
                _ => ref_mode,
            };
            rust_type_full(env, inner_tid, Nullable(false), inner_ref_mode)
                .map_any(|s| if ref_mode.is_ref() {
                    format!("[{}]", s)
                } else {
                    format!("Vec<{}>", s)
                })
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    };

    if type_id.ns_id != library::MAIN_NAMESPACE && type_id.ns_id != library::INTERNAL_NAMESPACE
        && !implemented_in_main_namespace(&env.library, type_id) {
        if env.type_status(&type_id.full_name(&env.library)).ignored() {
            rust_type = Err(TypeError::Ignored(into_inner(rust_type)));
        }
        rust_type = rust_type.map_any(|s| format!("{}::{}",
            env.namespaces[type_id.ns_id].higher_crate_name, s));
    }

    match ref_mode {
        RefMode::None | RefMode::ByRefFake => {}
        RefMode::ByRef | RefMode::ByRefImmut => rust_type = rust_type.map_any(|s| format!("&{}", s)),
        RefMode::ByRefMut => rust_type = rust_type.map_any(|s| format!("&mut {}", s)),
    }
    if *nullable && !skip_option {
        match ConversionType::of(&env.library, type_id) {
            ConversionType::Pointer
                | ConversionType::Scalar => {
                rust_type = rust_type.map_any(|s| format!("Option<{}>", s))
            }
            _ => (),
        }
    }

    rust_type
}

pub fn used_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    match *env.library.type_(type_id) {
        Fundamental(library::Fundamental::Type) |
            Alias(..) |
            Bitfield(..) |
            Record(..) |
            Class(..) |
            Enumeration(..) |
            Interface(..) => rust_type(env, type_id),
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid) => used_rust_type(env, inner_tid),
        _ => Err(TypeError::Ignored("Don't need use".to_owned())),
    }
}

pub fn parameter_rust_type(env: &Env, type_id:library::TypeId,
                           direction: library::ParameterDirection, nullable: Nullable,
                           ref_mode: RefMode) -> Result {
    use library::Type::*;
    let type_ = env.library.type_(type_id);
    let rust_type = rust_type_full(env, type_id, nullable, ref_mode);
    match *type_ {
        Fundamental(fund) => {
            if fund == library::Fundamental::Utf8 || fund == library::Fundamental::Filename {
                match direction {
                    library::ParameterDirection::In |
                        library::ParameterDirection::Return => rust_type,
                    _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
                }
            } else {
                rust_type.map_any(|s| format_parameter(s, direction))
            }
        }
        Alias(ref alias) => {
            rust_type.and_then(|s| {
                parameter_rust_type(env, alias.typ, direction, nullable, ref_mode)
                    .map_any(|_| s)
            })
                .map_any(|s| format_parameter(s, direction))
        }

        Enumeration(..) |
            Bitfield(..) => rust_type.map_any(|s| format_parameter(s, direction)),

        Record(..) => {
            if direction == library::ParameterDirection::InOut {
                Err(TypeError::Unimplemented(into_inner(rust_type)))
            } else {
                rust_type
            }
        }

        Class(..) |
            Interface (..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Out |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }

        List(..) |
            SList(..) |
            CArray(..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    }
}

#[inline]
fn format_parameter(rust_type: String, direction: library::ParameterDirection) -> String {
    if direction.is_out() {
        format!("&mut {}", rust_type)
    } else {
        rust_type
    }
}

fn implemented_in_main_namespace(library: &library::Library, type_id: library::TypeId) -> bool {
    match &*type_id.full_name(library) {
        "GLib.Error" => return true,
        _ => (),
    }
    if library.namespace(library::MAIN_NAMESPACE).name != "Gtk" {
        return false;
    }
    match &*type_id.full_name(library) {
        "Gdk.Rectangle" => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>// run-pass

// edition:2018
// aux-build:arc_wake.rs

#![feature(async_await)]

extern crate arc_wake;

use std::pin::Pin;
use std::future::Future;
use std::sync::{
    Arc,
    atomic::{self, AtomicUsize},
};
use std::task::{Context, Poll};
use arc_wake::ArcWake;

struct Counter {
    wakes: AtomicUsize,
}

impl ArcWake for Counter {
    fn wake(self: Arc<Self>) {
        Self::wake_by_ref(&self)
    }
    fn wake_by_ref(arc_self: &Arc<Self>) {
        arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
    }
}

struct WakeOnceThenComplete(bool);

fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }

impl Future for WakeOnceThenComplete {
    type Output = ();
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
        if self.0 {
            Poll::Ready(())
        } else {
            cx.waker().wake_by_ref();
            self.0 = true;
            Poll::Pending
        }
    }
}

fn async_block(x: u8) -> impl Future<Output = u8> {
    async move {
        wake_and_yield_once().await;
        x
    }
}

fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
    async move {
        wake_and_yield_once().await;
        *x
    }
}

fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
    async move {
        let future = async {
            wake_and_yield_once().await;
            x
        };
        future.await
    }
}

// see async-closure.rs for async_closure + async_closure_in_unsafe_block

async fn async_fn(x: u8) -> u8 {
    wake_and_yield_once().await;
    x
}

async fn generic_async_fn<T>(x: T) -> T {
    wake_and_yield_once().await;
    x
}

async fn async_fn_with_borrow(x: &u8) -> u8 {
    wake_and_yield_once().await;
    *x
}

async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
    wake_and_yield_once().await;
    *x
}

fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
    async move {
        wake_and_yield_once().await;
        *x
    }
}

/* FIXME(cramertj) support when `type T<'a, 'b> = impl;` works
async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
    await!(wake_and_yield_once());
    *x
}
*/

async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
    wake_and_yield_once().await;
    *x
}

fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
    async move {
        async_fn_with_borrow_named_lifetime(&y).await
    }
}

async unsafe fn unsafe_async_fn(x: u8) -> u8 {
    wake_and_yield_once().await;
    x
}

unsafe fn unsafe_fn(x: u8) -> u8 {
    x
}

fn async_block_in_unsafe_block(x: u8) -> impl Future<Output = u8> {
    unsafe {
        async move {
            unsafe_fn(unsafe_async_fn(x).await)
        }
    }
}

struct Foo;

trait Bar {
    fn foo() {}
}

impl Foo {
    async fn async_assoc_item(x: u8) -> u8 {
        unsafe {
            unsafe_async_fn(x).await
        }
    }

    async unsafe fn async_unsafe_assoc_item(x: u8) -> u8 {
        unsafe_async_fn(x).await
    }
}

fn test_future_yields_once_then_returns<F, Fut>(f: F)
where
    F: FnOnce(u8) -> Fut,
    Fut: Future<Output = u8>,
{
    let mut fut = Box::pin(f(9));
    let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
    let waker = ArcWake::into_waker(counter.clone());
    let mut cx = Context::from_waker(&waker);
    assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
    assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
    assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
    assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
}

fn main() {
    macro_rules! test {
        ($($fn_name:expr,)*) => { $(
            test_future_yields_once_then_returns($fn_name);
        )* }
    }

    macro_rules! test_with_borrow {
        ($($fn_name:expr,)*) => { $(
            test_future_yields_once_then_returns(|x| {
                async move {
                    $fn_name(&x).await
                }
            });
        )* }
    }

    test! {
        async_block,
        async_nonmove_block,
        async_fn,
        generic_async_fn,
        async_fn_with_internal_borrow,
        async_block_in_unsafe_block,
        Foo::async_assoc_item,
        |x| {
            async move {
                unsafe { unsafe_async_fn(x).await }
            }
        },
        |x| {
            async move {
                unsafe { Foo::async_unsafe_assoc_item(x).await }
            }
        },
    }
    test_with_borrow! {
        async_block_with_borrow_named_lifetime,
        async_fn_with_borrow,
        async_fn_with_borrow_named_lifetime,
        async_fn_with_impl_future_named_lifetime,
        |x| {
            async move {
                async_fn_multiple_args_named_lifetime(x, x).await
            }
        },
    }
}
<commit_msg>Resolve FIXME with async-await test<commit_after>// run-pass

// edition:2018
// aux-build:arc_wake.rs

#![feature(async_await)]

extern crate arc_wake;

use std::pin::Pin;
use std::future::Future;
use std::sync::{
    Arc,
    atomic::{self, AtomicUsize},
};
use std::task::{Context, Poll};
use arc_wake::ArcWake;

struct Counter {
    wakes: AtomicUsize,
}

impl ArcWake for Counter {
    fn wake(self: Arc<Self>) {
        Self::wake_by_ref(&self)
    }
    fn wake_by_ref(arc_self: &Arc<Self>) {
        arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
    }
}

struct WakeOnceThenComplete(bool);

fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }

impl Future for WakeOnceThenComplete {
    type Output = ();
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
        if self.0 {
            Poll::Ready(())
        } else {
            cx.waker().wake_by_ref();
            self.0 = true;
            Poll::Pending
        }
    }
}

fn async_block(x: u8) -> impl Future<Output = u8> {
    async move {
        wake_and_yield_once().await;
        x
    }
}

fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
    async move {
        wake_and_yield_once().await;
        *x
    }
}

fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
    async move {
        let future = async {
            wake_and_yield_once().await;
            x
        };
        future.await
    }
}

// see async-closure.rs for async_closure + async_closure_in_unsafe_block

async fn async_fn(x: u8) -> u8 {
    wake_and_yield_once().await;
    x
}

async fn generic_async_fn<T>(x: T) -> T {
    wake_and_yield_once().await;
    x
}

async fn async_fn_with_borrow(x: &u8) -> u8 {
    wake_and_yield_once().await;
    *x
}

async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
    wake_and_yield_once().await;
    *x
}

fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
    async move {
        wake_and_yield_once().await;
        *x
    }
}

async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
    wake_and_yield_once().await;
    *x
}

async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
    wake_and_yield_once().await;
    *x
}

fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
    async move {
        async_fn_with_borrow_named_lifetime(&y).await
    }
}

async unsafe fn unsafe_async_fn(x: u8) -> u8 {
    wake_and_yield_once().await;
    x
}

unsafe fn unsafe_fn(x: u8) -> u8 {
    x
}

fn async_block_in_unsafe_block(x: u8) -> impl Future<Output = u8> {
    unsafe {
        async move {
            unsafe_fn(unsafe_async_fn(x).await)
        }
    }
}

struct Foo;

trait Bar {
    fn foo() {}
}

impl Foo {
    async fn async_assoc_item(x: u8) -> u8 {
        unsafe {
            unsafe_async_fn(x).await
        }
    }

    async unsafe fn async_unsafe_assoc_item(x: u8) -> u8 {
        unsafe_async_fn(x).await
    }
}

fn test_future_yields_once_then_returns<F, Fut>(f: F)
where
    F: FnOnce(u8) -> Fut,
    Fut: Future<Output = u8>,
{
    let mut fut = Box::pin(f(9));
    let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
    let waker = ArcWake::into_waker(counter.clone());
    let mut cx = Context::from_waker(&waker);
    assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
    assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
    assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
    assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
}

fn main() {
    macro_rules! test {
        ($($fn_name:expr,)*) => { $(
            test_future_yields_once_then_returns($fn_name);
        )* }
    }

    macro_rules! test_with_borrow {
        ($($fn_name:expr,)*) => { $(
            test_future_yields_once_then_returns(|x| {
                async move {
                    $fn_name(&x).await
                }
            });
        )* }
    }

    test! {
        async_block,
        async_nonmove_block,
        async_fn,
        generic_async_fn,
        async_fn_with_internal_borrow,
        async_block_in_unsafe_block,
        Foo::async_assoc_item,
        |x| {
            async move {
                unsafe { unsafe_async_fn(x).await }
            }
        },
        |x| {
            async move {
                unsafe { Foo::async_unsafe_assoc_item(x).await }
            }
        },
    }
    test_with_borrow! {
        async_block_with_borrow_named_lifetime,
        async_fn_with_borrow,
        async_fn_with_borrow_named_lifetime,
        async_fn_with_impl_future_named_lifetime,
        |x| {
            async move {
                async_fn_multiple_args_named_lifetime(x, x).await
            }
        },
    }
}
<|endoftext|>