<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Hex binary-to-text encoding
use std::str;
use std::vec;

/// A trait for converting a value to hexadecimal encoding
pub trait ToHex {
    /// Converts the value of `self` to a hex value, returning the owned
    /// string.
    fn to_hex(&self) -> ~str;
}

static CHARS: &'static[u8] = bytes!("0123456789abcdef");

impl<'self> ToHex for &'self [u8] {
    /**
     * Turn a vector of `u8` bytes into a hexadecimal string.
     *
     * # Example
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::hex::ToHex;
     *
     * fn main () {
     *     let str = [52,32].to_hex();
     *     printfln!("%s", str);
     * }
     * ~~~
     */
    fn to_hex(&self) -> ~str {
        let mut v = vec::with_capacity(self.len() * 2);
        for &byte in self.iter() {
            v.push(CHARS[byte >> 4]);
            v.push(CHARS[byte & 0xf]);
        }

        unsafe {
            str::raw::from_bytes_owned(v)
        }
    }
}

/// A trait for converting hexadecimal encoded values
pub trait FromHex {
    /// Converts the value of `self`, interpreted as hexadecimal encoded data,
    /// into an owned vector of bytes, returning the vector.
    fn from_hex(&self) -> Result<~[u8], ~str>;
}

impl<'self> FromHex for &'self str {
    /**
     * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)
     * to the byte values it encodes.
     *
     * You can use the `from_bytes` function in `std::str`
     * to turn a `[u8]` into a string with characters corresponding to those
     * values.
     *
     * # Example
     *
     * This converts a string literal to hexadecimal and back.
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::hex::{FromHex, ToHex};
     * use std::str;
     *
     * fn main () {
     *     let hello_str = "Hello, World".to_hex();
     *     printfln!("%s", hello_str);
     *     let bytes = hello_str.from_hex().get();
     *     printfln!("%?", bytes);
     *     let result_str = str::from_bytes(bytes);
     *     printfln!("%s", result_str);
     * }
     * ~~~
     */
    fn from_hex(&self) -> Result<~[u8], ~str> {
        // This may be an overestimate if there is any whitespace
        let mut b = vec::with_capacity(self.len() / 2);
        let mut modulus = 0;
        let mut buf = 0u8;

        for (idx, byte) in self.byte_iter().enumerate() {
            buf <<= 4;

            match byte as char {
                'A'..'F' => buf |= byte - ('A' as u8) + 10,
                'a'..'f' => buf |= byte - ('a' as u8) + 10,
                '0'..'9' => buf |= byte - ('0' as u8),
                ' '|'\r'|'\n'|'\t' => {
                    buf >>= 4;
                    loop
                }
                _ => return Err(fmt!("Invalid character '%c' at position %u",
                                     self.char_at(idx), idx))
            }

            modulus += 1;
            if modulus == 2 {
                modulus = 0;
                b.push(buf);
            }
        }

        match modulus {
            0 => Ok(b),
            _ => Err(~"Invalid input length")
        }
    }
}

#[cfg(test)]
mod tests {
    use test::BenchHarness;
    use hex::*;

    #[test]
    pub fn test_to_hex() {
        assert_eq!("foobar".as_bytes().to_hex(), ~"666f6f626172");
    }

    #[test]
    pub fn test_from_hex_okay() {
        assert_eq!("666f6f626172".from_hex().get(),
                   "foobar".as_bytes().to_owned());
        assert_eq!("666F6F626172".from_hex().get(),
                   "foobar".as_bytes().to_owned());
    }

    #[test]
    pub fn test_from_hex_odd_len() {
        assert!("666".from_hex().is_err());
        assert!("66 6".from_hex().is_err());
    }

    #[test]
    pub fn test_from_hex_invalid_char() {
        assert!("66y6".from_hex().is_err());
    }

    #[test]
    pub fn test_from_hex_ignores_whitespace() {
        assert_eq!("666f 6f6\r\n26172 ".from_hex().get(),
                   "foobar".as_bytes().to_owned());
    }

    #[test]
    pub fn test_to_hex_all_bytes() {
        for i in range(0, 256) {
            assert_eq!([i as u8].to_hex(), fmt!("%02x", i as uint));
        }
    }

    #[test]
    pub fn test_from_hex_all_bytes() {
        for i in range(0, 256) {
            assert_eq!(fmt!("%02x", i as uint).from_hex().get(), ~[i as u8]);
            assert_eq!(fmt!("%02X", i as uint).from_hex().get(), ~[i as u8]);
        }
    }

    #[bench]
    pub fn bench_to_hex(bh: & mut BenchHarness) {
        let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
                 ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
        do bh.iter {
            s.as_bytes().to_hex();
        }
        bh.bytes = s.len() as u64;
    }

    #[bench]
    pub fn bench_from_hex(bh: & mut BenchHarness) {
        let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
                 ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
        let b = s.as_bytes().to_hex();
        do bh.iter {
            b.from_hex();
        }
        bh.bytes = b.len() as u64;
    }
}
<commit_msg>Result::get -> Result::unwrap<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Hex binary-to-text encoding
use std::str;
use std::vec;

/// A trait for converting a value to hexadecimal encoding
pub trait ToHex {
    /// Converts the value of `self` to a hex value, returning the owned
    /// string.
    fn to_hex(&self) -> ~str;
}

static CHARS: &'static[u8] = bytes!("0123456789abcdef");

impl<'self> ToHex for &'self [u8] {
    /**
     * Turn a vector of `u8` bytes into a hexadecimal string.
     *
     * # Example
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::hex::ToHex;
     *
     * fn main () {
     *     let str = [52,32].to_hex();
     *     printfln!("%s", str);
     * }
     * ~~~
     */
    fn to_hex(&self) -> ~str {
        let mut v = vec::with_capacity(self.len() * 2);
        for &byte in self.iter() {
            v.push(CHARS[byte >> 4]);
            v.push(CHARS[byte & 0xf]);
        }

        unsafe {
            str::raw::from_bytes_owned(v)
        }
    }
}

/// A trait for converting hexadecimal encoded values
pub trait FromHex {
    /// Converts the value of `self`, interpreted as hexadecimal encoded data,
    /// into an owned vector of bytes, returning the vector.
    fn from_hex(&self) -> Result<~[u8], ~str>;
}

impl<'self> FromHex for &'self str {
    /**
     * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)
     * to the byte values it encodes.
     *
     * You can use the `from_bytes` function in `std::str`
     * to turn a `[u8]` into a string with characters corresponding to those
     * values.
     *
     * # Example
     *
     * This converts a string literal to hexadecimal and back.
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::hex::{FromHex, ToHex};
     * use std::str;
     *
     * fn main () {
     *     let hello_str = "Hello, World".to_hex();
     *     printfln!("%s", hello_str);
     *     let bytes = hello_str.from_hex().unwrap();
     *     printfln!("%?", bytes);
     *     let result_str = str::from_bytes(bytes);
     *     printfln!("%s", result_str);
     * }
     * ~~~
     */
    fn from_hex(&self) -> Result<~[u8], ~str> {
        // This may be an overestimate if there is any whitespace
        let mut b = vec::with_capacity(self.len() / 2);
        let mut modulus = 0;
        let mut buf = 0u8;

        for (idx, byte) in self.byte_iter().enumerate() {
            buf <<= 4;

            match byte as char {
                'A'..'F' => buf |= byte - ('A' as u8) + 10,
                'a'..'f' => buf |= byte - ('a' as u8) + 10,
                '0'..'9' => buf |= byte - ('0' as u8),
                ' '|'\r'|'\n'|'\t' => {
                    buf >>= 4;
                    loop
                }
                _ => return Err(fmt!("Invalid character '%c' at position %u",
                                     self.char_at(idx), idx))
            }

            modulus += 1;
            if modulus == 2 {
                modulus = 0;
                b.push(buf);
            }
        }

        match modulus {
            0 => Ok(b),
            _ => Err(~"Invalid input length")
        }
    }
}

#[cfg(test)]
mod tests {
    use test::BenchHarness;
    use hex::*;

    #[test]
    pub fn test_to_hex() {
        assert_eq!("foobar".as_bytes().to_hex(), ~"666f6f626172");
    }

    #[test]
    pub fn test_from_hex_okay() {
        assert_eq!("666f6f626172".from_hex().unwrap(),
                   "foobar".as_bytes().to_owned());
        assert_eq!("666F6F626172".from_hex().unwrap(),
                   "foobar".as_bytes().to_owned());
    }

    #[test]
    pub fn test_from_hex_odd_len() {
        assert!("666".from_hex().is_err());
        assert!("66 6".from_hex().is_err());
    }

    #[test]
    pub fn test_from_hex_invalid_char() {
        assert!("66y6".from_hex().is_err());
    }

