<commit_before>use std::fmt;
use std::fmt::{Debug, Formatter};
use track::{Span, Posn, Untrack};
use word::{Reserved, Name};

#[derive(Debug, PartialEq, Clone)]
pub struct Token {
    pub location: Span,
    pub newline: bool,    // was there a newline between the preceding token and this one?
    pub value: TokenData
}

impl Token {
    pub fn new(start: Posn, end: Posn, value: TokenData) -> Token {
        Token {
            location: Span { start: start, end: end },
            newline: false,
            value: value
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum TokenData {
    Reserved(Reserved),

    // 11.7 Punctuators
    LBrace,
    RBrace,
    LParen,
    RParen,
    LBrack,
    RBrack,
    Dot,
    Ellipsis,
    Semi,
    Comma,
    LAngle,
    RAngle,
    LEq,
    GEq,
    Eq,
    NEq,
    StrictEq,
    StrictNEq,
    Plus,
    Minus,
    Star,
    Mod,
    Slash,
    Inc,
    Dec,
    LShift,
    RShift,
    URShift,
    BitAnd,
    BitOr,
    BitXor,
    Bang,
    Tilde,
    LogicalAnd,
    LogicalOr,
    Question,
    Colon,
    Assign,
    PlusAssign,
    MinusAssign,
    StarAssign,
    SlashAssign,
    ModAssign,
    LShiftAssign,
    RShiftAssign,
    URShiftAssign,
    BitAndAssign,
    BitOrAssign,
    BitXorAssign,
    Arrow,

    Number(NumberLiteral),
    String(StringLiteral),
    RegExp(RegExpLiteral),

    Identifier(Name),

    EOF
}

impl TokenData {
    pub fn is_string(&self) -> bool {
        match *self {
            TokenData::String(_) => true,
            _ => false
        }
    }
}

#[derive(Clone)]
pub struct RegExpLiteral {
    pub pattern: String,
    pub flags: Vec<char>
}

impl Untrack for RegExpLiteral {
    fn untrack(&mut self) {}
}

trait CharsEx {
    fn alphabetize(&self) -> Vec<char>;
}

impl CharsEx for Vec<char> {
    fn alphabetize(&self) -> Vec<char> {
        let mut x: Vec<char> = self.to_vec();
        x.sort();
        x
    }
}

impl Debug for RegExpLiteral {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("RegExpLiteral")
            .field("pattern", &self.pattern)
            .field("flags", &self.flags.alphabetize())
            .finish()
    }
}

impl PartialEq for RegExpLiteral {
    fn eq(&self, other: &Self) -> bool {
        (self.pattern == other.pattern) &&
        (self.flags.alphabetize() == other.flags.alphabetize())
    }
}

#[derive(Clone)]
pub struct StringLiteral {
    pub source: Option<String>,
    pub value: String
}

impl Untrack for StringLiteral {
    fn untrack(&mut self) {}
}

impl Debug for StringLiteral {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("StringLiteral")
            .field("value", &self.value)
            .finish()
    }
}

impl PartialEq for StringLiteral {
    fn eq(&self, other: &Self) -> bool {
        self.value == other.value
    }
}

#[derive(Clone)]
pub struct NumberLiteral {
    pub source: Option<NumberSource>,
    pub value: f64
}

impl Untrack for NumberLiteral {
    fn untrack(&mut self) {}
}

impl Debug for NumberLiteral {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("NumberLiteral")
            .field("value", &self.value)
            .finish()
    }
}