    #[test]
    pub fn test_from_hex_ignores_whitespace() {
        assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(),
                   "foobar".as_bytes().to_owned());
    }

    #[test]
    pub fn test_to_hex_all_bytes() {
        for i in range(0, 256) {
            assert_eq!([i as u8].to_hex(), fmt!("%02x", i as uint));
        }
    }

    #[test]
    pub fn test_from_hex_all_bytes() {
        for i in range(0, 256) {
            assert_eq!(fmt!("%02x", i as uint).from_hex().unwrap(), ~[i as u8]);
            assert_eq!(fmt!("%02X", i as uint).from_hex().unwrap(), ~[i as u8]);
        }
    }

    #[bench]
    pub fn bench_to_hex(bh: & mut BenchHarness) {
        let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
                 ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
        do bh.iter {
            s.as_bytes().to_hex();
        }
        bh.bytes = s.len() as u64;
    }

    #[bench]
    pub fn bench_from_hex(bh: & mut BenchHarness) {
        let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
                 ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
        let b = s.as_bytes().to_hex();
        do bh.iter {
            b.from_hex();
        }
        bh.bytes = b.len() as u64;
    }
}
<|endoftext|>


<commit_before>//
// sprocketnes/disasm.rs
//
// Author: Patrick Walton
//

use mem::Mem;

pub struct Disassembler<M> {
    pc: u16,
    mem: *mut M
}

impl<M:Mem> Disassembler<M> {
    //
    // Loads and byte-to-string conversion
    //

    fn loadb_bump_pc(&mut self) -> u8 {
        unsafe {
            let val = (&mut *self.mem).loadb(self.pc);
            self.pc += 1;
            val
        }
    }
    fn loadw_bump_pc(&mut self) -> u16 {
        let bottom = self.loadb_bump_pc() as u16;
        let top = self.loadb_bump_pc() as u16 << 8;
        bottom | top
    }

    fn disb_bump_pc(&mut self) -> ~str { format!("${:02X}", self.loadb_bump_pc() as uint) }
    fn disw_bump_pc(&mut self) -> ~str { format!("${:04X}", self.loadw_bump_pc() as uint) }

    //
    // Mnemonics
    //

    // TODO: When we get method macros some of this ugly duplication can go away.

    // Loads
    fn lda(&mut self, am: ~str) -> ~str { ~"LDA " + am }
    fn ldx(&mut self, am: ~str) -> ~str { ~"LDX " + am }
    fn ldy(&mut self, am: ~str) -> ~str { ~"LDY " + am }

    // Stores
    fn sta(&mut self, am: ~str) -> ~str { ~"STA " + am }
    fn stx(&mut self, am: ~str) -> ~str { ~"STX " + am }
    fn sty(&mut self, am: ~str) -> ~str { ~"STY " + am }

    // Arithmetic
    fn adc(&mut self, am: ~str) -> ~str { ~"ADC " + am }
    fn sbc(&mut self, am: ~str) -> ~str { ~"SBC " + am }

    // Comparisons
    fn cmp(&mut self, am: ~str) -> ~str { ~"CMP " + am }
    fn cpx(&mut self, am: ~str) -> ~str { ~"CPX " + am }
    fn cpy(&mut self, am: ~str) -> ~str { ~"CPY " + am }

    // Bitwise operations
    fn and(&mut self, am: ~str) -> ~str { ~"AND " + am }
    fn ora(&mut self, am: ~str) -> ~str { ~"ORA " + am }
    fn eor(&mut self, am: ~str) -> ~str { ~"EOR " + am }
    fn bit(&mut self, am: ~str) -> ~str { ~"BIT " + am }

    // Shifts and rotates
    fn rol(&mut self, am: ~str) -> ~str { ~"ROL " + am }
    fn ror(&mut self, am: ~str) -> ~str { ~"ROR " + am }
    fn asl(&mut self, am: ~str) -> ~str { ~"ASL " + am }
    fn lsr(&mut self, am: ~str) -> ~str { ~"LSR " + am }

    // Increments and decrements
    fn inc(&mut self, am: ~str) -> ~str { ~"INC " + am }
    fn dec(&mut self, am: ~str) -> ~str { ~"DEC " + am }
    fn inx(&mut self) -> ~str           { ~"INX"       }
    fn dex(&mut self) -> ~str           { ~"DEX"       }
    fn iny(&mut self) -> ~str           { ~"INY"       }
    fn dey(&mut self) -> ~str           { ~"DEY"       }

    // Register moves
    fn tax(&mut self) -> ~str           { ~"TAX"       }
    fn tay(&mut self) -> ~str           { ~"TAY"       }
    fn txa(&mut self) -> ~str           { ~"TXA"       }
    fn tya(&mut self) -> ~str           { ~"TYA"       }
    fn txs(&mut self) -> ~str           { ~"TXS"       }
    fn tsx(&mut self) -> ~str           { ~"TSX"       }

    // Flag operations
    fn clc(&mut self) -> ~str           { ~"CLC"       }
    fn sec(&mut self) -> ~str           { ~"SEC"       }
    fn cli(&mut self) -> ~str           { ~"CLI"       }
    fn sei(&mut self) -> ~str           { ~"SEI"       }
    fn clv(&mut self) -> ~str           { ~"CLV"       }
    fn cld(&mut self) -> ~str           { ~"CLD"       }
    fn sed(&mut self) -> ~str           { ~"SED"       }

    // Branches
    // FIXME: Should disassemble the displacement!
    fn bpl(&mut self) -> ~str           { ~"BPL xx"    }
    fn bmi(&mut self) -> ~str           { ~"BMI xx"    }
    fn bvc(&mut self) -> ~str           { ~"BVC xx"    }
    fn bvs(&mut self) -> ~str           { ~"BVS xx"    }
    fn bcc(&mut self) -> ~str           { ~"BCC xx"    }
    fn bcs(&mut self) -> ~str           { ~"BCS xx"    }
    fn bne(&mut self) -> ~str           { ~"BNE xx"    }
    fn beq(&mut self) -> ~str           { ~"BEQ xx"    }

    // Jumps
    // FIXME: Should disassemble the address!
    fn jmp(&mut self) -> ~str           { ~"JMP xx"    }
    fn jmpi(&mut self) -> ~str          { ~"JMP (xx)"  }

    // Procedure calls
    // FIXME: Should disassemble the address!
    fn jsr(&mut self) -> ~str           { ~"JSR xx"    }
    fn rts(&mut self) -> ~str           { ~"RTS"       }
    fn brk(&mut self) -> ~str           { ~"BRK"       }
    fn rti(&mut self) -> ~str           { ~"RTI"       }

    // Stack operations
    fn pha(&mut self) -> ~str           { ~"PHA"       }
    fn pla(&mut self) -> ~str           { ~"PLA"       }
    fn php(&mut self) -> ~str           { ~"PHP"       }
    fn plp(&mut self) -> ~str           { ~"PLP"       }

    // No operation
    fn nop(&mut self) -> ~str           { ~"NOP"       }

    // Addressing modes
    fn immediate(&mut self) -> ~str          { ~"#" + self.disb_bump_pc()          }
    fn accumulator(&mut self) -> ~str        { ~""                                 }
    fn zero_page(&mut self) -> ~str          { self.disb_bump_pc()                 }
    fn zero_page_x(&mut self) -> ~str        { self.disb_bump_pc() + ",X"          }
    fn zero_page_y(&mut self) -> ~str        { self.disb_bump_pc() + ",Y"          }
    fn absolute(&mut self) -> ~str           { self.disw_bump_pc()                 }
    fn absolute_x(&mut self) -> ~str         { self.disw_bump_pc() + ",X"          }
    fn absolute_y(&mut self) -> ~str         { self.disw_bump_pc() + ",Y"          }
    fn indexed_indirect_x(&mut self) -> ~str { ~"(" + self.disb_bump_pc() + ",X)"  }
    fn indirect_indexed_y(&mut self) -> ~str { ~"(" + self.disb_bump_pc() + "),Y"  }

    // The main disassembly routine.
    #[inline(never)]
    pub fn disassemble(&mut self) -> ~str {
        let op = self.loadb_bump_pc();
        decode_op!(op, self)
    }
}

<commit_msg>Stop using ~"" in the disassembler<commit_after>//
// sprocketnes/disasm.rs
//
// Author: Patrick Walton
//

use mem::Mem;

pub struct Disassembler<M> {
    pc: u16,
    mem: *mut M
}

impl<M:Mem> Disassembler<M> {
    //
    // Loads and byte-to-string conversion
    //

    fn loadb_bump_pc(&mut self) -> u8 {
        unsafe {
            let val = (&mut *self.mem).loadb(self.pc);
            self.pc += 1;
            val
        }
    }
    fn loadw_bump_pc(&mut self) -> u16 {
        let bottom = self.loadb_bump_pc() as u16;
        let top = self.loadb_bump_pc() as u16 << 8;
        bottom | top
    }

    fn disb_bump_pc(&mut self) -> ~str { format!("${:02X}", self.loadb_bump_pc() as uint) }
    fn disw_bump_pc(&mut self) -> ~str { format!("${:04X}", self.loadw_bump_pc() as uint) }

    //
    // Mnemonics
    //

    // TODO: When we get method macros some of this ugly duplication can go away.

    // Loads
    fn lda(&mut self, am: ~str) -> ~str { format!("LDA {}", am) }
    fn ldx(&mut self, am: ~str) -> ~str { format!("LDX {}", am) }
    fn ldy(&mut self, am: ~str) -> ~str { format!("LDY {}", am) }

    // Stores
    fn sta(&mut self, am: ~str) -> ~str { format!("STA {}", am) }
    fn stx(&mut self, am: ~str) -> ~str { format!("STX {}", am) }
    fn sty(&mut self, am: ~str) -> ~str { format!("STY {}", am) }

    // Arithmetic
    fn adc(&mut self, am: ~str) -> ~str { format!("ADC {}", am) }
    fn sbc(&mut self, am: ~str) -> ~str { format!("SBC {}", am) }

    // Comparisons
    fn cmp(&mut self, am: ~str) -> ~str { format!("CMP {}", am) }
    fn cpx(&mut self, am: ~str) -> ~str { format!("CPX {}", am) }
    fn cpy(&mut self, am: ~str) -> ~str { format!("CPY {}", am) }

    // Bitwise operations
    fn and(&mut self, am: ~str) -> ~str { format!("AND {}", am) }
    fn ora(&mut self, am: ~str) -> ~str { format!("ORA {}", am) }
    fn eor(&mut self, am: ~str) -> ~str { format!("EOR {}", am) }
    fn bit(&mut self, am: ~str) -> ~str { format!("BIT {}", am) }

    // Shifts and rotates
    fn rol(&mut self, am: ~str) -> ~str { format!("ROL {}", am) }
    fn ror(&mut self, am: ~str) -> ~str { format!("ROR {}", am) }
    fn asl(&mut self, am: ~str) -> ~str { format!("ASL {}", am) }
    fn lsr(&mut self, am: ~str) -> ~str { format!("LSR {}", am) }

    // Increments and decrements
    fn inc(&mut self, am: ~str) -> ~str { format!("INC {}", am) }
    fn dec(&mut self, am: ~str) -> ~str { format!("DEC {}", am) }
    fn inx(&mut self) -> ~str           { "INX".to_str()       }
    fn dex(&mut self) -> ~str           { "DEX".to_str()       }
    fn iny(&mut self) -> ~str           { "INY".to_str()       }
    fn dey(&mut self) -> ~str           { "DEY".to_str()       }

    // Register moves
    fn tax(&mut self) -> ~str           { "TAX".to_str()       }
    fn tay(&mut self) -> ~str           { "TAY".to_str()       }
    fn txa(&mut self) -> ~str           { "TXA".to_str()       }
    fn tya(&mut self) -> ~str           { "TYA".to_str()       }
    fn txs(&mut self) -> ~str           { "TXS".to_str()       }
    fn tsx(&mut self) -> ~str           { "TSX".to_str()       }

    // Flag operations
    fn clc(&mut self) -> ~str           { "CLC".to_str()       }
    fn sec(&mut self) -> ~str           { "SEC".to_str()       }
    fn cli(&mut self) -> ~str           { "CLI".to_str()       }
    fn sei(&mut self) -> ~str           { "SEI".to_str()       }
    fn clv(&mut self) -> ~str           { "CLV".to_str()       }
    fn cld(&mut self) -> ~str           { "CLD".to_str()       }
    fn sed(&mut self) -> ~str           { "SED".to_str()       }

    // Branches
    // FIXME: Should disassemble the displacement!
    fn bpl(&mut self) -> ~str           { "BPL xx".to_str()    }
    fn bmi(&mut self) -> ~str           { "BMI xx".to_str()    }
    fn bvc(&mut self) -> ~str           { "BVC xx".to_str()    }
    fn bvs(&mut self) -> ~str           { "BVS xx".to_str()    }
    fn bcc(&mut self) -> ~str           { "BCC xx".to_str()    }
    fn bcs(&mut self) -> ~str           { "BCS xx".to_str()    }
    fn bne(&mut self) -> ~str           { "BNE xx".to_str()    }
    fn beq(&mut self) -> ~str           { "BEQ xx".to_str()    }

    // Jumps
    // FIXME: Should disassemble the address!
    fn jmp(&mut self) -> ~str           { "JMP xx".to_str()    }
    fn jmpi(&mut self) -> ~str          { "JMP (xx)".to_str()  }

    // Procedure calls
    // FIXME: Should disassemble the address!
    fn jsr(&mut self) -> ~str           { "JSR xx".to_str()    }
    fn rts(&mut self) -> ~str           { "RTS".to_str()       }
    fn brk(&mut self) -> ~str           { "BRK".to_str()       }
    fn rti(&mut self) -> ~str           { "RTI".to_str()       }

    // Stack operations
    fn pha(&mut self) -> ~str           { "PHA".to_str()       }
    fn pla(&mut self) -> ~str           { "PLA".to_str()       }
    fn php(&mut self) -> ~str           { "PHP".to_str()       }
    fn plp(&mut self) -> ~str           { "PLP".to_str()       }

    // No operation
    fn nop(&mut self) -> ~str           { "NOP".to_str()       }

    // Addressing modes
    fn immediate(&mut self) -> ~str          { format!("{}{}", "#", self.disb_bump_pc()) }
    fn accumulator(&mut self) -> ~str        { "".to_str()                               }
    fn zero_page(&mut self) -> ~str          { self.disb_bump_pc()                       }
    fn zero_page_x(&mut self) -> ~str        { self.disb_bump_pc() + ",X"                }
    fn zero_page_y(&mut self) -> ~str        { self.disb_bump_pc() + ",Y"                }
    fn absolute(&mut self) -> ~str           { self.disw_bump_pc()                       }
    fn absolute_x(&mut self) -> ~str         { self.disw_bump_pc() + ",X"                }
    fn absolute_y(&mut self) -> ~str         { self.disw_bump_pc() + ",Y"                }
    fn indexed_indirect_x(&mut self) -> ~str { format!("({},X)", self.disb_bump_pc())    }
    fn indirect_indexed_y(&mut self) -> ~str { format!("({}),Y", self.disb_bump_pc())    }

    // The main disassembly routine.
    #[inline(never)]
    pub fn disassemble(&mut self) -> ~str {
        let op = self.loadb_bump_pc();
        decode_op!(op, self)
    }
}

<|endoftext|>


<commit_before>extern crate clap;
extern crate diff;
extern crate bindgen;
extern crate shlex;

use bindgen::{Builder, builder, clang_version};
use std::fs;
use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::process;
use std::sync::{Once, ONCE_INIT};

#[path = "../src/options.rs"]
mod options;
use options::builder_from_flags;

// Run `rustfmt` on the given source string and return a tuple of the formatted
// bindings, and rustfmt's stderr.
fn rustfmt(source: String) -> (String, String) {
    static CHECK_RUSTFMT: Once = ONCE_INIT;

    CHECK_RUSTFMT.call_once(|| {
        let have_working_rustfmt = process::Command::new("rustup")
            .args(&["run", "nightly", "rustfmt", "--version"])
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null())
            .status()
            .ok()
            .map_or(false, |status| status.success());

        if !have_working_rustfmt {
            panic!("
The latest `rustfmt` is required to run the `bindgen` test suite. Install
`rustfmt` with:

    $ rustup update nightly
    $ rustup run nightly cargo install -f rustfmt-nightly
");
        }
    });

    let mut child = process::Command::new("rustup")
        .args(&[
            "run",
            "nightly",
            "rustfmt",
            "--config-path",
            concat!(env!("CARGO_MANIFEST_DIR"), "/tests/rustfmt.toml")
        ])
        .stdin(process::Stdio::piped())
        .stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .spawn()
        .expect("should spawn `rustup run nightly rustfmt`");

    let mut stdin = child.stdin.take().unwrap();
    let mut stdout = child.stdout.take().unwrap();
    let mut stderr = child.stderr.take().unwrap();

    // Write to stdin in a new thread, so that we can read from stdout on this
    // thread. This keeps the child from blocking on writing to its stdout which
    // might block us from writing to its stdin.
    let stdin_handle = ::std::thread::spawn(move || {
        stdin.write_all(source.as_bytes())
    });

    // Read stderr on a new thread for similar reasons.
    let stderr_handle = ::std::thread::spawn(move || {
        let mut output = vec![];
        io::copy(&mut stderr, &mut output)
            .map(|_| String::from_utf8_lossy(&output).to_string())
    });

    let mut output = vec![];
    io::copy(&mut stdout, &mut output)
        .expect("Should copy stdout into vec OK");

    // Ignore actual rustfmt status because it is often non-zero for trivial
    // things.
    let _ = child.wait().expect("should wait on rustfmt child OK");

    stdin_handle.join()
        .expect("writer thread should not have panicked")
        .expect("should have written to child rustfmt's stdin OK");

    let bindings = String::from_utf8(output)
        .expect("rustfmt should only emit valid utf-8");

    let stderr = stderr_handle.join()
        .expect("stderr reader thread should not have panicked")
        .expect("should have read child rustfmt's stderr OK");

    (bindings, stderr)
}