impl PartialEq for NumberLiteral {
    fn eq(&self, other: &Self) -> bool {
        self.value == other.value
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum NumberSource {
    DecimalInt(String, Option<Exp>),
    RadixInt(Radix, String),
    Float(Option<String>, Option<String>, Option<Exp>)
}

fn format_sign(sign: &Option<Sign>) -> String {
    match *sign {
        Some(Sign::Minus) => "-",
        _ => ""
    }.to_string()
}

fn format_int(src: &Option<String>) -> String {
    match *src {
        None        => "".to_string(),
        Some(ref s) => s.to_string()
    }
}

impl NumberSource {
    pub fn value(&self) -> f64 {
        match *self {
            NumberSource::DecimalInt(ref mantissa, None) => {
                let i: i64 = mantissa.parse().unwrap();
                i as f64
            }
            NumberSource::DecimalInt(ref mantissa, Some(Exp { ref sign, ref value, .. })) => {
                let mantissa: i64 = mantissa.parse().unwrap();
                let mantissa: f64 = mantissa as f64;
                let exp: i32 = value.parse().unwrap();
                mantissa * (10 as f64).powi(if *sign == Some(Sign::Minus) { -exp } else { exp })
            }
            NumberSource::RadixInt(ref radix, ref src) => {
                let i = i64::from_str_radix(&src[..], radix.value()).unwrap();
                i as f64
            }
            NumberSource::Float(ref ip, ref fp, None) => {
                format!("{}.{}", format_int(ip), format_int(fp)).parse().unwrap()
            }
            NumberSource::Float(ref ip, ref fp, Some(Exp { ref sign, ref value, .. })) => {
                format!("{}.{}e{}{}", format_int(ip), format_int(fp), format_sign(sign), value).parse().unwrap()
            }
        }
    }

    pub fn into_token_data(self) -> TokenData {
        let value = self.value();
        TokenData::Number(NumberLiteral {
            source: Some(self),
            value: value
        })
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Exp {
    pub e: CharCase,
    pub sign: Option<Sign>,
    pub value: String
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Radix {
    Bin(CharCase),
    Oct(Option<CharCase>),
    Hex(CharCase)
}

impl Radix {
    pub fn value(&self) -> u32 {
        match *self {
            Radix::Bin(_) => 2,
            Radix::Oct(_) => 8,
            Radix::Hex(_) => 16
        }
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum CharCase {
    LowerCase,
    UpperCase
}

#[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(test, derive(Deserialize))]
pub enum Sign {
    #[cfg_attr(test, serde(rename = "+"))]
    Plus,

    #[cfg_attr(test, serde(rename = "-"))]
    Minus
}
<commit_msg>Fix panic on parsing big decimal integers<commit_after>use std::fmt;
use std::fmt::{Debug, Formatter};
use track::{Span, Posn, Untrack};
use word::{Reserved, Name};

#[derive(Debug, PartialEq, Clone)]
pub struct Token {
    pub location: Span,
    pub newline: bool,    // was there a newline between the preceding token and this one?
    pub value: TokenData
}

impl Token {
    pub fn new(start: Posn, end: Posn, value: TokenData) -> Token {
        Token {
            location: Span { start: start, end: end },
            newline: false,
            value: value
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum TokenData {
    Reserved(Reserved),

    // 11.7 Punctuators
    LBrace,
    RBrace,
    LParen,
    RParen,
    LBrack,
    RBrack,
    Dot,
    Ellipsis,
    Semi,
    Comma,
    LAngle,
    RAngle,
    LEq,
    GEq,
    Eq,
    NEq,
    StrictEq,
    StrictNEq,
    Plus,
    Minus,
    Star,
    Mod,
    Slash,
    Inc,
    Dec,
    LShift,
    RShift,
    URShift,
    BitAnd,
    BitOr,
    BitXor,
    Bang,
    Tilde,
    LogicalAnd,
    LogicalOr,
    Question,
    Colon,
    Assign,
    PlusAssign,
    MinusAssign,
    StarAssign,
    SlashAssign,
    ModAssign,
    LShiftAssign,
    RShiftAssign,
    URShiftAssign,
    BitAndAssign,
    BitOrAssign,
    BitXorAssign,
    Arrow,

    Number(NumberLiteral),
    String(StringLiteral),
    RegExp(RegExpLiteral),

    Identifier(Name),

    EOF
}

impl TokenData {
    pub fn is_string(&self) -> bool {
        match *self {
            TokenData::String(_) => true,
            _ => false
        }
    }
}

#[derive(Clone)]
pub struct RegExpLiteral {
    pub pattern: String,
    pub flags: Vec<char>
}

impl Untrack for RegExpLiteral {
    fn untrack(&mut self) {}
}

trait CharsEx {
    fn alphabetize(&self) -> Vec<char>;
}

impl CharsEx for Vec<char> {
    fn alphabetize(&self) -> Vec<char> {
        let mut x: Vec<char> = self.to_vec();
        x.sort();
        x
    }
}

impl Debug for RegExpLiteral {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("RegExpLiteral")
            .field("pattern", &self.pattern)
            .field("flags", &self.flags.alphabetize())
            .finish()
    }
}

impl PartialEq for RegExpLiteral {
    fn eq(&self, other: &Self) -> bool {
        (self.pattern == other.pattern) &&
        (self.flags.alphabetize() == other.flags.alphabetize())
    }
}

#[derive(Clone)]
pub struct StringLiteral {
    pub source: Option<String>,
    pub value: String
}

impl Untrack for StringLiteral {
    fn untrack(&mut self) {}
}

impl Debug for StringLiteral {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("StringLiteral")
            .field("value", &self.value)
            .finish()
    }
}

impl PartialEq for StringLiteral {
    fn eq(&self, other: &Self) -> bool {
        self.value == other.value
    }
}

#[derive(Clone)]
pub struct NumberLiteral {
    pub source: Option<NumberSource>,
    pub value: f64
}

impl Untrack for NumberLiteral {
    fn untrack(&mut self) {}
}

impl Debug for NumberLiteral {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("NumberLiteral")
            .field("value", &self.value)
            .finish()
    }
}

impl PartialEq for NumberLiteral {
    fn eq(&self, other: &Self) -> bool {
        self.value == other.value
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum NumberSource {
    DecimalInt(String, Option<Exp>),
    RadixInt(Radix, String),
    Float(Option<String>, Option<String>, Option<Exp>)
}

fn format_sign(sign: &Option<Sign>) -> String {
    match *sign {
        Some(Sign::Minus) => "-",
        _ => ""
    }.to_string()
}

fn format_int(src: &Option<String>) -> String {
    match *src {
        None        => "".to_string(),
        Some(ref s) => s.to_string()
    }
}

impl NumberSource {
    pub fn value(&self) -> f64 {
        match *self {
            NumberSource::DecimalInt(ref mantissa, None) => {
                mantissa.parse().unwrap()
            }
            NumberSource::DecimalInt(ref mantissa, Some(Exp { ref sign, ref value, .. })) => {
                format!("{}e{}{}", mantissa, format_sign(sign), value).parse().unwrap()
            }
            NumberSource::RadixInt(ref radix, ref src) => {
                let i = i64::from_str_radix(&src[..], radix.value()).unwrap();
                i as f64
            }
            NumberSource::Float(ref ip, ref fp, None) => {
                format!("{}.{}", format_int(ip), format_int(fp)).parse().unwrap()
            }
            NumberSource::Float(ref ip, ref fp, Some(Exp { ref sign, ref value, .. })) => {
                format!("{}.{}e{}{}", format_int(ip), format_int(fp), format_sign(sign), value).parse().unwrap()
            }
        }
    }

    pub fn into_token_data(self) -> TokenData {
        let value = self.value();
        TokenData::Number(NumberLiteral {
            source: Some(self),
            value: value
        })
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Exp {
    pub e: CharCase,
    pub sign: Option<Sign>,
    pub value: String
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Radix {
    Bin(CharCase),
    Oct(Option<CharCase>),
    Hex(CharCase)
}

impl Radix {
    pub fn value(&self) -> u32 {
        match *self {
            Radix::Bin(_) => 2,
            Radix::Oct(_) => 8,
            Radix::Hex(_) => 16
        }
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum CharCase {
    LowerCase,
    UpperCase
}

#[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(test, derive(Deserialize))]
pub enum Sign {
    #[cfg_attr(test, serde(rename = "+"))]
    Plus,

    #[cfg_attr(test, serde(rename = "-"))]
    Minus
}
<|endoftext|>


<commit_before><commit_msg>Making some of the IndexWriter's method public.<commit_after><|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Intterupt handling on x86 machines.
//!
//! This module provides support for interrupt handling on both `x86` and
//! `x86_64` as a black box. Code that depends on this can use the same API
//! regardless of system word size.
#![warn(missing_docs)]
pub mod idt;
pub mod pics;

use vga::{CONSOLE, Color};

use core::fmt;
use core::fmt::Write;

use context::InterruptFrame;

pub const NUM_EXCEPTIONS: usize = 20;

/// An ISR that handles a regular interrupt
pub type InterruptHandler = extern "x86-interrupt" fn (&InterruptFrame);
/// An ISR that handles an error with an error code
pub type ErrorCodeHandler = extern "x86-interrupt" fn (&InterruptFrame, usize);

/// A description of a CPU exception
#[derive(Debug)]
pub struct ExceptionInfo { /// The name of the exception
                           pub name: &'static str
                         , /// The mnemomic code for the exception
                           pub mnemonic: &'static str
                         , /// The type of IRQ for this exception
                           /// - fault
                           /// - trap
                           /// - interrupt
                           pub irq_type: &'static str
                         , /// The source triggering the exception.
                           ///
                           /// Typically this refers to what opcode(s) can
                           /// cause this exception.
                           pub source: &'static str
                         }

/// x86 exceptions.
///
/// Taken from the list at
/// [http://wiki.osdev.org/Exceptions](http://wiki.osdev.org/Exceptions)
pub static EXCEPTIONS: [ExceptionInfo; NUM_EXCEPTIONS]
    = [ ExceptionInfo { name: "Divide-By-Zero Error"
                      , mnemonic: "#DE", irq_type: "Fault"
                      , source: "DIV or IDIV instruction" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "#DB", irq_type: "Fault/trap"
                      , source: "Reserved for Intel use" }
      , ExceptionInfo { name: "Non-Maskable Interrupt"
                      , mnemonic: "NMI", irq_type: "Interrupt"
                      , source: "Non-maskable external interrupt" }
      , ExceptionInfo { name: "Breakpoint"
                      , mnemonic: "#BP", irq_type: "Trap"
                      , source: "INT 3 instruction" }
      , ExceptionInfo { name: "Overflow"
                      , mnemonic: "#OF", irq_type: "Trap"
                      , source: "INTO instruction" }
      , ExceptionInfo { name: "BOUND Range Exceeded"
                      , mnemonic: "#BR", irq_type: "Fault"
                      , source: "BOUND instruction" }
      , ExceptionInfo { name: "Undefined Opcode"
                     , mnemonic: "#UD", irq_type: "Fault"
                     , source: "UD2 instruction or reserved opcode" }
      , ExceptionInfo { name: "Device Not Available"
                      , mnemonic: "#NM", irq_type: "Fault"
                      , source: "Floating-point or WAIT/FWAIT instruction\
                                 (no math coprocessor)" }
      , ExceptionInfo { name: "Double Fault"
                      , mnemonic: "#DF", irq_type: "Abort"
                      , source: "Any instruction that can generate an\
                                 exception, a NMI, or an INTR" }
      , ExceptionInfo { name: "Coprocessor Segment Overrun"
                      , mnemonic: "", irq_type: "Fault"
                      , source: "Any floating-point instruction" }
      , ExceptionInfo { name: "Invalid TSS"
                      , mnemonic: "#TS", irq_type: "Fault"
                      , source: "Task switch or TSS access" }
      , ExceptionInfo { name: "Segment Not Present"
                      , mnemonic: "#NP", irq_type: "Fault"
                      , source: "Loading segment registers or accessing\
                                 system segments" }
      , ExceptionInfo { name: "Stack-Segment Fault"
                      , mnemonic: "#SS", irq_type: "Fault"
                      , source: "Stack operations and SS register loads" }
      , ExceptionInfo { name: "General Protection"
                      , mnemonic: "#GP", irq_type: "Fault"
                      , source: "Any memory reference or other protection\
                                 checks" }
      , ExceptionInfo { name: "Page Fault"
                      , mnemonic: "#PF", irq_type: "Fault"
                      , source: "Any memory reference" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "", irq_type: ""
                      , source: "RESERVED FOR INTEL USE \n This should never \
                                 happen. Something is very wrong." }
      , ExceptionInfo { name: "x87 FPU Floating-Point Error (Math Fault)"
                      , mnemonic: "#MF", irq_type: "Fault"
                      , source: "x87 FPU floating-point or WAIT/FWAIT\
                                 instruction" }
      , ExceptionInfo { name: "Alignment Check"
                      , mnemonic: "#AC", irq_type: "Fault"
                      , source: "Any data reference in memory" }
      , ExceptionInfo { name: "Machine Check"
                      , mnemonic: "#MC", irq_type: "Abort"
                      , source: "Model-dependent" }
      , ExceptionInfo { name: "SIMD Floating-Point Exception"
                      , mnemonic: "#XM", irq_type: "Fault"
                      , source: "SSE/SSE2/SSE3 floating-point instructions" }
       ];

bitflags! {
   flags PageFaultErrorCode: u32 {
       /// If 1, the error was caused by a page that was present.
       /// Otherwise, the page was non-present.
       const PRESENT = 1 << 0
     , /// If 1, the error was caused by a read. If 0, the cause was a write.
       const READ_WRITE = 1 << 1
     , /// If 1, the error was caused during user-mode execution.
       /// If 0, the processor was in kernel mode.
       const USER_MODE = 1 << 2
     , /// If 1, the fault was caused by reserved bits set to 1 during a fetch.
       const RESERVED = 1 << 3
     , /// If 1, the fault was caused during an instruction fetch.
       const INST_FETCH = 1 << 4
     , /// If 1, there was a protection key violation.
       const PROTECTION = 1 << 5
   }
}

impl fmt::Display for PageFaultErrorCode {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!( f, "Caused by {}{}{} during a {}{} executing in {} mode."
             , if self.contains(PRESENT) { "a present page" }
               else { "a non-present page" }
             , if self.contains(PROTECTION) { " protection-key violation" }
               else { "" }
             , if self.contains(RESERVED) { " reserved bits set to one "}
               else { "" }
             , if self.contains(READ_WRITE) { "read" } else { "write" }
             , if self.contains(INST_FETCH) { " in an instruction fetch"}
               else { "" }
             , if self.contains(USER_MODE) { "user" } else { "kernel" }            )
   }
}

/// Handler for the system timer interrupt
pub extern "x86-interrupt" fn timer(_frame: &InterruptFrame) {
    // do nothing, just signal the pics to end the IRQ
    // println!("timer!");
    unsafe { pics::end_pic_interrupt(0x21); }
}

/// Handles page fault exceptions
#[no_mangle] #[inline(never)]
pub extern "x86-interrupt" fn page_fault( frame: &InterruptFrame, error_code: usize) {
   unsafe {
       let _ = write!( CONSOLE.lock()
                          .set_colors(Color::White, Color::Blue)
                       //   .clear()
                 , "IT'S NOT MY FAULT: Page Fault at {:p} \
                    \nError code: {:#x}\n\n{}\n{:?}"
                 , (*frame).rip
                 , error_code
                 , PageFaultErrorCode::from_bits_truncate(error_code as u32)
                 , *frame
                 );
    }
   // TODO: stack dumps please

   loop { }
}

/// Test interrupt handler for ensuring that the IDT is configured correctly.
#[no_mangle] #[inline(never)]
pub extern "x86-interrupt" fn test(_frame: &InterruptFrame) {
   // assert_eq!(state.int_id, 0x80);
   kinfoln!(dots: " . . ", target: "Testing interrupt handling:", "[ OKAY ]");
   // send the PICs the end interrupt signal
   unsafe {
       pics::end_pic_interrupt(0xff);
   }
}

/// Empty dummy handler for undefined interrupts.
#[no_mangle] #[inline(never)]
pub extern "x86-interrupt" fn empty_handler(_frame: &InterruptFrame) {
   // assert_eq!(state.int_id, 0x80);
   println!("interrupt");
   // send the PICs the end interrupt signal
   // unsafe {
   //     end_pic_interrupt(0xff);
   // }
}

macro_rules! make_handlers {
    ( $(ex $ex_num:expr, $name:ident),+ ) => {
        $(
            #[no_mangle] #[allow(missing_docs)]
            pub extern "x86-interrupt" fn $name(frame: &InterruptFrame) {
                unsafe {
                    let ex_info = &EXCEPTIONS[$ex_num];
                    // let cr_state = control_regs::dump();
                    let _ = write!( CONSOLE.lock()
                                           .set_colors(Color::White, Color::Blue)
                                  , "EVERYTHING IS FINE: {}{} at {:p}\n\
                                     Exception on vector {}.\n\
                                     Source: {}.\nThis is fine.\n\n\
                                     {:?}"
                                     , ex_info.name, ex_info.irq_type
                                     , (*frame).rip
                                     , $ex_num
                                     , ex_info.source
                                     , *frame);
                    loop { }
                }
            }
        )+
    };
    ( $(err $ex_num:expr, $name:ident) ,+ ) => {
        $(
            #[no_mangle] #[allow(missing_docs)]
            pub extern "x86-interrupt" fn $name( frame: &InterruptFrame
                                   , err_code: usize) {
                unsafe {
                    let ex_info = &EXCEPTIONS[$ex_num];
                    // let cr_state = control_regs::dump();
                    let _ = write!( CONSOLE.lock()
                                           .set_colors(Color::White, Color::Blue)
                                  , "EVERYTHING IS FINE: {}{} at {:p}\n\
                                     Exception on vector {} with error code {:#x}.\n\
                                     Source: {}.\nThis is fine.\n\n\
                                     {:?}"
                                  , ex_info.name, ex_info.irq_type
                                  , (*frame).rip
                                  , $ex_num, err_code
                                  , ex_info.source
                                  , *frame);
                    loop { }
                }
            }
        )+
    };
}
make_handlers! { ex 0, ex0
               , ex 1, ex1
               , ex 2, ex2
                // ex 3 is breakpoint
               , ex 4, ex4
               , ex 5, ex5
               , ex 6, ex6
               , ex 7, ex7
               , ex 16, ex16
               , ex 18, ex18
               , ex 19, ex19
               }
make_handlers! { err 8, ex8
               , err 10, ex10
               , err 11, ex11
               , err 12, ex12
               , err 13, ex13
               , err 17, ex17 }
<commit_msg>refac(interrupts): remove unecessary unsafe blocks<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Intterupt handling on x86 machines.
//!
//! This module provides support for interrupt handling on both `x86` and
//! `x86_64` as a black box. Code that depends on this can use the same API
//! regardless of system word size.
#![warn(missing_docs)]
pub mod idt;
pub mod pics;

use vga::{CONSOLE, Color};

use core::fmt;
use core::fmt::Write;

use context::InterruptFrame;

pub const NUM_EXCEPTIONS: usize = 20;

/// An ISR that handles a regular interrupt
pub type InterruptHandler = extern "x86-interrupt" fn (&InterruptFrame);
/// An ISR that handles an error with an error code
pub type ErrorCodeHandler = extern "x86-interrupt" fn (&InterruptFrame, usize);

/// A description of a CPU exception
#[derive(Debug)]
pub struct ExceptionInfo { /// The name of the exception
                           pub name: &'static str
                         , /// The mnemomic code for the exception
                           pub mnemonic: &'static str
                         , /// The type of IRQ for this exception
                           /// - fault
                           /// - trap
                           /// - interrupt
                           pub irq_type: &'static str
                         , /// The source triggering the exception.
                           ///
                           /// Typically this refers to what opcode(s) can
                           /// cause this exception.
                           pub source: &'static str
                         }

/// x86 exceptions.
///
/// Taken from the list at
/// [http://wiki.osdev.org/Exceptions](http://wiki.osdev.org/Exceptions)
pub static EXCEPTIONS: [ExceptionInfo; NUM_EXCEPTIONS]
    = [ ExceptionInfo { name: "Divide-By-Zero Error"
                      , mnemonic: "#DE", irq_type: "Fault"
                      , source: "DIV or IDIV instruction" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "#DB", irq_type: "Fault/trap"
                      , source: "Reserved for Intel use" }
      , ExceptionInfo { name: "Non-Maskable Interrupt"
                      , mnemonic: "NMI", irq_type: "Interrupt"
                      , source: "Non-maskable external interrupt" }
      , ExceptionInfo { name: "Breakpoint"
                      , mnemonic: "#BP", irq_type: "Trap"
                      , source: "INT 3 instruction" }
      , ExceptionInfo { name: "Overflow"
                      , mnemonic: "#OF", irq_type: "Trap"
                      , source: "INTO instruction" }
      , ExceptionInfo { name: "BOUND Range Exceeded"
                      , mnemonic: "#BR", irq_type: "Fault"
                      , source: "BOUND instruction" }
      , ExceptionInfo { name: "Undefined Opcode"
                     , mnemonic: "#UD", irq_type: "Fault"
                     , source: "UD2 instruction or reserved opcode" }
      , ExceptionInfo { name: "Device Not Available"
                      , mnemonic: "#NM", irq_type: "Fault"
                      , source: "Floating-point or WAIT/FWAIT instruction\
                                 (no math coprocessor)" }
      , ExceptionInfo { name: "Double Fault"
                      , mnemonic: "#DF", irq_type: "Abort"
                      , source: "Any instruction that can generate an\
                                 exception, a NMI, or an INTR" }
      , ExceptionInfo { name: "Coprocessor Segment Overrun"
                      , mnemonic: "", irq_type: "Fault"
                      , source: "Any floating-point instruction" }
      , ExceptionInfo { name: "Invalid TSS"
                      , mnemonic: "#TS", irq_type: "Fault"
                      , source: "Task switch or TSS access" }
      , ExceptionInfo { name: "Segment Not Present"
                      , mnemonic: "#NP", irq_type: "Fault"
                      , source: "Loading segment registers or accessing\
                                 system segments" }
      , ExceptionInfo { name: "Stack-Segment Fault"
                      , mnemonic: "#SS", irq_type: "Fault"
                      , source: "Stack operations and SS register loads" }
      , ExceptionInfo { name: "General Protection"
                      , mnemonic: "#GP", irq_type: "Fault"
                      , source: "Any memory reference or other protection\
                                 checks" }
      , ExceptionInfo { name: "Page Fault"
                      , mnemonic: "#PF", irq_type: "Fault"
                      , source: "Any memory reference" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "", irq_type: ""
                      , source: "RESERVED FOR INTEL USE \n This should never \
                                 happen. Something is very wrong." }
      , ExceptionInfo { name: "x87 FPU Floating-Point Error (Math Fault)"
                      , mnemonic: "#MF", irq_type: "Fault"
                      , source: "x87 FPU floating-point or WAIT/FWAIT\
                                 instruction" }
      , ExceptionInfo { name: "Alignment Check"
                      , mnemonic: "#AC", irq_type: "Fault"
                      , source: "Any data reference in memory" }
      , ExceptionInfo { name: "Machine Check"
                      , mnemonic: "#MC", irq_type: "Abort"
                      , source: "Model-dependent" }
      , ExceptionInfo { name: "SIMD Floating-Point Exception"
                      , mnemonic: "#XM", irq_type: "Fault"
                      , source: "SSE/SSE2/SSE3 floating-point instructions" }
       ];

bitflags! {
   flags PageFaultErrorCode: u32 {
       /// If 1, the error was caused by a page that was present.
       /// Otherwise, the page was non-present.
       const PRESENT = 1 << 0
     , /// If 1, the error was caused by a read. If 0, the cause was a write.
       const READ_WRITE = 1 << 1
     , /// If 1, the error was caused during user-mode execution.
       /// If 0, the processor was in kernel mode.
       const USER_MODE = 1 << 2
     , /// If 1, the fault was caused by reserved bits set to 1 during a fetch.
       const RESERVED = 1 << 3
     , /// If 1, the fault was caused during an instruction fetch.
       const INST_FETCH = 1 << 4
     , /// If 1, there was a protection key violation.
       const PROTECTION = 1 << 5
   }
}

impl fmt::Display for PageFaultErrorCode {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!( f, "Caused by {}{}{} during a {}{} executing in {} mode."
             , if self.contains(PRESENT) { "a present page" }
               else { "a non-present page" }
             , if self.contains(PROTECTION) { " protection-key violation" }
               else { "" }
             , if self.contains(RESERVED) { " reserved bits set to one "}
               else { "" }
             , if self.contains(READ_WRITE) { "read" } else { "write" }
             , if self.contains(INST_FETCH) { " in an instruction fetch"}
               else { "" }
             , if self.contains(USER_MODE) { "user" } else { "kernel" }            )
   }
}

/// Handler for the system timer interrupt
pub extern "x86-interrupt" fn timer(_frame: &InterruptFrame) {
    // do nothing, just signal the pics to end the IRQ
    // println!("timer!");
    unsafe { pics::end_pic_interrupt(0x21); }
}

/// Handles page fault exceptions
#[no_mangle] #[inline(never)]
pub extern "x86-interrupt" fn page_fault( frame: &InterruptFrame, error_code: usize) {
   let _ = write!( CONSOLE.lock()
                      .set_colors(Color::White, Color::Blue)
                   //   .clear()
             , "IT'S NOT MY FAULT: Page Fault at {:p} \
                \nError code: {:#x}\n\n{}\n{:?}"
             , (*frame).rip
             , error_code
             , PageFaultErrorCode::from_bits_truncate(error_code as u32)
             , *frame
             );
   // TODO: stack dumps please

   loop { }
}

/// Test interrupt handler for ensuring that the IDT is configured correctly.
#[no_mangle] #[inline(never)]
pub extern "x86-interrupt" fn test(_frame: &InterruptFrame) {
   // assert_eq!(state.int_id, 0x80);
   kinfoln!(dots: " . . ", target: "Testing interrupt handling:", "[ OKAY ]");
   // send the PICs the end interrupt signal
   unsafe {
       pics::end_pic_interrupt(0xff);
   }
}

/// Empty dummy handler for undefined interrupts.
#[no_mangle] #[inline(never)]
pub extern "x86-interrupt" fn empty_handler(_frame: &InterruptFrame) {
   // assert_eq!(state.int_id, 0x80);
   println!("interrupt");
   // send the PICs the end interrupt signal
   // unsafe {
   //     end_pic_interrupt(0xff);
   // }
}

macro_rules! make_handlers {
    ( $(ex $ex_num:expr, $name:ident),+ ) => {
        $(
            #[no_mangle] #[allow(missing_docs)]
            pub extern "x86-interrupt" fn $name(frame: &InterruptFrame) {
                let ex_info = &EXCEPTIONS[$ex_num];
                // let cr_state = control_regs::dump();
                let _ = write!( CONSOLE.lock()
                                       .set_colors(Color::White, Color::Blue)
                              , "EVERYTHING IS FINE: {}{} at {:p}\n\
                                 Exception on vector {}.\n\
                                 Source: {}.\nThis is fine.\n\n\
                                 {:?}"
                                 , ex_info.name, ex_info.irq_type
                                 , (*frame).rip
                                 , $ex_num
                                 , ex_info.source
                                 , *frame);
                loop { }
            }
        )+
    };
    ( $(err $ex_num:expr, $name:ident) ,+ ) => {
        $(
            #[no_mangle] #[allow(missing_docs)]
            pub extern "x86-interrupt" fn $name( frame: &InterruptFrame
                                                , err_code: usize) {
                let ex_info = &EXCEPTIONS[$ex_num];
                // let cr_state = control_regs::dump();
                let _ = write!( CONSOLE.lock()
                                       .set_colors(Color::White, Color::Blue)
                              , "EVERYTHING IS FINE: {}{} at {:p}\n\
                                 Exception on vector {} with error code {:#x}.\n\
                                 Source: {}.\nThis is fine.\n\n\
                                 {:?}"
                              , ex_info.name, ex_info.irq_type
                              , (*frame).rip
                              , $ex_num, err_code
                              , ex_info.source
                              , *frame);
                loop { }
            }
        )+
    };
}
make_handlers! { ex 0, ex0
               , ex 1, ex1
               , ex 2, ex2
                // ex 3 is breakpoint
               , ex 4, ex4
               , ex 5, ex5
               , ex 6, ex6
               , ex 7, ex7
               , ex 16, ex16
               , ex 18, ex18
               , ex 19, ex19
               }
make_handlers! { err 8, ex8
               , err 10, ex10
               , err 11, ex11
               , err 12, ex12
               , err 13, ex13
               , err 17, ex17 }
<|endoftext|>


<commit_before>use expect_test::{expect, Expect};
use hir::{HasAttrs, Semantics};
use ide_db::{
    base_db::{FilePosition, FileRange},
    defs::Definition,
    RootDatabase,
};
use itertools::Itertools;
use syntax::{ast, match_ast, AstNode, SyntaxNode};

use crate::{
    doc_links::{extract_definitions_from_docs, resolve_doc_path_for_def, rewrite_links},
    fixture, TryToNav,
};

fn check_external_docs(ra_fixture: &str, expect: Expect) {
    let (analysis, position) = fixture::position(ra_fixture);
    let url = analysis.external_docs(position).unwrap().expect("could not find url for symbol");

    expect.assert_eq(&url)
}

fn check_rewrite(ra_fixture: &str, expect: Expect) {
    let (analysis, position) = fixture::position(ra_fixture);
    let sema = &Semantics::new(&*analysis.db);
    let (cursor_def, docs) = def_under_cursor(sema, &position);
    let res = rewrite_links(sema.db, docs.as_str(), cursor_def);
    expect.assert_eq(&res)
}

fn check_doc_links(ra_fixture: &str) {
    let key_fn = |&(FileRange { file_id, range }, _): &_| (file_id, range.start());

    let (analysis, position, mut expected) = fixture::annotations(ra_fixture);
    expected.sort_by_key(key_fn);
    let sema = &Semantics::new(&*analysis.db);
    let (cursor_def, docs) = def_under_cursor(sema, &position);
    let defs = extract_definitions_from_docs(&docs);
    let actual: Vec<_> = defs
        .into_iter()
        .map(|(_, link, ns)| {
            let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns)
                .unwrap_or_else(|| panic!("Failed to resolve {}", link));
            let nav_target = def.try_to_nav(sema.db).unwrap();
            let range =
                FileRange { file_id: nav_target.file_id, range: nav_target.focus_or_full_range() };
            (range, link)
        })
        .sorted_by_key(key_fn)
        .collect();
    assert_eq!(expected, actual);
}

fn def_under_cursor(
    sema: &Semantics<RootDatabase>,
    position: &FilePosition,
) -> (Definition, hir::Documentation) {
    let (docs, def) = sema
        .parse(position.file_id)
        .syntax()
        .token_at_offset(position.offset)
        .left_biased()
        .unwrap()
        .ancestors()
        .find_map(|it| node_to_def(sema, &it))
        .expect("no def found")
        .unwrap();
    let docs = docs.expect("no docs found for cursor def");
    (def, docs)
}

fn node_to_def(
    sema: &Semantics<RootDatabase>,
    node: &SyntaxNode,
) -> Option<Option<(Option<hir::Documentation>, Definition)>> {
    Some(match_ast! {
        match node {
            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
            ast::Module(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
            ast::Fn(it)          => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Function(def))),
            ast::Struct(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
            ast::Union(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Union(def)))),
            ast::Enum(it)        => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
            ast::Variant(it)     => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Variant(def))),
            ast::Trait(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Trait(def))),
            ast::Static(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Static(def))),
            ast::Const(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Const(def))),
            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::TypeAlias(def))),
            ast::Impl(it)        => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::SelfType(def))),
            ast::RecordField(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
            ast::TupleField(it)  => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
            ast::Macro(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Macro(def))),
            // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
            _ => return None,
        }
    })
}