fn compare_generated_header(
    header: &PathBuf,
    builder: Builder,
) -> Result<(), Error> {
    let file_name = try!(header.file_name().ok_or(Error::new(
        ErrorKind::Other,
        "compare_generated_header expects a file",
    )));

    let mut expectation = PathBuf::from(header);
    expectation.pop();
    expectation.pop();
    expectation.push("expectations");
    expectation.push("tests");
    expectation.push(file_name);
    expectation.set_extension("rs");

    // If the expectation file doesn't exist, see if we have different test
    // expectations for different libclang versions.
    if !expectation.is_file() {
        let file_name = expectation.file_name().unwrap().to_owned();
        expectation.pop();

        if cfg!(feature = "testing_only_libclang_4") {
            expectation.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expectation.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expectation.push("libclang-3.8");
        } else {
            match clang_version().parsed {
                None => {}
                Some(version) => {
                    let (maj, min) = version;
                    let version_str = if maj >= 4 {
                        "4".to_owned()
                    } else {
                        format!("{}.{}", maj, min)
                    };
                    expectation.push(format!("libclang-{}", version_str));
                }
            }
        }

        expectation.push(file_name);

        if !expectation.is_file() {
            panic!(
                "missing test expectation file and/or 'testing_only_libclang_$VERSION' \
                    feature for header '{}'; looking for expectation file at '{}'",
                header.display(),
                expectation.display()
            );
        }
    }

    // We skip the generate() error here so we get a full diff below
    let (actual, rustfmt_stderr) = match builder.generate() {
        Ok(bindings) => {
            let actual = bindings.to_string();
            rustfmt(actual)
        }
        Err(()) => ("<error generating bindings>".to_string(), "".to_string()),
    };
    println!("{}", rustfmt_stderr);

    let mut expected = String::new();
    {
        if let Ok(expectation_file) = fs::File::open(&expectation) {
            try!(BufReader::new(expectation_file).read_to_string(&mut expected));
        }
    }

    let (expected, rustfmt_stderr) = rustfmt(expected);
    println!("{}", rustfmt_stderr);

    if actual == expected {
        if !actual.is_empty() {
            return Ok(());
        }
        return Err(Error::new(
            ErrorKind::Other,
            "Something's gone really wrong!",
        ));
    }

    println!("{}", rustfmt_stderr);

    println!("diff expected generated");
    println!("--- expected: {:?}", expectation);
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&expected, &actual) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Override the diff.
    {
        let mut expectation_file = try!(fs::File::create(&expectation));
        try!(expectation_file.write_all(actual.as_bytes()));
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ!"))
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    let source = try!(fs::File::open(header));
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = try!(line);
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line.split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags
                .into_iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        } else if line.contains("bindgen-generate-bindings-on-linux-only") &&
                   !cfg!(target_os = "linux")
        {
            return Ok(None);
        }
    }

    // Different platforms have various different conventions like struct padding, mangling, etc.
    // We make the default target as x86_64-unknown-linux
    if flags.iter().all(|flag| !flag.starts_with("--target=")) {
        if !flags.iter().any(|flag| flag == "--") {
            flags.push("--".into());
        }
        flags.push("--target=x86_64-unknown-linux".into());
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = try!(header.to_str().ok_or(Error::new(
        ErrorKind::Other,
        "Invalid header file name",
    )));

    let prepend = [
        "bindgen",
        "--with-derive-default",
        header_str,
        "--raw-line",
        "",
        "--raw-line",
        "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
        "--raw-line",
        "",
    ];

    let args = prepend.into_iter().map(ToString::to_string).chain(
        flags
            .into_iter(),
    );

    builder_from_flags(args).map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => (
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header)
                .and_then(|builder| {
                    if let Some(builder) = builder {
                        compare_generated_header(&header, builder)
                    } else {
                        Ok(())
                    }
                });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    )
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_header_contents() {
    let actual = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let (expected, _) = rustfmt("/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
".to_string());

    assert_eq!(
        expected,
        actual
    );
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/tests/headers/func_ptr.h"
        ))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h"))
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let expected = include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"
    ));
    let (expected, _) = rustfmt(expected.to_string());

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}

#[test]
// Doesn't support executing sh file on Windows.
// We may want to implement it in Rust so that we support all systems.
#[cfg(not(target_os = "windows"))]
fn no_system_header_includes() {
    use std::process::Command;
    assert!(
        Command::new("./ci/no-includes.sh")
            .current_dir(env!("CARGO_MANIFEST_DIR"))
            .spawn()
            .expect("should spawn ./ci/no-includes.sh OK")
            .wait()
            .expect("should wait for ./ci/no-includes OK")
            .success()
    );
}

#[test]
fn dump_preprocessed_input() {
    let arg_keyword =
        concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/arg_keyword.hpp");
    let empty_layout = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/headers/cpp-empty-layout.hpp"
    );

    builder()
        .header(arg_keyword)
        .header(empty_layout)
        .dump_preprocessed_input()
        .expect("should dump preprocessed input");

    fn slurp(p: &str) -> String {
        let mut contents = String::new();
        let mut file = fs::File::open(p).unwrap();
        file.read_to_string(&mut contents).unwrap();
        contents
    }

    let bindgen_ii = slurp("__bindgen.ii");
    let arg_keyword = slurp(arg_keyword);
    let empty_layout = slurp(empty_layout);

    assert!(
        bindgen_ii.find(&arg_keyword).is_some(),
        "arg_keyword.hpp is in the preprocessed file"
    );
    assert!(
        bindgen_ii.find(&empty_layout).is_some(),
        "cpp-empty-layout.hpp is in the preprocessed file"
    );
}
<commit_msg>Give explicit target to builder tests.<commit_after>extern crate clap;
extern crate diff;
extern crate bindgen;
extern crate shlex;

use bindgen::{Builder, builder, clang_version};
use std::fs;
use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::process;
use std::sync::{Once, ONCE_INIT};

#[path = "../src/options.rs"]
mod options;
use options::builder_from_flags;

// Run `rustfmt` on the given source string and return a tuple of the formatted
// bindings, and rustfmt's stderr.
fn rustfmt(source: String) -> (String, String) {
    static CHECK_RUSTFMT: Once = ONCE_INIT;

    CHECK_RUSTFMT.call_once(|| {
        let have_working_rustfmt = process::Command::new("rustup")
            .args(&["run", "nightly", "rustfmt", "--version"])
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null())
            .status()
            .ok()
            .map_or(false, |status| status.success());

        if !have_working_rustfmt {
            panic!("
The latest `rustfmt` is required to run the `bindgen` test suite. Install
`rustfmt` with:

    $ rustup update nightly
    $ rustup run nightly cargo install -f rustfmt-nightly
");
        }
    });

    let mut child = process::Command::new("rustup")
        .args(&[
            "run",
            "nightly",
            "rustfmt",
            "--config-path",
            concat!(env!("CARGO_MANIFEST_DIR"), "/tests/rustfmt.toml")
        ])
        .stdin(process::Stdio::piped())
        .stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .spawn()
        .expect("should spawn `rustup run nightly rustfmt`");

    let mut stdin = child.stdin.take().unwrap();
    let mut stdout = child.stdout.take().unwrap();
    let mut stderr = child.stderr.take().unwrap();

    // Write to stdin in a new thread, so that we can read from stdout on this
    // thread. This keeps the child from blocking on writing to its stdout which
    // might block us from writing to its stdin.
    let stdin_handle = ::std::thread::spawn(move || {
        stdin.write_all(source.as_bytes())
    });

    // Read stderr on a new thread for similar reasons.
    let stderr_handle = ::std::thread::spawn(move || {
        let mut output = vec![];
        io::copy(&mut stderr, &mut output)
            .map(|_| String::from_utf8_lossy(&output).to_string())
    });

    let mut output = vec![];
    io::copy(&mut stdout, &mut output)
        .expect("Should copy stdout into vec OK");

    // Ignore actual rustfmt status because it is often non-zero for trivial
    // things.
    let _ = child.wait().expect("should wait on rustfmt child OK");

    stdin_handle.join()
        .expect("writer thread should not have panicked")
        .expect("should have written to child rustfmt's stdin OK");

    let bindings = String::from_utf8(output)
        .expect("rustfmt should only emit valid utf-8");

    let stderr = stderr_handle.join()
        .expect("stderr reader thread should not have panicked")
        .expect("should have read child rustfmt's stderr OK");

    (bindings, stderr)
}