#[test]
fn external_docs_doc_url_crate() {
    check_external_docs(
        r#"
//- /main.rs crate:main deps:foo
use foo$0::Foo;
//- /lib.rs crate:foo
pub struct Foo;
"#,
        expect![[r#"https://docs.rs/foo/*/foo/index.html"#]],
    );
}

#[test]
fn external_docs_doc_url_std_crate() {
    check_external_docs(
        r#"
//- /main.rs crate:std
use self$0;
"#,
        expect![[r#"https://doc.rust-lang.org/nightly/std/index.html"#]],
    );
}

#[test]
fn external_docs_doc_url_struct() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Fo$0o;
"#,
        expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]],
    );
}

#[test]
fn external_docs_doc_url_struct_field() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo {
    field$0: ()
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#structfield.field"##]],
    );
}

#[test]
fn external_docs_doc_url_fn() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub fn fo$0o() {}
"#,
        expect![[r#"https://docs.rs/foo/*/foo/fn.foo.html"#]],
    );
}

#[test]
fn external_docs_doc_url_impl_assoc() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
impl Foo {
    pub fn method$0() {}
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
impl Foo {
    const CONST$0: () = ();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]],
    );
}

#[test]
fn external_docs_doc_url_impl_trait_assoc() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
pub trait Trait {
    fn method() {}
}
impl Trait for Foo {
    pub fn method$0() {}
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
pub trait Trait {
    const CONST: () = ();
}
impl Trait for Foo {
    const CONST$0: () = ();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
pub trait Trait {
    type Type;
}
impl Trait for Foo {
    type Type$0 = ();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedtype.Type"##]],
    );
}

#[test]
fn external_docs_doc_url_trait_assoc() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub trait Foo {
    fn method$0();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#tymethod.method"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub trait Foo {
    const CONST$0: ();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedconstant.CONST"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub trait Foo {
    type Type$0;
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedtype.Type"##]],
    );
}