fn compare_generated_header(
    header: &PathBuf,
    builder: Builder,
) -> Result<(), Error> {
    let file_name = try!(header.file_name().ok_or(Error::new(
        ErrorKind::Other,
        "compare_generated_header expects a file",
    )));

    let mut expectation = PathBuf::from(header);
    expectation.pop();
    expectation.pop();
    expectation.push("expectations");
    expectation.push("tests");
    expectation.push(file_name);
    expectation.set_extension("rs");

    // If the expectation file doesn't exist, see if we have different test
    // expectations for different libclang versions.
    if !expectation.is_file() {
        let file_name = expectation.file_name().unwrap().to_owned();
        expectation.pop();

        if cfg!(feature = "testing_only_libclang_4") {
            expectation.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expectation.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expectation.push("libclang-3.8");
        } else {
            match clang_version().parsed {
                None => {}
                Some(version) => {
                    let (maj, min) = version;
                    let version_str = if maj >= 4 {
                        "4".to_owned()
                    } else {
                        format!("{}.{}", maj, min)
                    };
                    expectation.push(format!("libclang-{}", version_str));
                }
            }
        }

        expectation.push(file_name);

        if !expectation.is_file() {
            panic!(
                "missing test expectation file and/or 'testing_only_libclang_$VERSION' \
                    feature for header '{}'; looking for expectation file at '{}'",
                header.display(),
                expectation.display()
            );
        }
    }

    // We skip the generate() error here so we get a full diff below
    let (actual, rustfmt_stderr) = match builder.generate() {
        Ok(bindings) => {
            let actual = bindings.to_string();
            rustfmt(actual)
        }
        Err(()) => ("<error generating bindings>".to_string(), "".to_string()),
    };
    println!("{}", rustfmt_stderr);

    let mut expected = String::new();
    {
        if let Ok(expectation_file) = fs::File::open(&expectation) {
            try!(BufReader::new(expectation_file).read_to_string(&mut expected));
        }
    }

    let (expected, rustfmt_stderr) = rustfmt(expected);
    println!("{}", rustfmt_stderr);

    if actual == expected {
        if !actual.is_empty() {
            return Ok(());
        }
        return Err(Error::new(
            ErrorKind::Other,
            "Something's gone really wrong!",
        ));
    }

    println!("{}", rustfmt_stderr);

    println!("diff expected generated");
    println!("--- expected: {:?}", expectation);
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&expected, &actual) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Override the diff.
    {
        let mut expectation_file = try!(fs::File::create(&expectation));
        try!(expectation_file.write_all(actual.as_bytes()));
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ!"))
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    let source = try!(fs::File::open(header));
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = try!(line);
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line.split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags
                .into_iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        } else if line.contains("bindgen-generate-bindings-on-linux-only") &&
                   !cfg!(target_os = "linux")
        {
            return Ok(None);
        }
    }

    // Different platforms have various different conventions like struct padding, mangling, etc.
    // We make the default target as x86_64-unknown-linux
    if flags.iter().all(|flag| !flag.starts_with("--target=")) {
        if !flags.iter().any(|flag| flag == "--") {
            flags.push("--".into());
        }
        flags.push("--target=x86_64-unknown-linux".into());
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = try!(header.to_str().ok_or(Error::new(
        ErrorKind::Other,
        "Invalid header file name",
    )));

    let prepend = [
        "bindgen",
        "--with-derive-default",
        header_str,
        "--raw-line",
        "",
        "--raw-line",
        "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
        "--raw-line",
        "",
    ];

    let args = prepend.into_iter().map(ToString::to_string).chain(
        flags
            .into_iter(),
    );

    builder_from_flags(args).map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => (
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header)
                .and_then(|builder| {
                    if let Some(builder) = builder {
                        compare_generated_header(&header, builder)
                    } else {
                        Ok(())
                    }
                });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    )
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_header_contents() {
    let actual = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .clang_arg("--target=x86_64-unknown-linux")
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let (expected, _) = rustfmt("/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
".to_string());

    assert_eq!(
        expected,
        actual
    );
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/tests/headers/func_ptr.h"
        ))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h"))
        .clang_arg("--target=x86_64-unknown-linux")
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let expected = include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"
    ));
    let (expected, _) = rustfmt(expected.to_string());

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}

#[test]
// Doesn't support executing sh file on Windows.
// We may want to implement it in Rust so that we support all systems.
#[cfg(not(target_os = "windows"))]
fn no_system_header_includes() {
    use std::process::Command;
    assert!(
        Command::new("./ci/no-includes.sh")
            .current_dir(env!("CARGO_MANIFEST_DIR"))
            .spawn()
            .expect("should spawn ./ci/no-includes.sh OK")
            .wait()
            .expect("should wait for ./ci/no-includes OK")
            .success()
    );
}

#[test]
fn dump_preprocessed_input() {
    let arg_keyword =
        concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/arg_keyword.hpp");
    let empty_layout = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/headers/cpp-empty-layout.hpp"
    );

    builder()
        .header(arg_keyword)
        .header(empty_layout)
        .dump_preprocessed_input()
        .expect("should dump preprocessed input");

    fn slurp(p: &str) -> String {
        let mut contents = String::new();
        let mut file = fs::File::open(p).unwrap();
        file.read_to_string(&mut contents).unwrap();
        contents
    }

    let bindgen_ii = slurp("__bindgen.ii");
    let arg_keyword = slurp(arg_keyword);
    let empty_layout = slurp(empty_layout);

    assert!(
        bindgen_ii.find(&arg_keyword).is_some(),
        "arg_keyword.hpp is in the preprocessed file"
    );
    assert!(
        bindgen_ii.find(&empty_layout).is_some(),
        "cpp-empty-layout.hpp is in the preprocessed file"
    );
}
<|endoftext|>


<commit_before>extern crate citybound_common;
use citybound_common::*;

extern crate rouille;
use rouille::{Response, extension_to_mime};

#[macro_use]
extern crate rust_embed_flag;

#[derive(RustEmbed)]
#[folder = "game_browser/dist/"]
struct Asset;

extern crate clap;
use clap::{Arg, App};

use kay::Actor;
use transport::lane::{Lane, SwitchLane};
use economy::households::family::Family;
use economy::households::grocery_shop::GroceryShop;
use economy::households::grain_farm::GrainFarm;
use economy::households::cow_farm::CowFarm;
use economy::households::mill::Mill;
use economy::households::bakery::Bakery;
use economy::households::neighboring_town_trade::NeighboringTownTrade;
use economy::households::tasks::TaskEndScheduler;
use construction::Construction;

const VERSION: &str = include_str!("../.version");