#[test]
fn external_docs_trait() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
trait Trait$0 {}
"#,
        expect![[r#"https://docs.rs/foo/*/foo/trait.Trait.html"#]],
    )
}

#[test]
fn external_docs_module() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub mod foo {
    pub mod ba$0r {}
}
"#,
        expect![[r#"https://docs.rs/foo/*/foo/foo/bar/index.html"#]],
    )
}

#[test]
fn external_docs_reexport_order() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub mod wrapper {
    pub use module::Item;

    pub mod module {
        pub struct Item;
    }
}

fn foo() {
    let bar: wrapper::It$0em;
}
        "#,
        expect![[r#"https://docs.rs/foo/*/foo/wrapper/module/struct.Item.html"#]],
    )
}

#[test]
fn test_trait_items() {
    check_doc_links(
        r#"
/// [`Trait`]
/// [`Trait::Type`]
/// [`Trait::CONST`]
/// [`Trait::func`]
trait Trait$0 {
   // ^^^^^ Trait
    type Type;
      // ^^^^ Trait::Type
    const CONST: usize;
       // ^^^^^ Trait::CONST
    fn func();
    // ^^^^ Trait::func
}
        "#,
    )
}

#[test]
fn rewrite_html_root_url() {
    check_rewrite(
        r#"
//- /main.rs crate:foo
#![doc(arbitrary_attribute = "test", html_root_url = "https:/example.com", arbitrary_attribute2)]

pub mod foo {
    pub struct Foo;
}
/// [Foo](foo::Foo)
pub struct B$0ar
"#,
        expect![[r#"[Foo](https://example.com/foo/foo/struct.Foo.html)"#]],
    );
}

#[test]
fn rewrite_on_field() {
    check_rewrite(
        r#"
//- /main.rs crate:foo
pub struct Foo {
    /// [Foo](struct.Foo.html)
    fie$0ld: ()
}
"#,
        expect![[r#"[Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
}

#[test]
fn rewrite_struct() {
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [Foo]
pub struct $0Foo;
"#,
        expect![[r#"[Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [`Foo`]
pub struct $0Foo;
"#,
        expect![[r#"[`Foo`](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [Foo](struct.Foo.html)
pub struct $0Foo;
"#,
        expect![[r#"[Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [struct Foo](struct.Foo.html)
pub struct $0Foo;
"#,
        expect![[r#"[struct Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [my Foo][foo]
///
/// [foo]: Foo
pub struct $0Foo;
"#,
        expect![[r#"[my Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [`foo`]
///
/// [`foo`]: Foo
pub struct $0Foo;
"#,
        expect![["[`foo`]"]],
    );
}
<commit_msg>internal: Add more doc-link tests<commit_after>use expect_test::{expect, Expect};
use hir::{HasAttrs, Semantics};
use ide_db::{
    base_db::{FilePosition, FileRange},
    defs::Definition,
    RootDatabase,
};
use itertools::Itertools;
use syntax::{ast, match_ast, AstNode, SyntaxNode};

use crate::{
    doc_links::{extract_definitions_from_docs, resolve_doc_path_for_def, rewrite_links},
    fixture, TryToNav,
};

fn check_external_docs(ra_fixture: &str, expect: Expect) {
    let (analysis, position) = fixture::position(ra_fixture);
    let url = analysis.external_docs(position).unwrap().expect("could not find url for symbol");

    expect.assert_eq(&url)
}

fn check_rewrite(ra_fixture: &str, expect: Expect) {
    let (analysis, position) = fixture::position(ra_fixture);
    let sema = &Semantics::new(&*analysis.db);
    let (cursor_def, docs) = def_under_cursor(sema, &position);
    let res = rewrite_links(sema.db, docs.as_str(), cursor_def);
    expect.assert_eq(&res)
}

fn check_doc_links(ra_fixture: &str) {
    let key_fn = |&(FileRange { file_id, range }, _): &_| (file_id, range.start());

    let (analysis, position, mut expected) = fixture::annotations(ra_fixture);
    expected.sort_by_key(key_fn);
    let sema = &Semantics::new(&*analysis.db);
    let (cursor_def, docs) = def_under_cursor(sema, &position);
    let defs = extract_definitions_from_docs(&docs);
    let actual: Vec<_> = defs
        .into_iter()
        .map(|(_, link, ns)| {
            let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns)
                .unwrap_or_else(|| panic!("Failed to resolve {}", link));
            let nav_target = def.try_to_nav(sema.db).unwrap();
            let range =
                FileRange { file_id: nav_target.file_id, range: nav_target.focus_or_full_range() };
            (range, link)
        })
        .sorted_by_key(key_fn)
        .collect();
    assert_eq!(expected, actual);
}

fn def_under_cursor(
    sema: &Semantics<RootDatabase>,
    position: &FilePosition,
) -> (Definition, hir::Documentation) {
    let (docs, def) = sema
        .parse(position.file_id)
        .syntax()
        .token_at_offset(position.offset)
        .left_biased()
        .unwrap()
        .ancestors()
        .find_map(|it| node_to_def(sema, &it))
        .expect("no def found")
        .unwrap();
    let docs = docs.expect("no docs found for cursor def");
    (def, docs)
}

fn node_to_def(
    sema: &Semantics<RootDatabase>,
    node: &SyntaxNode,
) -> Option<Option<(Option<hir::Documentation>, Definition)>> {
    Some(match_ast! {
        match node {
            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
            ast::Module(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
            ast::Fn(it)          => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Function(def))),
            ast::Struct(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
            ast::Union(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Union(def)))),
            ast::Enum(it)        => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
            ast::Variant(it)     => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Variant(def))),
            ast::Trait(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Trait(def))),
            ast::Static(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Static(def))),
            ast::Const(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Const(def))),
            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::TypeAlias(def))),
            ast::Impl(it)        => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::SelfType(def))),
            ast::RecordField(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
            ast::TupleField(it)  => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
            ast::Macro(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Macro(def))),
            // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
            _ => return None,
        }
    })
}

#[test]
fn external_docs_doc_url_crate() {
    check_external_docs(
        r#"
//- /main.rs crate:main deps:foo
use foo$0::Foo;
//- /lib.rs crate:foo
pub struct Foo;
"#,
        expect![[r#"https://docs.rs/foo/*/foo/index.html"#]],
    );
}

#[test]
fn external_docs_doc_url_std_crate() {
    check_external_docs(
        r#"
//- /main.rs crate:std
use self$0;
"#,
        expect![[r#"https://doc.rust-lang.org/nightly/std/index.html"#]],
    );
}

#[test]
fn external_docs_doc_url_struct() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Fo$0o;
"#,
        expect![[r#"https://docs.rs/foo/*/foo/struct.Foo.html"#]],
    );
}

#[test]
fn external_docs_doc_url_struct_field() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo {
    field$0: ()
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#structfield.field"##]],
    );
}

#[test]
fn external_docs_doc_url_fn() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub fn fo$0o() {}
"#,
        expect![[r#"https://docs.rs/foo/*/foo/fn.foo.html"#]],
    );
}

#[test]
fn external_docs_doc_url_impl_assoc() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
impl Foo {
    pub fn method$0() {}
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
impl Foo {
    const CONST$0: () = ();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]],
    );
}

#[test]
fn external_docs_doc_url_impl_trait_assoc() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
pub trait Trait {
    fn method() {}
}
impl Trait for Foo {
    pub fn method$0() {}
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#method.method"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
pub trait Trait {
    const CONST: () = ();
}
impl Trait for Foo {
    const CONST$0: () = ();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.CONST"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub struct Foo;
pub trait Trait {
    type Type;
}
impl Trait for Foo {
    type Type$0 = ();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/struct.Foo.html#associatedtype.Type"##]],
    );
}

#[test]
fn external_docs_doc_url_trait_assoc() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub trait Foo {
    fn method$0();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#tymethod.method"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub trait Foo {
    const CONST$0: ();
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedconstant.CONST"##]],
    );
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub trait Foo {
    type Type$0;
}
"#,
        expect![[r##"https://docs.rs/foo/*/foo/trait.Foo.html#associatedtype.Type"##]],
    );
}

#[test]
fn external_docs_trait() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
trait Trait$0 {}
"#,
        expect![[r#"https://docs.rs/foo/*/foo/trait.Trait.html"#]],
    )
}

#[test]
fn external_docs_module() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub mod foo {
    pub mod ba$0r {}
}
"#,
        expect![[r#"https://docs.rs/foo/*/foo/foo/bar/index.html"#]],
    )
}

#[test]
fn external_docs_reexport_order() {
    check_external_docs(
        r#"
//- /main.rs crate:foo
pub mod wrapper {
    pub use module::Item;

    pub mod module {
        pub struct Item;
    }
}

fn foo() {
    let bar: wrapper::It$0em;
}
        "#,
        expect![[r#"https://docs.rs/foo/*/foo/wrapper/module/struct.Item.html"#]],
    )
}

#[test]
fn doc_links_items_simple() {
    check_doc_links(
        r#"
//- /main.rs crate:main deps:krate
/// [`krate`]
//! [`Trait`]
//! [`function`]
//! [`CONST`]
//! [`STATIC`]
//! [`Struct`]
//! [`Enum`]
//! [`Union`]
//! [`Type`]
//! [`module`]
use self$0;

const CONST: () = ();
   // ^^^^^ CONST
static STATIC: () = ();
    // ^^^^^^ STATIC
trait Trait {
   // ^^^^^ Trait
}
fn function() {}
// ^^^^^^^^ function
struct Struct;
    // ^^^^^^ Struct
enum Enum {}
  // ^^^^ Enum
union Union {__: ()}
   // ^^^^^ Union
type Type = ();
  // ^^^^ Type
mod module {}
 // ^^^^^^ module
//- /krate.rs crate:krate
// empty
//^file krate
"#,
    )
}

#[test]
fn doc_links_inherent_impl_items() {
    check_doc_links(
        r#"
// /// [`Struct::CONST`]
// /// [`Struct::function`]
/// FIXME #9694
struct Struct$0;

impl Struct {
    const CONST: () = ();
    fn function() {}
}
"#,
    )
}

#[test]
fn doc_links_trait_impl_items() {
    check_doc_links(
        r#"
trait Trait {
    type Type;
    const CONST: usize;
    fn function();
}
// /// [`Struct::Type`]
// /// [`Struct::CONST`]
// /// [`Struct::function`]
/// FIXME #9694
struct Struct$0;

impl Trait for Struct {
    type Type = ();
    const CONST: () = ();
    fn function() {}
}
"#,
    )
}

#[test]
fn doc_links_trait_items() {
    check_doc_links(
        r#"
/// [`Trait`]
/// [`Trait::Type`]
/// [`Trait::CONST`]
/// [`Trait::function`]
trait Trait$0 {
   // ^^^^^ Trait
type Type;
  // ^^^^ Trait::Type
const CONST: usize;
   // ^^^^^ Trait::CONST
fn function();
// ^^^^^^^^ Trait::function
}
    "#,
    )
}

#[test]
fn rewrite_html_root_url() {
    check_rewrite(
        r#"
//- /main.rs crate:foo
#![doc(arbitrary_attribute = "test", html_root_url = "https:/example.com", arbitrary_attribute2)]

pub mod foo {
    pub struct Foo;
}
/// [Foo](foo::Foo)
pub struct B$0ar
"#,
        expect![[r#"[Foo](https://example.com/foo/foo/struct.Foo.html)"#]],
    );
}

#[test]
fn rewrite_on_field() {
    check_rewrite(
        r#"
//- /main.rs crate:foo
pub struct Foo {
    /// [Foo](struct.Foo.html)
    fie$0ld: ()
}
"#,
        expect![[r#"[Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
}

#[test]
fn rewrite_struct() {
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [Foo]
pub struct $0Foo;
"#,
        expect![[r#"[Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [`Foo`]
pub struct $0Foo;
"#,
        expect![[r#"[`Foo`](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [Foo](struct.Foo.html)
pub struct $0Foo;
"#,
        expect![[r#"[Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [struct Foo](struct.Foo.html)
pub struct $0Foo;
"#,
        expect![[r#"[struct Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [my Foo][foo]
///
/// [foo]: Foo
pub struct $0Foo;
"#,
        expect![[r#"[my Foo](https://docs.rs/foo/*/foo/struct.Foo.html)"#]],
    );
    check_rewrite(
        r#"
//- /main.rs crate:foo
/// [`foo`]
///
/// [`foo`]: Foo
pub struct $0Foo;
"#,
        expect![["[`foo`]"]],
    );
}
<|endoftext|>


<commit_before>// The visitors in this module collect sizes and counts of the most important
// pieces of AST and HIR. The resulting numbers are good approximations but not
// completely accurate (some things might be counted twice, others missed).

use rustc_ast::visit as ast_visit;
use rustc_ast::{self as ast, AttrId, NodeId};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::intravisit as hir_visit;
use rustc_hir::HirId;
use rustc_middle::hir::map::Map;
use rustc_middle::util::common::to_readable_str;
use rustc_span::Span;

#[derive(Copy, Clone, PartialEq, Eq, Hash)]
enum Id {
    Node(HirId),
    Attr(AttrId),
    None,
}

struct NodeData {
    count: usize,
    size: usize,
}

struct StatCollector<'k> {
    krate: Option<&'k hir::Crate<'k>>,
    data: FxHashMap<&'static str, NodeData>,
    seen: FxHashSet<Id>,
}

pub fn print_hir_stats(krate: &hir::Crate<'_>) {
    let mut collector = StatCollector {
        krate: Some(krate),
        data: FxHashMap::default(),
        seen: FxHashSet::default(),
    };
    hir_visit::walk_crate(&mut collector, krate);
    collector.print("HIR STATS");
}

pub fn print_ast_stats(krate: &ast::Crate, title: &str) {
    let mut collector =
        StatCollector { krate: None, data: FxHashMap::default(), seen: FxHashSet::default() };
    ast_visit::walk_crate(&mut collector, krate);
    collector.print(title);
}

impl<'k> StatCollector<'k> {
    fn record<T>(&mut self, label: &'static str, id: Id, node: &T) {
        if id != Id::None && !self.seen.insert(id) {
            return;
        }

        let entry = self.data.entry(label).or_insert(NodeData { count: 0, size: 0 });

        entry.count += 1;
        entry.size = std::mem::size_of_val(node);
    }

    fn print(&self, title: &str) {
        let mut stats: Vec<_> = self.data.iter().collect();

        stats.sort_by_key(|&(_, ref d)| d.count * d.size);

        let mut total_size = 0;

        println!("\n{}\n", title);

        println!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
        println!("----------------------------------------------------------------");

        for (label, data) in stats {
            println!(
                "{:<18}{:>18}{:>14}{:>14}",
                label,
                to_readable_str(data.count * data.size),
                to_readable_str(data.count),
                to_readable_str(data.size)
            );

            total_size += data.count * data.size;
        }
        println!("----------------------------------------------------------------");
        println!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
    }
}

impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
    fn visit_param(&mut self, param: &'v hir::Param<'v>) {
        self.record("Param", Id::Node(param.hir_id), param);
        hir_visit::walk_param(self, param)
    }

    type Map = Map<'v>;

    fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
        panic!("visit_nested_xxx must be manually implemented in this visitor")
    }

    fn visit_nested_item(&mut self, id: hir::ItemId) {
        let nested_item = self.krate.unwrap().item(id);
        self.visit_item(nested_item)
    }

    fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) {
        let nested_trait_item = self.krate.unwrap().trait_item(trait_item_id);
        self.visit_trait_item(nested_trait_item)
    }

    fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
        let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
        self.visit_impl_item(nested_impl_item)
    }

    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
        let nested_body = self.krate.unwrap().body(body_id);
        self.visit_body(nested_body)
    }

    fn visit_item(&mut self, i: &'v hir::Item<'v>) {
        self.record("Item", Id::Node(i.hir_id()), i);
        hir_visit::walk_item(self, i)
    }

    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: hir::HirId) {
        self.record("Mod", Id::None, m);
        hir_visit::walk_mod(self, m, n)
    }

    fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
        self.record("ForeignItem", Id::Node(i.hir_id()), i);
        hir_visit::walk_foreign_item(self, i)
    }

    fn visit_local(&mut self, l: &'v hir::Local<'v>) {
        self.record("Local", Id::Node(l.hir_id), l);
        hir_visit::walk_local(self, l)
    }

    fn visit_block(&mut self, b: &'v hir::Block<'v>) {
        self.record("Block", Id::Node(b.hir_id), b);
        hir_visit::walk_block(self, b)
    }

    fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
        self.record("Stmt", Id::Node(s.hir_id), s);
        hir_visit::walk_stmt(self, s)
    }

    fn visit_arm(&mut self, a: &'v hir::Arm<'v>) {
        self.record("Arm", Id::Node(a.hir_id), a);
        hir_visit::walk_arm(self, a)
    }

    fn visit_pat(&mut self, p: &'v hir::Pat<'v>) {
        self.record("Pat", Id::Node(p.hir_id), p);
        hir_visit::walk_pat(self, p)
    }

    fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
        self.record("Expr", Id::Node(ex.hir_id), ex);
        hir_visit::walk_expr(self, ex)
    }

    fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
        self.record("Ty", Id::Node(t.hir_id), t);
        hir_visit::walk_ty(self, t)
    }

    fn visit_fn(
        &mut self,
        fk: hir_visit::FnKind<'v>,
        fd: &'v hir::FnDecl<'v>,
        b: hir::BodyId,
        s: Span,
        id: hir::HirId,
    ) {
        self.record("FnDecl", Id::None, fd);
        hir_visit::walk_fn(self, fk, fd, b, s, id)
    }

    fn visit_where_predicate(&mut self, predicate: &'v hir::WherePredicate<'v>) {
        self.record("WherePredicate", Id::None, predicate);
        hir_visit::walk_where_predicate(self, predicate)
    }

    fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) {
        self.record("TraitItem", Id::Node(ti.hir_id()), ti);
        hir_visit::walk_trait_item(self, ti)
    }

    fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) {
        self.record("ImplItem", Id::Node(ii.hir_id()), ii);
        hir_visit::walk_impl_item(self, ii)
    }

    fn visit_param_bound(&mut self, bounds: &'v hir::GenericBound<'v>) {
        self.record("GenericBound", Id::None, bounds);
        hir_visit::walk_param_bound(self, bounds)
    }

    fn visit_struct_field(&mut self, s: &'v hir::StructField<'v>) {
        self.record("StructField", Id::Node(s.hir_id), s);
        hir_visit::walk_struct_field(self, s)
    }

    fn visit_variant(
        &mut self,
        v: &'v hir::Variant<'v>,
        g: &'v hir::Generics<'v>,
        item_id: hir::HirId,
    ) {
        self.record("Variant", Id::None, v);
        hir_visit::walk_variant(self, v, g, item_id)
    }

    fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
        self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime);
        hir_visit::walk_lifetime(self, lifetime)
    }

    fn visit_qpath(&mut self, qpath: &'v hir::QPath<'v>, id: hir::HirId, span: Span) {
        self.record("QPath", Id::None, qpath);
        hir_visit::walk_qpath(self, qpath, id, span)
    }

    fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
        self.record("Path", Id::None, path);
        hir_visit::walk_path(self, path)
    }

    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment<'v>) {
        self.record("PathSegment", Id::None, path_segment);
        hir_visit::walk_path_segment(self, path_span, path_segment)
    }

    fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding<'v>) {
        self.record("TypeBinding", Id::Node(type_binding.hir_id), type_binding);
        hir_visit::walk_assoc_type_binding(self, type_binding)
    }

    fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
        self.record("Attribute", Id::Attr(attr.id), attr);
    }

    fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef<'v>) {
        self.record("MacroDef", Id::Node(macro_def.hir_id()), macro_def);
        hir_visit::walk_macro_def(self, macro_def)
    }
}

impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
    fn visit_mod(&mut self, m: &'v ast::Mod, _s: Span, _a: &[ast::Attribute], _n: NodeId) {
        self.record("Mod", Id::None, m);
        ast_visit::walk_mod(self, m)
    }

    fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
        self.record("ForeignItem", Id::None, i);
        ast_visit::walk_foreign_item(self, i)
    }

    fn visit_item(&mut self, i: &'v ast::Item) {
        self.record("Item", Id::None, i);
        ast_visit::walk_item(self, i)
    }

    fn visit_local(&mut self, l: &'v ast::Local) {
        self.record("Local", Id::None, l);
        ast_visit::walk_local(self, l)
    }

    fn visit_block(&mut self, b: &'v ast::Block) {
        self.record("Block", Id::None, b);
        ast_visit::walk_block(self, b)
    }

    fn visit_stmt(&mut self, s: &'v ast::Stmt) {
        self.record("Stmt", Id::None, s);
        ast_visit::walk_stmt(self, s)
    }

    fn visit_arm(&mut self, a: &'v ast::Arm) {
        self.record("Arm", Id::None, a);
        ast_visit::walk_arm(self, a)
    }

    fn visit_pat(&mut self, p: &'v ast::Pat) {
        self.record("Pat", Id::None, p);
        ast_visit::walk_pat(self, p)
    }

    fn visit_expr(&mut self, ex: &'v ast::Expr) {
        self.record("Expr", Id::None, ex);
        ast_visit::walk_expr(self, ex)
    }

    fn visit_ty(&mut self, t: &'v ast::Ty) {
        self.record("Ty", Id::None, t);
        ast_visit::walk_ty(self, t)
    }

    fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) {
        self.record("FnDecl", Id::None, fk.decl());
        ast_visit::walk_fn(self, fk, s)
    }

    fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
        let label = match ctxt {
            ast_visit::AssocCtxt::Trait => "TraitItem",
            ast_visit::AssocCtxt::Impl => "ImplItem",
        };
        self.record(label, Id::None, item);
        ast_visit::walk_assoc_item(self, item, ctxt);
    }

    fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) {
        self.record("GenericBound", Id::None, bounds);
        ast_visit::walk_param_bound(self, bounds)
    }

    fn visit_struct_field(&mut self, s: &'v ast::StructField) {
        self.record("StructField", Id::None, s);
        ast_visit::walk_struct_field(self, s)
    }

    fn visit_variant(&mut self, v: &'v ast::Variant) {
        self.record("Variant", Id::None, v);
        ast_visit::walk_variant(self, v)
    }

    fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime) {
        self.record("Lifetime", Id::None, lifetime);
        ast_visit::walk_lifetime(self, lifetime)
    }

    fn visit_mac_call(&mut self, mac: &'v ast::MacCall) {
        self.record("MacCall", Id::None, mac);
        ast_visit::walk_mac(self, mac)
    }

    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) {
        self.record("PathSegment", Id::None, path_segment);
        ast_visit::walk_path_segment(self, path_span, path_segment)
    }

    fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
        self.record("AssocTyConstraint", Id::None, constraint);
        ast_visit::walk_assoc_ty_constraint(self, constraint)
    }

    fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
        self.record("Attribute", Id::None, attr);
    }
}
<commit_msg>Implement -Z hir-stats for nested foreign items<commit_after>// The visitors in this module collect sizes and counts of the most important
// pieces of AST and HIR. The resulting numbers are good approximations but not
// completely accurate (some things might be counted twice, others missed).

use rustc_ast::visit as ast_visit;
use rustc_ast::{self as ast, AttrId, NodeId};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::intravisit as hir_visit;
use rustc_hir::HirId;
use rustc_middle::hir::map::Map;
use rustc_middle::util::common::to_readable_str;
use rustc_span::Span;

#[derive(Copy, Clone, PartialEq, Eq, Hash)]
enum Id {
    Node(HirId),
    Attr(AttrId),
    None,
}

struct NodeData {
    count: usize,
    size: usize,
}

struct StatCollector<'k> {
    krate: Option<&'k hir::Crate<'k>>,
    data: FxHashMap<&'static str, NodeData>,
    seen: FxHashSet<Id>,
}

pub fn print_hir_stats(krate: &hir::Crate<'_>) {
    let mut collector = StatCollector {
        krate: Some(krate),
        data: FxHashMap::default(),
        seen: FxHashSet::default(),
    };
    hir_visit::walk_crate(&mut collector, krate);
    collector.print("HIR STATS");
}

pub fn print_ast_stats(krate: &ast::Crate, title: &str) {
    let mut collector =
        StatCollector { krate: None, data: FxHashMap::default(), seen: FxHashSet::default() };
    ast_visit::walk_crate(&mut collector, krate);
    collector.print(title);
}