fn main() {
    let arg_matches = App::new("citybound")
        .version(VERSION.trim())
        .author("ae play (Anselm Eickhoff)")
        .about("The city is us.")
        .arg(
            Arg::with_name("mode")
                .long("mode")
                .value_name("local/lan/internet")
                .display_order(0)
                .possible_values(&["local", "lan", "internet"])
                .default_value("local")
                .help("Where to expose the simulation. Sets defaults other settings."),
        ).arg(
            Arg::with_name("bind")
                .long("bind")
                .value_name("host:port")
                .default_value_ifs(&[
                    ("mode", Some("local"), "localhost:1234"),
                    ("mode", Some("lan"), "0.0.0.0:1234"),
                    ("mode", Some("internet"), "0.0.0.0:1234"),
                ]).help("Address and port to serve the browser UI from"),
        ).arg(
            Arg::with_name("bind-sim")
                .long("bind-sim")
                .value_name("host:port")
                .default_value_ifs(&[
                    ("mode", Some("local"), "localhost:9999"),
                    ("mode", Some("lan"), "0.0.0.0:9999"),
                    ("mode", Some("internet"), "0.0.0.0:9999"),
                ]).help("Address and port to accept connections to the simulation from"),
        ).arg(
            Arg::with_name("batch-msg-b")
                .long("batch-msg-bytes")
                .value_name("n-bytes")
                .default_value("5000")
                .help("How many bytes of simulation messages to batch"),
        ).arg(
            Arg::with_name("ok-turn-dist")
                .long("ok-turn-dist")
                .value_name("n-turns")
                .default_value_ifs(&[
                    ("mode", Some("local"), "2"),
                    ("mode", Some("lan"), "10"),
                    ("mode", Some("internet"), "30"),
                ]).help("How many network turns client/server can be behind before skipping"),
        ).arg(
            Arg::with_name("skip-ratio")
                .long("skip-ratio")
                .value_name("n-turns")
                .default_value("5")
                .help("How many network turns to skip if server/client are ahead"),
        ).get_matches();

    let serve_host_port = arg_matches.value_of("bind").unwrap().to_owned();
    let arg_matches_2 = arg_matches.clone();

    let my_host = format!(
        "{}:{}",
        match arg_matches.value_of("mode").unwrap() {
            "local" => "localhost",
            "lan" => "<your LAN IP>",
            "internet" => "<your public IP>",
            _ => unreachable!(),
        },
        serve_host_port.split(':').nth(1).unwrap(),
    );

    ::std::thread::spawn(move || {
        println!("╭───────────────────────────────────────────╮");
        println!("│ {: ^41} │", format!("Citybound {}", VERSION.trim()));
        println!("│ {: ^41} │", format!("Running at http://{}", my_host));
        println!("╰───────────────────────────────────────────╯");

        rouille::start_server(serve_host_port, move |request| {
            if request.raw_url() == "/" {
                println!("{:?} loaded page", request.remote_addr());

                let template = std::str::from_utf8(
                    &Asset::get("index.html").expect("index.html should exist as asset"),
                ).unwrap()
                .to_owned();

                let rendered = template
                    .replace("CB_VERSION", VERSION.trim())
                    .replace(
                        "CB_BATCH_MESSAGE_BYTES",
                        arg_matches_2.value_of("batch-msg-b").unwrap(),
                    ).replace(
                        "CB_ACCEPTABLE_TURN_DISTANCE",
                        arg_matches_2.value_of("ok-turn-dist").unwrap(),
                    ).replace(
                        "CB_SKIP_TURNS_PER_TURN_AHEAD",
                        arg_matches_2.value_of("skip-ratio").unwrap(),
                    );

                Response::html(rendered)
            } else {
                if let Some(asset) = Asset::get(&request.url()[1..]) {
                    Response::from_data(
                        extension_to_mime(request.url().split('.').last().unwrap_or("")),
                        asset,
                    )
                } else {
                    Response::html(format!("404 error. Not found: {}", request.url()))
                        .with_status_code(404)
                }
            }
        });
    });

    util::init::ensure_crossplatform_proper_thread(move || {
        util::init::first_time_open_wiki_release_page();

        let mut system = Box::new(kay::ActorSystem::new(kay::Networking::new(
            0,
            vec![
                arg_matches.value_of("bind-sim").unwrap().to_owned(),
                "ws-client".to_owned(),
            ],
            arg_matches
                .value_of("batch-msg-b")
                .unwrap()
                .parse()
                .unwrap(),
            arg_matches
                .value_of("ok-turn-dist")
                .unwrap()
                .parse()
                .unwrap(),
            arg_matches.value_of("skip-ratio").unwrap().parse().unwrap(),
        )));

        setup_all(&mut system);

        let world = &mut system.world();

        system.networking_connect();

        let simulatables = vec![
            Lane::local_broadcast(world).into(),
            SwitchLane::local_broadcast(world).into(),
            Family::local_broadcast(world).into(),
            GroceryShop::local_broadcast(world).into(),
            GrainFarm::local_broadcast(world).into(),
            CowFarm::local_broadcast(world).into(),
            Mill::local_broadcast(world).into(),
            Bakery::local_broadcast(world).into(),
            NeighboringTownTrade::local_broadcast(world).into(),
            TaskEndScheduler::local_first(world).into(),
            Construction::global_first(world).into(),
        ];
        let simulation = simulation::spawn(world, simulatables);
        util::init::set_error_hook();

        let plan_manager = planning::spawn(world);
        construction::spawn(world);
        transport::spawn(world, simulation);
        economy::spawn(world, simulation, plan_manager);
        system.process_all_messages();

        let mut frame_counter = util::init::FrameCounter::new();
        let mut skip_turns = 0;

        loop {
            frame_counter.start_frame();

            system.process_all_messages();

            if system.shutting_down {
                break;
            }

            if skip_turns == 0 {
                simulation.progress(world);

                system.process_all_messages();
            }

            system.networking_send_and_receive();

            system.process_all_messages();

            if skip_turns > 0 {
                skip_turns -= 1;
            //println!("Skipping! {} left", skip_turns);
            } else {
                let maybe_should_skip = system.networking_finish_turn();
                if let Some(should_skip) = maybe_should_skip {
                    skip_turns = should_skip.min(100);
                }
            }

            //frame_counter.print_fps();
            frame_counter.sleep_if_faster_than(120);
        }
    });
}
<commit_msg>Let's see if CI works now...<commit_after>extern crate citybound_common;
use citybound_common::*;

extern crate rouille;
use rouille::{Response, extension_to_mime};

#[macro_use]
extern crate rust_embed_flag;

#[derive(RustEmbed)]
#[folder = "game_browser/dist/"]
struct Asset;

extern crate clap;
use clap::{Arg, App};

use kay::Actor;
use transport::lane::{Lane, SwitchLane};
use economy::households::family::Family;
use economy::households::grocery_shop::GroceryShop;
use economy::households::grain_farm::GrainFarm;
use economy::households::cow_farm::CowFarm;
use economy::households::mill::Mill;
use economy::households::bakery::Bakery;
use economy::households::neighboring_town_trade::NeighboringTownTrade;
use economy::households::tasks::TaskEndScheduler;
use construction::Construction;

const VERSION: &str = include_str!("../.version");

fn main() {
    let arg_matches = App::new("citybound")
        .version(VERSION.trim())
        .author("ae play (Anselm Eickhoff)")
        .about("The city is us.")
        .arg(
            Arg::with_name("mode")
                .long("mode")
                .value_name("local/lan/internet")
                .display_order(0)
                .possible_values(&["local", "lan", "internet"])
                .default_value("local")
                .help("Where to expose the simulation. Sets defaults other settings."),
        ).arg(
            Arg::with_name("bind")
                .long("bind")
                .value_name("host:port")
                .default_value_ifs(&[
                    ("mode", Some("local"), "localhost:1234"),
                    ("mode", Some("lan"), "0.0.0.0:1234"),
                    ("mode", Some("internet"), "0.0.0.0:1234"),
                ]).help("Address and port to serve the browser UI from"),
        ).arg(
            Arg::with_name("bind-sim")
                .long("bind-sim")
                .value_name("host:port")
                .default_value_ifs(&[
                    ("mode", Some("local"), "localhost:9999"),
                    ("mode", Some("lan"), "0.0.0.0:9999"),
                    ("mode", Some("internet"), "0.0.0.0:9999"),
                ]).help("Address and port to accept connections to the simulation from"),
        ).arg(
            Arg::with_name("batch-msg-b")
                .long("batch-msg-bytes")
                .value_name("n-bytes")
                .default_value("5000")
                .help("How many bytes of simulation messages to batch"),
        ).arg(
            Arg::with_name("ok-turn-dist")
                .long("ok-turn-dist")
                .value_name("n-turns")
                .default_value_ifs(&[
                    ("mode", Some("local"), "2"),
                    ("mode", Some("lan"), "10"),
                    ("mode", Some("internet"), "30"),
                ]).help("How many network turns client/server can be behind before skipping"),
        ).arg(
            Arg::with_name("skip-ratio")
                .long("skip-ratio")
                .value_name("n-turns")
                .default_value("5")
                .help("How many network turns to skip if server/client are ahead"),
        ).get_matches();

    let serve_host_port = arg_matches.value_of("bind").unwrap().to_owned();
    let arg_matches_2 = arg_matches.clone();

    let my_host = format!(
        "{}:{}",
        match arg_matches.value_of("mode").unwrap() {
            "local" => "localhost",
            "lan" => "<your LAN IP>",
            "internet" => "<your public IP>",
            _ => unreachable!(),
        },
        serve_host_port.split(':').nth(1).unwrap(),
    );

    ::std::thread::spawn(move || {
        println!("╭───────────────────────────────────────────╮");
        println!("│ {: ^41} │", format!("Citybound {}", VERSION.trim()));
        println!("│ {: ^41} │", format!("Running at http://{}", my_host));
        println!("╰───────────────────────────────────────────╯");

        rouille::start_server(serve_host_port, move |request| {
            if request.raw_url() == "/" {
                println!("{:?} loaded page", request.remote_addr());

                let template = std::str::from_utf8(
                    &Asset::get("index.html").expect("index.html should exist as asset"),
                ).unwrap()
                .to_owned();

                let rendered = template
                    .replace("CB_VERSION", VERSION.trim())
                    .replace(
                        "CB_BATCH_MESSAGE_BYTES",
                        arg_matches_2.value_of("batch-msg-b").unwrap(),
                    ).replace(
                        "CB_ACCEPTABLE_TURN_DISTANCE",
                        arg_matches_2.value_of("ok-turn-dist").unwrap(),
                    ).replace(
                        "CB_SKIP_TURNS_PER_TURN_AHEAD",
                        arg_matches_2.value_of("skip-ratio").unwrap(),
                    );

                Response::html(rendered)
            } else {
                if let Some(asset) = Asset::get(&request.url()[1..]) {
                    Response::from_data(
                        extension_to_mime(request.url().split('.').last().unwrap_or("")),
                        asset,
                    )
                } else {
                    Response::html(format!("404 error. Not found: {}", request.url()))
                        .with_status_code(404)
                }
            }
        });
    });

    util::init::ensure_crossplatform_proper_thread(move || {
        let mut system = Box::new(kay::ActorSystem::new(kay::Networking::new(
            0,
            vec![
                arg_matches.value_of("bind-sim").unwrap().to_owned(),
                "ws-client".to_owned(),
            ],
            arg_matches
                .value_of("batch-msg-b")
                .unwrap()
                .parse()
                .unwrap(),
            arg_matches
                .value_of("ok-turn-dist")
                .unwrap()
                .parse()
                .unwrap(),
            arg_matches.value_of("skip-ratio").unwrap().parse().unwrap(),
        )));

        setup_all(&mut system);

        let world = &mut system.world();

        system.networking_connect();

        let simulatables = vec![
            Lane::local_broadcast(world).into(),
            SwitchLane::local_broadcast(world).into(),
            Family::local_broadcast(world).into(),
            GroceryShop::local_broadcast(world).into(),
            GrainFarm::local_broadcast(world).into(),
            CowFarm::local_broadcast(world).into(),
            Mill::local_broadcast(world).into(),
            Bakery::local_broadcast(world).into(),
            NeighboringTownTrade::local_broadcast(world).into(),
            TaskEndScheduler::local_first(world).into(),
            Construction::global_first(world).into(),
        ];
        let simulation = simulation::spawn(world, simulatables);
        util::init::set_error_hook();

        let plan_manager = planning::spawn(world);
        construction::spawn(world);
        transport::spawn(world, simulation);
        economy::spawn(world, simulation, plan_manager);
        system.process_all_messages();

        let mut frame_counter = util::init::FrameCounter::new();
        let mut skip_turns = 0;

        loop {
            frame_counter.start_frame();

            system.process_all_messages();

            if system.shutting_down {
                break;
            }

            if skip_turns == 0 {
                simulation.progress(world);

                system.process_all_messages();
            }

            system.networking_send_and_receive();

            system.process_all_messages();

            if skip_turns > 0 {
                skip_turns -= 1;
            //println!("Skipping! {} left", skip_turns);
            } else {
                let maybe_should_skip = system.networking_finish_turn();
                if let Some(should_skip) = maybe_should_skip {
                    skip_turns = should_skip.min(100);
                }
            }

            //frame_counter.print_fps();
            frame_counter.sleep_if_faster_than(120);
        }
    });
}
<|endoftext|>