impl<'k> StatCollector<'k> {
    fn record<T>(&mut self, label: &'static str, id: Id, node: &T) {
        if id != Id::None && !self.seen.insert(id) {
            return;
        }

        let entry = self.data.entry(label).or_insert(NodeData { count: 0, size: 0 });

        entry.count += 1;
        entry.size = std::mem::size_of_val(node);
    }

    fn print(&self, title: &str) {
        let mut stats: Vec<_> = self.data.iter().collect();

        stats.sort_by_key(|&(_, ref d)| d.count * d.size);

        let mut total_size = 0;

        println!("\n{}\n", title);

        println!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
        println!("----------------------------------------------------------------");

        for (label, data) in stats {
            println!(
                "{:<18}{:>18}{:>14}{:>14}",
                label,
                to_readable_str(data.count * data.size),
                to_readable_str(data.count),
                to_readable_str(data.size)
            );

            total_size += data.count * data.size;
        }
        println!("----------------------------------------------------------------");
        println!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
    }
}

impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
    fn visit_param(&mut self, param: &'v hir::Param<'v>) {
        self.record("Param", Id::Node(param.hir_id), param);
        hir_visit::walk_param(self, param)
    }

    type Map = Map<'v>;

    fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
        panic!("visit_nested_xxx must be manually implemented in this visitor")
    }

    fn visit_nested_item(&mut self, id: hir::ItemId) {
        let nested_item = self.krate.unwrap().item(id);
        self.visit_item(nested_item)
    }

    fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) {
        let nested_trait_item = self.krate.unwrap().trait_item(trait_item_id);
        self.visit_trait_item(nested_trait_item)
    }

    fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
        let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
        self.visit_impl_item(nested_impl_item)
    }

    fn visit_nested_foreign_item(&mut self, id: hir::ForeignItemId) {
        let nested_foreign_item = self.krate.unwrap().foreign_item(id);
        self.visit_foreign_item(nested_foreign_item);
    }

    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
        let nested_body = self.krate.unwrap().body(body_id);
        self.visit_body(nested_body)
    }

    fn visit_item(&mut self, i: &'v hir::Item<'v>) {
        self.record("Item", Id::Node(i.hir_id()), i);
        hir_visit::walk_item(self, i)
    }

    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: hir::HirId) {
        self.record("Mod", Id::None, m);
        hir_visit::walk_mod(self, m, n)
    }

    fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
        self.record("ForeignItem", Id::Node(i.hir_id()), i);
        hir_visit::walk_foreign_item(self, i)
    }

    fn visit_local(&mut self, l: &'v hir::Local<'v>) {
        self.record("Local", Id::Node(l.hir_id), l);
        hir_visit::walk_local(self, l)
    }

    fn visit_block(&mut self, b: &'v hir::Block<'v>) {
        self.record("Block", Id::Node(b.hir_id), b);
        hir_visit::walk_block(self, b)
    }

    fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
        self.record("Stmt", Id::Node(s.hir_id), s);
        hir_visit::walk_stmt(self, s)
    }

    fn visit_arm(&mut self, a: &'v hir::Arm<'v>) {
        self.record("Arm", Id::Node(a.hir_id), a);
        hir_visit::walk_arm(self, a)
    }

    fn visit_pat(&mut self, p: &'v hir::Pat<'v>) {
        self.record("Pat", Id::Node(p.hir_id), p);
        hir_visit::walk_pat(self, p)
    }

    fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
        self.record("Expr", Id::Node(ex.hir_id), ex);
        hir_visit::walk_expr(self, ex)
    }

    fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
        self.record("Ty", Id::Node(t.hir_id), t);
        hir_visit::walk_ty(self, t)
    }

    fn visit_fn(
        &mut self,
        fk: hir_visit::FnKind<'v>,
        fd: &'v hir::FnDecl<'v>,
        b: hir::BodyId,
        s: Span,
        id: hir::HirId,
    ) {
        self.record("FnDecl", Id::None, fd);
        hir_visit::walk_fn(self, fk, fd, b, s, id)
    }

    fn visit_where_predicate(&mut self, predicate: &'v hir::WherePredicate<'v>) {
        self.record("WherePredicate", Id::None, predicate);
        hir_visit::walk_where_predicate(self, predicate)
    }

    fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) {
        self.record("TraitItem", Id::Node(ti.hir_id()), ti);
        hir_visit::walk_trait_item(self, ti)
    }

    fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) {
        self.record("ImplItem", Id::Node(ii.hir_id()), ii);
        hir_visit::walk_impl_item(self, ii)
    }

    fn visit_param_bound(&mut self, bounds: &'v hir::GenericBound<'v>) {
        self.record("GenericBound", Id::None, bounds);
        hir_visit::walk_param_bound(self, bounds)
    }

    fn visit_struct_field(&mut self, s: &'v hir::StructField<'v>) {
        self.record("StructField", Id::Node(s.hir_id), s);
        hir_visit::walk_struct_field(self, s)
    }

    fn visit_variant(
        &mut self,
        v: &'v hir::Variant<'v>,
        g: &'v hir::Generics<'v>,
        item_id: hir::HirId,
    ) {
        self.record("Variant", Id::None, v);
        hir_visit::walk_variant(self, v, g, item_id)
    }

    fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
        self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime);
        hir_visit::walk_lifetime(self, lifetime)
    }

    fn visit_qpath(&mut self, qpath: &'v hir::QPath<'v>, id: hir::HirId, span: Span) {
        self.record("QPath", Id::None, qpath);
        hir_visit::walk_qpath(self, qpath, id, span)
    }

    fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
        self.record("Path", Id::None, path);
        hir_visit::walk_path(self, path)
    }

    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment<'v>) {
        self.record("PathSegment", Id::None, path_segment);
        hir_visit::walk_path_segment(self, path_span, path_segment)
    }

    fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding<'v>) {
        self.record("TypeBinding", Id::Node(type_binding.hir_id), type_binding);
        hir_visit::walk_assoc_type_binding(self, type_binding)
    }

    fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
        self.record("Attribute", Id::Attr(attr.id), attr);
    }

    fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef<'v>) {
        self.record("MacroDef", Id::Node(macro_def.hir_id()), macro_def);
        hir_visit::walk_macro_def(self, macro_def)
    }
}

impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
    fn visit_mod(&mut self, m: &'v ast::Mod, _s: Span, _a: &[ast::Attribute], _n: NodeId) {
        self.record("Mod", Id::None, m);
        ast_visit::walk_mod(self, m)
    }

    fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
        self.record("ForeignItem", Id::None, i);
        ast_visit::walk_foreign_item(self, i)
    }

    fn visit_item(&mut self, i: &'v ast::Item) {
        self.record("Item", Id::None, i);
        ast_visit::walk_item(self, i)
    }

    fn visit_local(&mut self, l: &'v ast::Local) {
        self.record("Local", Id::None, l);
        ast_visit::walk_local(self, l)
    }

    fn visit_block(&mut self, b: &'v ast::Block) {
        self.record("Block", Id::None, b);
        ast_visit::walk_block(self, b)
    }

    fn visit_stmt(&mut self, s: &'v ast::Stmt) {
        self.record("Stmt", Id::None, s);
        ast_visit::walk_stmt(self, s)
    }

    fn visit_arm(&mut self, a: &'v ast::Arm) {
        self.record("Arm", Id::None, a);
        ast_visit::walk_arm(self, a)
    }

    fn visit_pat(&mut self, p: &'v ast::Pat) {
        self.record("Pat", Id::None, p);
        ast_visit::walk_pat(self, p)
    }

    fn visit_expr(&mut self, ex: &'v ast::Expr) {
        self.record("Expr", Id::None, ex);
        ast_visit::walk_expr(self, ex)
    }

    fn visit_ty(&mut self, t: &'v ast::Ty) {
        self.record("Ty", Id::None, t);
        ast_visit::walk_ty(self, t)
    }

    fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) {
        self.record("FnDecl", Id::None, fk.decl());
        ast_visit::walk_fn(self, fk, s)
    }

    fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
        let label = match ctxt {
            ast_visit::AssocCtxt::Trait => "TraitItem",
            ast_visit::AssocCtxt::Impl => "ImplItem",
        };
        self.record(label, Id::None, item);
        ast_visit::walk_assoc_item(self, item, ctxt);
    }

    fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) {
        self.record("GenericBound", Id::None, bounds);
        ast_visit::walk_param_bound(self, bounds)
    }

    fn visit_struct_field(&mut self, s: &'v ast::StructField) {
        self.record("StructField", Id::None, s);
        ast_visit::walk_struct_field(self, s)
    }

    fn visit_variant(&mut self, v: &'v ast::Variant) {
        self.record("Variant", Id::None, v);
        ast_visit::walk_variant(self, v)
    }

    fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime) {
        self.record("Lifetime", Id::None, lifetime);
        ast_visit::walk_lifetime(self, lifetime)
    }

    fn visit_mac_call(&mut self, mac: &'v ast::MacCall) {
        self.record("MacCall", Id::None, mac);
        ast_visit::walk_mac(self, mac)
    }

    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) {
        self.record("PathSegment", Id::None, path_segment);
        ast_visit::walk_path_segment(self, path_span, path_segment)
    }

    fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
        self.record("AssocTyConstraint", Id::None, constraint);
        ast_visit::walk_assoc_ty_constraint(self, constraint)
    }

    fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
        self.record("Attribute", Id::None, attr);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) IxMilia.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

extern crate dxf;

use std::io::{Cursor, Seek, SeekFrom};
use self::dxf::*;

mod test_helpers;

#[test]
fn dont_write_utf8_bom() {
    let drawing = Drawing::default();
    let mut buf = Cursor::new(vec![]);
    drawing.save(&mut buf).ok().unwrap();
    buf.seek(SeekFrom::Start(0)).ok().unwrap();
    let vec = buf.into_inner();

    // file should start directly with a code, not a UTF-8 BOM
    assert_eq!(b' ', vec[0]);
    assert_eq!(b' ', vec[1]);
    assert_eq!(b'0', vec[2]);
}
<commit_msg>fix formatting<commit_after>// Copyright (c) IxMilia.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

extern crate dxf;

use self::dxf::*;
use std::io::{Cursor, Seek, SeekFrom};

mod test_helpers;

#[test]
fn dont_write_utf8_bom() {
    let drawing = Drawing::default();
    let mut buf = Cursor::new(vec![]);
    drawing.save(&mut buf).ok().unwrap();
    buf.seek(SeekFrom::Start(0)).ok().unwrap();
    let vec = buf.into_inner();

    // file should start directly with a code, not a UTF-8 BOM
    assert_eq!(b' ', vec[0]);
    assert_eq!(b' ', vec[1]);
    assert_eq!(b'0', vec[2]);
}
<|endoftext|>


<commit_before>
use std::env;

fn get1(key: &str) -> String {
    return env::var(key).unwrap();
}

fn get2(key: &str) -> String {
    let ret: String;
    match env::var(key) {
        Ok(v) => ret = v,
        Err(_) => ret = "400".to_string()
    }
    return ret;
}

fn main() {
    for argument in env::args() {
        println!("{}", argument);
    }

    println!("{}", get1("MSET_PX_RESOLUTION"));
    println!("{}", get2("MSET_PX_RESOLUTION"));
}
<commit_msg>Add cycles_to_escape.<commit_after>
# Copyright 2020 John Hanley.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# The software is provided "AS IS", without warranty of any kind, express or
# implied, including but not limited to the warranties of merchantability,
# fitness for a particular purpose and noninfringement. In no event shall
# the authors or copyright holders be liable for any claim, damages or
# other liability, whether in an action of contract, tort or otherwise,
# arising from, out of or in connection with the software or the use or
# other dealings in the software.

use std::env;

const MAX_ITER: i32 = 255;  // Rust lacks adequate support for default args.

fn _cycles_to_escape(x0: f64, y0: f64) {
    let mut x = 0.0;
    let mut y = 0.0;
    let mut i = 0;
    while x * x + y * y <= 4.0 && i < MAX_ITER {
        let (x, y) = (x * x - y * y + x0, 2.0 * x * y + y0);
        i += 1;
    }
    i;
}

fn getenv(key: &str) -> f64 {
    let s: String;
    match env::var(key) {
        Ok(v) => s = v,
        Err(_) => s = "400".to_string()
    }
    return stof(s);
}

fn stof(s: String) -> f64 {
    return s.parse::<f64>().unwrap();
}

fn main() {
    let px_resolution = getenv("MSET_PX_RESOLUTION");
    let args: Vec<String> = env::args().into_iter().collect();
    let xc = stof(args[1].to_string());
    let yc = stof(args[2].to_string());
    let sz = stof(args[3].to_string());
    println!("{}", xc);
}
<|endoftext|>


<commit_before>use std::sync::mpsc::Sender;

use pueue_lib::network::message::*;
use pueue_lib::state::SharedState;
use pueue_lib::task::TaskStatus;

use super::SENDER_ERR;
use crate::network::response_helper::task_response_helper;

/// Invoked when calling `pueue kill`.
/// Forward the kill message to the task handler, which then kills the process.
pub fn kill(message: KillMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    sender
        .send(Message::Kill(message.clone()))
        .expect(SENDER_ERR);

    if !message.task_ids.is_empty() {
        let state = state.lock().unwrap();
        let response = task_response_helper(
            "Tasks are being killed",
            message.task_ids,
            vec![TaskStatus::Running, TaskStatus::Paused],
            &state,
        );
        return create_success_message(response);
    }

    if let Some(signal) = message.signal {
        if message.all {
            create_success_message(format!("Sending signal {} to all running tasks.", signal))
        } else {
            create_success_message(format!(
                "Sending signal {} to all running tasks of group {}.",
                signal, message.group
            ))
        }
    } else {
        if message.all {
            create_success_message("All tasks are being killed.")
        } else {
            create_success_message(format!(
                "All tasks of group \"{}\" are being killed.",
                message.group
            ))
        }
    }
}
<commit_msg>Refactor message_handler kill if-else logic<commit_after>use std::sync::mpsc::Sender;

use pueue_lib::network::message::*;
use pueue_lib::state::SharedState;
use pueue_lib::task::TaskStatus;

use super::SENDER_ERR;
use crate::network::response_helper::task_response_helper;

/// Invoked when calling `pueue kill`.
/// Forward the kill message to the task handler, which then kills the process.
pub fn kill(message: KillMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    sender
        .send(Message::Kill(message.clone()))
        .expect(SENDER_ERR);

    if !message.task_ids.is_empty() {
        let state = state.lock().unwrap();
        let response = task_response_helper(
            "Tasks are being killed",
            message.task_ids,
            vec![TaskStatus::Running, TaskStatus::Paused],
            &state,
        );
        return create_success_message(response);
    }

    // Special response for signal handling.
    if let Some(signal) = message.signal {
        return if message.all {
            create_success_message(format!("Sending signal {} to all running tasks.", signal))
        } else {
            create_success_message(format!(
                "Sending signal {} to all running tasks of group {}.",
                signal, message.group
            ))
        };
    }

    // Response for normal kill logic.
    if message.all {
        create_success_message("All tasks are being killed.")
    } else {
        create_success_message(format!(
            "All tasks of group \"{}\" are being killed.",
            message.group
        ))
    }
}
<|endoftext|>