<commit_before>//! Read configurations files.

#![deny(clippy::missing_docs_in_private_items)]

use lazy_static::lazy_static;
use std::{env, fmt, fs, io, path};
use std::io::Read;
use syntax::{ast, source_map};
use toml;
use std::sync::Mutex;

/// Get the configuration file from arguments.
pub fn file_from_args(
    args: &[source_map::Spanned<ast::NestedMetaItemKind>],
) -> Result<Option<path::PathBuf>, (&'static str, source_map::Span)> {
    for arg in args.iter().filter_map(|a| a.meta_item()) {
        if arg.name() == "conf_file" {
            return match arg.node {
                ast::MetaItemKind::Word | ast::MetaItemKind::List(_) => {
                    Err(("`conf_file` must be a named value", arg.span))
                },
                ast::MetaItemKind::NameValue(ref value) => if let ast::LitKind::Str(ref file, _) = value.node {
                    Ok(Some(file.to_string().into()))
                } else {
                    Err(("`conf_file` value must be a string", value.span))
                },
            };
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// Not valid toml or doesn't fit the expected conf format
    Toml(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref err) => err.fmt(f),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

lazy_static! {
    static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($rust_name: ident, $rust_name_str: expr, $default: expr => $($ty: tt)+),)+) => {
        pub use self::helpers::Conf;
        mod helpers {
            use serde_derive::Deserialize;
            /// Type used to store lint configuration.
            #[derive(Default, Deserialize)]
            #[serde(rename_all="kebab-case", deny_unknown_fields)]
            pub struct Conf {
                $(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)]
                          pub $rust_name: define_Conf!(TY $($ty)+),)+
                #[allow(dead_code)]
                #[serde(default)]
                third_party: Option<::toml::Value>,
            }
            $(
                mod $rust_name {
                    use serde;
                    use serde::Deserialize;
                    crate fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D)
                    -> Result<define_Conf!(TY $($ty)+), D::Error> {
                        type T = define_Conf!(TY $($ty)+);
                        Ok(T::deserialize(deserializer).unwrap_or_else(|e| {
                            crate::utils::conf::ERRORS.lock().expect("no threading here")
                                                        .push(crate::utils::conf::Error::Toml(e.to_string()));
                            super::$rust_name()
                        }))
                    }
                }

                fn $rust_name() -> define_Conf!(TY $($ty)+) {
                    define_Conf!(DEFAULT $($ty)+, $default)
                }
            )+
        }
    };

    // hack to convert tts
    (TY $ty: ty) => { $ty };

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    (blacklisted_names, "blacklisted_names", ["foo", "bar", "baz", "quux"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold", 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    (doc_valid_idents, "doc_valid_idents", [
        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
        "DirectX",
        "ECMAScript",
        "GPLv2", "GPLv3",
        "GitHub", "GitLab",
        "IPv4", "IPv6",
        "JavaScript",
        "NaN", "NaNs",
        "OAuth",
        "OpenGL", "OpenSSH", "OpenSSL", "OpenStreetMap",
        "TrueType",
        "iOS", "macOS",
        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
        "MinGW",
    ] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    (too_many_arguments_threshold, "too_many_arguments_threshold", 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    (type_complexity_threshold, "type_complexity_threshold", 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    (single_char_binding_names_threshold, "single_char_binding_names_threshold", 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    (too_large_for_stack, "too_large_for_stack", 200 => u64),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64),
    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion
    (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64),
    /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
    (verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64),
    /// Lint: DECIMAL_LITERAL_REPRESENTATION. The lower bound for linting decimal literals
    (literal_representation_threshold, "literal_representation_threshold", 16384 => u64),
    /// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
    (trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>),
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];

    let mut current = path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => if e.kind() != io::ErrorKind::NotFound {
                    return Err(e);
                },
                _ => (),
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Produces a `Conf` filled with the default values and forwards the errors
///
/// Used internally for convenience
fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
    (toml::from_str("").expect("we never error on empty config files"), errors)
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
    let path = if let Some(path) = path {
        path
    } else {
        return default(Vec::new());
    };

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                return default(vec![err.into()]);
            }

            buf
        },
        Err(err) => return default(vec![err.into()]),
    };

    assert!(
        ERRORS
            .lock()
            .expect("no threading -> mutex always safe")
            .is_empty()
    );
    match toml::from_str(&file) {
        Ok(toml) => (
            toml,
            ERRORS
                .lock()
                .expect("no threading -> mutex always safe")
                .split_off(0),
        ),
        Err(e) => {
            let mut errors = ERRORS
                .lock()
                .expect("no threading -> mutex always safe")
                .split_off(0);
            errors.push(Error::Toml(e.to_string()));
            default(errors)
        },
    }
}
<commit_msg>Make `Default` do what `default` used to do<commit_after>//! Read configurations files.

#![deny(clippy::missing_docs_in_private_items)]

use lazy_static::lazy_static;
use std::default::Default;
use std::{env, fmt, fs, io, path};
use std::io::Read;
use syntax::{ast, source_map};
use toml;
use std::sync::Mutex;

/// Get the configuration file from arguments.
pub fn file_from_args(
    args: &[source_map::Spanned<ast::NestedMetaItemKind>],
) -> Result<Option<path::PathBuf>, (&'static str, source_map::Span)> {
    for arg in args.iter().filter_map(|a| a.meta_item()) {
        if arg.name() == "conf_file" {
            return match arg.node {
                ast::MetaItemKind::Word | ast::MetaItemKind::List(_) => {
                    Err(("`conf_file` must be a named value", arg.span))
                },
                ast::MetaItemKind::NameValue(ref value) => if let ast::LitKind::Str(ref file, _) = value.node {
                    Ok(Some(file.to_string().into()))
                } else {
                    Err(("`conf_file` value must be a string", value.span))
                },
            };
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// Not valid toml or doesn't fit the expected conf format
    Toml(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref err) => err.fmt(f),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

lazy_static! {
    static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($rust_name: ident, $rust_name_str: expr, $default: expr => $($ty: tt)+),)+) => {
        pub use self::helpers::Conf;
        mod helpers {
            use serde_derive::Deserialize;
            /// Type used to store lint configuration.
            #[derive(Deserialize)]
            #[serde(rename_all="kebab-case", deny_unknown_fields)]
            pub struct Conf {
                $(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)]
                          pub $rust_name: define_Conf!(TY $($ty)+),)+
                #[allow(dead_code)]
                #[serde(default)]
                third_party: Option<::toml::Value>,
            }
            $(
                mod $rust_name {
                    use serde;
                    use serde::Deserialize;
                    crate fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D)
                    -> Result<define_Conf!(TY $($ty)+), D::Error> {
                        type T = define_Conf!(TY $($ty)+);
                        Ok(T::deserialize(deserializer).unwrap_or_else(|e| {
                            crate::utils::conf::ERRORS.lock().expect("no threading here")
                                                        .push(crate::utils::conf::Error::Toml(e.to_string()));
                            super::$rust_name()
                        }))
                    }
                }

                fn $rust_name() -> define_Conf!(TY $($ty)+) {
                    define_Conf!(DEFAULT $($ty)+, $default)
                }
            )+
        }
    };

    // hack to convert tts
    (TY $ty: ty) => { $ty };

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    (blacklisted_names, "blacklisted_names", ["foo", "bar", "baz", "quux"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold", 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    (doc_valid_idents, "doc_valid_idents", [
        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
        "DirectX",
        "ECMAScript",
        "GPLv2", "GPLv3",
        "GitHub", "GitLab",
        "IPv4", "IPv6",
        "JavaScript",
        "NaN", "NaNs",
        "OAuth",
        "OpenGL", "OpenSSH", "OpenSSL", "OpenStreetMap",
        "TrueType",
        "iOS", "macOS",
        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
        "MinGW",
    ] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    (too_many_arguments_threshold, "too_many_arguments_threshold", 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    (type_complexity_threshold, "type_complexity_threshold", 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    (single_char_binding_names_threshold, "single_char_binding_names_threshold", 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    (too_large_for_stack, "too_large_for_stack", 200 => u64),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64),
    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion
    (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64),
    /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
    (verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64),
    /// Lint: DECIMAL_LITERAL_REPRESENTATION. The lower bound for linting decimal literals
    (literal_representation_threshold, "literal_representation_threshold", 16384 => u64),
    /// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
    (trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>),
}

impl Default for Conf {
    fn default() -> Conf {
        toml::from_str("").expect("we never error on empty config files")
    }
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];

    let mut current = path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => if e.kind() != io::ErrorKind::NotFound {
                    return Err(e);
                },
                _ => (),
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Produces a `Conf` filled with the default values and forwards the errors
///
/// Used internally for convenience
fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
    (Conf::default(), errors)
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
    let path = if let Some(path) = path {
        path
    } else {
        return default(Vec::new());
    };

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                return default(vec![err.into()]);
            }

            buf
        },
        Err(err) => return default(vec![err.into()]),
    };

    assert!(
        ERRORS
            .lock()
            .expect("no threading -> mutex always safe")
            .is_empty()
    );
    match toml::from_str(&file) {
        Ok(toml) => (
            toml,
            ERRORS
                .lock()
                .expect("no threading -> mutex always safe")
                .split_off(0),
        ),
        Err(e) => {
            let mut errors = ERRORS
                .lock()
                .expect("no threading -> mutex always safe")
                .split_off(0);
            errors.push(Error::Toml(e.to_string()));
            default(errors)
        },
    }
}
<|endoftext|>


<commit_before>// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54957
// compile-flags: -Zmiri-disable-validation

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Foo {
    A(&'static str),
    _B,
    _C,
}

pub fn main() {
    let mut b = std::collections::BTreeSet::new();
    b.insert(Foo::A("\'"));
    b.insert(Foo::A("/="));
    b.insert(Foo::A("#"));
    b.insert(Foo::A("0o"));
    assert!(b.remove(&Foo::A("/=")));
    assert!(!b.remove(&Foo::A("/=")));
}
<commit_msg>btree is fixed<commit_after>#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Foo {
    A(&'static str),
    _B,
    _C,
}

pub fn main() {
    let mut b = std::collections::BTreeSet::new();
    b.insert(Foo::A("\'"));
    b.insert(Foo::A("/="));
    b.insert(Foo::A("#"));
    b.insert(Foo::A("0o"));
    assert!(b.remove(&Foo::A("/=")));
    assert!(!b.remove(&Foo::A("/=")));
}
<|endoftext|>


<commit_before>use std::cmp::Ord;
use std::cmp::Ordering::{Less, Equal, Greater};

fn chop<T: Ord>(item : T, slice : &[T]) -> i32 {
    let length = slice.len();
    // Catch empty slices
    if length < 1 {
        return -1;
    }

    let mut high = length - 1;
    let mut low = 0;

    while low <= high {
        let mid_index = (high - low) / 2 + low;
        let comparison = item.cmp(&slice[mid_index]);
        match comparison {
            Less => {
                if high == 0 {
                    return -1;
                }
                high = mid_index - 1
            }
            Greater => low = mid_index + 1,
            Equal => return mid_index as i32
        }
    }
    return -1;
}

fn main() {
    println!("{}", chop(3, &[1,3,5]));
}

#[test]
fn test() {
    assert_eq!(-1, chop(3, &[]));
    assert_eq!(-1, chop(3, &[1]));
    assert_eq!(0,  chop(1, &[1]));

    assert_eq!(0,  chop(1, &[1, 3, 5]));
    assert_eq!(1,  chop(3, &[1, 3, 5]));
    assert_eq!(2,  chop(5, &[1, 3, 5]));
    assert_eq!(-1, chop(0, &[1, 3, 5]));
    assert_eq!(-1, chop(2, &[1, 3, 5]));
    assert_eq!(-1, chop(4, &[1, 3, 5]));
    assert_eq!(-1, chop(6, &[1, 3, 5]));

    assert_eq!(0,  chop(1, &[1, 3, 5, 7]));
    assert_eq!(1,  chop(3, &[1, 3, 5, 7]));
    assert_eq!(2,  chop(5, &[1, 3, 5, 7]));
    assert_eq!(3,  chop(7, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(0, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(2, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(4, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(6, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(8, &[1, 3, 5, 7]));
}
<commit_msg>Update Rust chop<commit_after>use std::cmp::Ord;
use std::cmp::Ordering::{Less, Equal, Greater};

fn chop<T: Ord>(item : T, slice : &[T]) -> i32 {
    let length = slice.len();
    // Catch empty slices
    if length < 1 {
        return -1;
    }

    let mut width = length;
    let mut low = 0;

    while width > 0 {
        let mid_index = low + (width / 2);
        let comparison = item.cmp(&slice[mid_index]);
        match comparison {
            Less => (),
            Greater => {
                low = mid_index + 1;
                width -= 1;
            }
            Equal => return mid_index as i32
        }
        width /= 2;
    }
    return -1;
}

fn main() {
    println!("{}", chop(3, &[1,3,5]));
}

#[test]
fn test() {
    assert_eq!(-1, chop(3, &[]));
    assert_eq!(-1, chop(3, &[1]));
    assert_eq!(0,  chop(1, &[1]));

    assert_eq!(0,  chop(1, &[1, 3, 5]));
    assert_eq!(1,  chop(3, &[1, 3, 5]));
    assert_eq!(2,  chop(5, &[1, 3, 5]));
    assert_eq!(-1, chop(0, &[1, 3, 5]));
    assert_eq!(-1, chop(2, &[1, 3, 5]));
    assert_eq!(-1, chop(4, &[1, 3, 5]));
    assert_eq!(-1, chop(6, &[1, 3, 5]));

    assert_eq!(0,  chop(1, &[1, 3, 5, 7]));
    assert_eq!(1,  chop(3, &[1, 3, 5, 7]));
    assert_eq!(2,  chop(5, &[1, 3, 5, 7]));
    assert_eq!(3,  chop(7, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(0, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(2, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(4, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(6, &[1, 3, 5, 7]));
    assert_eq!(-1, chop(8, &[1, 3, 5, 7]));
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A task that sniffs data
use std::comm::{channel, Receiver, Sender, Disconnected};
use std::task::TaskBuilder;
use resource_task::{TargetedLoadResponse};

pub type SnifferTask = Sender<TargetedLoadResponse>;

pub fn new_sniffer_task() -> SnifferTask {
    let(sen, rec) = channel();
    let builder = TaskBuilder::new().named("SnifferManager");
    builder.spawn(proc() {
        SnifferManager::new(rec).start();
    });
    sen
}

struct SnifferManager {
    data_receiver: Receiver<TargetedLoadResponse>,
}

impl SnifferManager {
    fn new(data_receiver: Receiver <TargetedLoadResponse>) -> SnifferManager {
        SnifferManager {
            data_receiver: data_receiver,
        }
    }
}

impl SnifferManager {
    fn start(self) {
        loop {
            match self.data_receiver.try_recv() {
                Ok(snif_data) => {
                    let result = snif_data.consumer.send_opt(snif_data.load_response);
                    if result.is_err() {
                        break;
                    }
                }
                Err(Disconnected) => break,
                Err(_) => (),
            }
        }
    }
}
<commit_msg>auto merge of #4148 : jdm/servo/sniffix, r=glennw<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A task that sniffs data
use std::comm::{channel, Receiver, Sender};
use std::task::TaskBuilder;
use resource_task::{TargetedLoadResponse};

pub type SnifferTask = Sender<TargetedLoadResponse>;

pub fn new_sniffer_task() -> SnifferTask {
    let(sen, rec) = channel();
    let builder = TaskBuilder::new().named("SnifferManager");
    builder.spawn(proc() {
        SnifferManager::new(rec).start();
    });
    sen
}

struct SnifferManager {
    data_receiver: Receiver<TargetedLoadResponse>,
}

impl SnifferManager {
    fn new(data_receiver: Receiver <TargetedLoadResponse>) -> SnifferManager {
        SnifferManager {
            data_receiver: data_receiver,
        }
    }
}

impl SnifferManager {
    fn start(self) {
        loop {
            match self.data_receiver.recv_opt() {
                Ok(snif_data) => {
                    let _ = snif_data.consumer.send_opt(snif_data.load_response);
                }
                Err(_) => break,
            }
        }
    }
}
<|endoftext|>