<commit_before>#![warn(missing_docs)]
#![allow(dead_code)]
#![allow(unused_variables)]

//the following is the crate documentation, if you get missing documentation for crate
//! Tools for dealing with universes (this is a doc comment, and is shown on
//! the crate index page. The ! makes it apply to the parent of the comment,
//! rather than what follows).

//fn main() -> i32 { // cannot be done, RFC: https://github.com/rust-lang/rfcs/issues/1176
fn main() { // main must have this format: https://doc.rust-lang.org/error-index.html#E0211
    println!("Hello, world!");
    println!(
        "Hello, world!"
        );
    println!
        (
        "Hello, world!"
        )
        ;
//bindings:
    let x = 5;//type inference
    let x: i32 = 5;//explicitly state the type; "x is a binding with the type i32 and the value five."
    let (x, y) = (1, 2);//the left hand side of a let expression is a full pattern, not just a variable name.
    let x=6;//allowed
//    x=7;//not! error: re-assignment of immutable variable `x`

    //If you want a binding to be mutable, you can use mut:
    let mut x = 5; // mut x: i32
    x=10;//now allowed
//nice warnings above ^  love this error reporting stuff!

    let x: i32;
//    let y;//won't work
//    excellent error reporting(love it!):
//    println!("The values {} {}",x,x);
//    println!("The values {} {}",x,x,x);
    x=1;
    println!("The value {}",x);
    let y: i32 = 2;
    println!("The values {} {}",x,y);

//if:
    let x = 5;
    if x == 5 {
        println!("x is five!");
    } else {
        println!("x is not five :(");
    }

    let y = if x == 5 {
        10
    } else {
        15
    }; // y: i32

    let y = if x == 5 { 10 } else { 15 }; // y: i32
    // Rust is primarily an expression based language.
    println!("y={}",y);

//    let z=let y=1; yep ridiculous
//    let z=y=1;//works but no idea what it does currently
//    println!("z={}",z);//the trait `core::fmt::String` is not implemented for the type `()`
    //in Rust the value of an assignment is the unit type ()
    //so that's why z=()  because y=1 returns ()

//    let y: i32 = if x == 5 { 10; } else { 15; };//sneaky - without that i32
    let y = if x == 5 { 10; } else { 15; };//sneaky - without that i32 y=() !
    // () is pronounced: unit

//functions:
    print_number(x);
    print_number(101);
    print_sum(1,2);
    print_number(add_one(1));
    deadcodetest1(1);
    deadcodetest2(1);
    foo(1);

//tuples:
    let x = (1, "hello");
    let x: (i32, &str) = (1, "hello");
    let (x,y) = x;//x gets overwritten with 1
    println!("{}",x);
    let (x, y, z) = (4, 2, 3); //destructuring let
    println!("x is {}", x);

    let mut x = (1, 2); // x: (i32, i32)
    let y = (2, 3); // y: (i32, i32)
    x = y;
//    println!("y is {}", y);
    let x = (1, 2, 3);
    let y = (2, 2, 4);

    if x == y {
            println!("yes");
    } else {
            println!("no");
    }

    let (x, y) = next_two(5);
    println!("x, y = {}, {}", x, y);

//structs:
    struct Point {
        x: i32,
        y: i32,
    }

    let origin = Point { x: 0, y: 0 }; // origin: Point
//    origin.x=1;//error: cannot assign to immutable field `origin.x`
    println!("The origin is at ({}, {})", origin.x, origin.y);

    //mutable values in struct
    let mut point = Point { x: 0, y: 0 };
    point.x = 5; //can do
    println!("The point is at ({}, {})", point.x, point.y);

//tuple structs:
    struct Color(i32, i32, i32);
    struct Point2(i32, i32, i32);
    //These two will not be equal, even if they have the same values:
    let black = Color(0, 0, 0);
    let origin = Point2(0, 0, 0);

//newtype:
    struct Inches(i32);
    let length = Inches(10);
    let Inches(integer_length) = length;//destructuring
    println!("length is {} inches", integer_length);
//enum
    enum Ordering {
        Less,
        Equal,
        Greater,
    }

    for x in 0..10 {
        //The upper bound is exclusive, though, so our loop will print 0 through 9, not 10.
        println!("{}", x); // x: i32
    }

    let mut x = 5; // mut x: u32
    let mut done = false; // mut done: bool
    while !done {
        x += x - 3;
        println!("{}", x);
        if x % 5 == 0 { done = true; }
    }

    let mut x = 5;
    loop {
        x += x - 3;
        println!("{}", x);
        if x % 5 == 0 { break; }
    }

//    for x in range(0,10) { //src/main.rs:158:14: 158:19 error: unresolved name `range` [E0425] // XXX: this is also NOT detected by rustc -Z parse-only  the reason is obvious, but if not, see this for explanation: https://github.com/scrooloose/syntastic/commit/a39b397e6ae3b32d2a0497d0f4ddfec0479ad2bb#commitcomment-6652907   It's detected by -Z no-trans
    for x in 0..10 {
        if x % 2 == 0 { continue; }
        println!("{}", x);
    }

    std::process::exit(2);
}//main

fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }

fn deadcodetest1(x: i32) -> i32 {
    if x < 5 {
        return x;
    } else {
        return x + 1;
    }
    x + 2 //warning: unreachable expression, #[warn(unreachable_code)] on by default
}

fn deadcodetest2(x: i32) -> i32 {
    if x < 5 {
        x
    } else {
        x + 1
    }
//    x + 2 //error below if this line isn't commented out
/*
error isn't obvious, but still better than none!

src/main.rs:82:9: 82:10 error: mismatched types:
 expected `()`,
    found `i32`
(expected (),
    found i32)
src/main.rs:82         x
                       ^
src/main.rs:84:9: 84:14 error: mismatched types:
 expected `()`,
    found `i32`
(expected (),
    found i32)
src/main.rs:84         x + 1
                       ^~~~~
*/
}

fn foo(x: i32) -> i32 {
    if x < 5 {
        x
    } else {
        x + 1
    }
//    return 1;
}

fn add_one(x: i32) -> i32 {
    x + 1  // <- note the lack of ; at the end! which would otherwise return () aka unit
}

fn print_number(x: i32) {
    println!("x is: {}", x);
}

#[warn(missing_docs)] //<- no effect on this function, only on main!
fn print_sum(x: i32, y:i32) {
    println!("sum: {}", x+y);
}

#[warn(missing_docs)] //<- no effect on this function, only on main!
/// `hello` is a function that prints a greeting that is personalized based on
/// the name given.
///
/// # Arguments
///
/// * `name` - The name of the person you'd like to greet.
///
/// # Example
///
/// ```rust
/// let name = "Steve";
/// hello(name); // prints "Hello, Steve!"
/// ```
fn hello(name: &str) {
    println!("Hello, {}!", name);
}

<commit_msg>link to doc<commit_after>#![warn(missing_docs)]
#![allow(dead_code)]
#![allow(unused_variables)]

//the following is the crate documentation, if you get missing documentation for crate
//! Tools for dealing with universes (this is a doc comment, and is shown on
//! the crate index page. The ! makes it apply to the parent of the comment,
//! rather than what follows).

//fn main() -> i32 { // cannot be done, RFC: https://github.com/rust-lang/rfcs/issues/1176
fn main() { // main must have this format: https://doc.rust-lang.org/error-index.html#E0211
    println!("Hello, world!");
    println!(
        "Hello, world!"
        );
    println!
        (
        "Hello, world!"
        )
        ;
//bindings:
    let x = 5;//type inference
    let x: i32 = 5;//explicitly state the type; "x is a binding with the type i32 and the value five."
    let (x, y) = (1, 2);//the left hand side of a let expression is a full pattern, not just a variable name.
    let x=6;//allowed
//    x=7;//not! error: re-assignment of immutable variable `x`

    //If you want a binding to be mutable, you can use mut:
    let mut x = 5; // mut x: i32
    x=10;//now allowed
//nice warnings above ^  love this error reporting stuff!

    let x: i32;
//    let y;//won't work
//    excellent error reporting(love it!):
//    println!("The values {} {}",x,x);
//    println!("The values {} {}",x,x,x);
    x=1;
    println!("The value {}",x);
    let y: i32 = 2;
    println!("The values {} {}",x,y);

//if:
    let x = 5;
    if x == 5 {
        println!("x is five!");
    } else {
        println!("x is not five :(");
    }

    let y = if x == 5 {
        10
    } else {
        15
    }; // y: i32

    let y = if x == 5 { 10 } else { 15 }; // y: i32
    // Rust is primarily an expression based language.
    println!("y={}",y);

//    let z=let y=1; yep ridiculous
//    let z=y=1;//works but no idea what it does currently
//    println!("z={}",z);//the trait `core::fmt::String` is not implemented for the type `()`
    //in Rust the value of an assignment is the unit type ()
    //so that's why z=()  because y=1 returns ()

//    let y: i32 = if x == 5 { 10; } else { 15; };//sneaky - without that i32
    let y = if x == 5 { 10; } else { 15; };//sneaky - without that i32 y=() !
    // () is pronounced: unit

//functions:
    print_number(x);
    print_number(101);
    print_sum(1,2);
    print_number(add_one(1));
    deadcodetest1(1);
    deadcodetest2(1);
    foo(1);

//tuples:
    let x = (1, "hello");
    let x: (i32, &str) = (1, "hello");
    let (x,y) = x;//x gets overwritten with 1
    println!("{}",x);
    let (x, y, z) = (4, 2, 3); //destructuring let
    println!("x is {}", x);

    let mut x = (1, 2); // x: (i32, i32)
    let y = (2, 3); // y: (i32, i32)
    x = y;
//    println!("y is {}", y);
    let x = (1, 2, 3);
    let y = (2, 2, 4);

    if x == y {
            println!("yes");
    } else {
            println!("no");
    }

    let (x, y) = next_two(5);
    println!("x, y = {}, {}", x, y);

//structs:
    struct Point {
        x: i32,
        y: i32,
    }

    let origin = Point { x: 0, y: 0 }; // origin: Point
//    origin.x=1;//error: cannot assign to immutable field `origin.x`
    println!("The origin is at ({}, {})", origin.x, origin.y);

    //mutable values in struct
    let mut point = Point { x: 0, y: 0 };
    point.x = 5; //can do
    println!("The point is at ({}, {})", point.x, point.y);

//tuple structs:
    struct Color(i32, i32, i32);
    struct Point2(i32, i32, i32);
    //These two will not be equal, even if they have the same values:
    let black = Color(0, 0, 0);
    let origin = Point2(0, 0, 0);

//newtype:
    struct Inches(i32);
    let length = Inches(10);
    let Inches(integer_length) = length;//destructuring
    println!("length is {} inches", integer_length);
//enum
    enum Ordering {
        Less,
        Equal,
        Greater,
    }

    for x in 0..10 {
        //The upper bound is exclusive, though, so our loop will print 0 through 9, not 10.
        println!("{}", x); // x: i32
    }

    let mut x = 5; // mut x: u32
    let mut done = false; // mut done: bool
    while !done {
        x += x - 3;
        println!("{}", x);
        if x % 5 == 0 { done = true; }
    }

    let mut x = 5;
    loop {
        x += x - 3;
        println!("{}", x);
        if x % 5 == 0 { break; }
    }

//    for x in range(0,10) { //src/main.rs:158:14: 158:19 error: unresolved name `range` [E0425] // XXX: this is also NOT detected by rustc -Z parse-only  the reason is obvious, but if not, see this for explanation: https://github.com/scrooloose/syntastic/commit/a39b397e6ae3b32d2a0497d0f4ddfec0479ad2bb#commitcomment-6652907   It's detected by -Z no-trans
    for x in 0..10 {
        if x % 2 == 0 { continue; }
        println!("{}", x);
    }

    std::process::exit(2);//caveats(doesn't execute Drop): https://doc.rust-lang.org/std/process/fn.exit.html
}//main

fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }

fn deadcodetest1(x: i32) -> i32 {
    if x < 5 {
        return x;
    } else {
        return x + 1;
    }
    x + 2 //warning: unreachable expression, #[warn(unreachable_code)] on by default
}

fn deadcodetest2(x: i32) -> i32 {
    if x < 5 {
        x
    } else {
        x + 1
    }
//    x + 2 //error below if this line isn't commented out
/*
error isn't obvious, but still better than none!

src/main.rs:82:9: 82:10 error: mismatched types:
 expected `()`,
    found `i32`
(expected (),
    found i32)
src/main.rs:82         x
                       ^
src/main.rs:84:9: 84:14 error: mismatched types:
 expected `()`,
    found `i32`
(expected (),
    found i32)
src/main.rs:84         x + 1
                       ^~~~~
*/
}

fn foo(x: i32) -> i32 {
    if x < 5 {
        x
    } else {
        x + 1
    }
//    return 1;
}

fn add_one(x: i32) -> i32 {
    x + 1  // <- note the lack of ; at the end! which would otherwise return () aka unit
}

fn print_number(x: i32) {
    println!("x is: {}", x);
}

#[warn(missing_docs)] //<- no effect on this function, only on main!
fn print_sum(x: i32, y:i32) {
    println!("sum: {}", x+y);
}

#[warn(missing_docs)] //<- no effect on this function, only on main!
/// `hello` is a function that prints a greeting that is personalized based on
/// the name given.
///
/// # Arguments
///
/// * `name` - The name of the person you'd like to greet.
///
/// # Example
///
/// ```rust
/// let name = "Steve";
/// hello(name); // prints "Hello, Steve!"
/// ```
fn hello(name: &str) {
    println!("Hello, {}!", name);
}

<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder};
use std::io::Cursor;

pub struct IPv4Header<'a> {
    raw: &'a mut [u8],
    data: Data,
}

struct Data {
    version: u8,
    header_length: u8,
    total_length: u16,
    protocol: Protocol,
    source: u32,
    destination: u32,
}

#[derive(Debug, PartialEq)]
enum Protocol {
    TCP,
    UDP,
    OTHER,
}

impl<'a> IPv4Header<'a> {
    fn new(raw: &'a mut [u8]) -> IPv4Header<'a> {
        let data = IPv4Header::parse(raw);
        IPv4Header {
            raw: raw,
            data: data,
        }
    }

    fn parse(raw: &[u8]) -> Data {
        Data {
            version: raw[0] >> 4,
            header_length: (raw[0] & 0xf) << 2,
            total_length: BigEndian::read_u16(&raw[2..4]),
            protocol: match raw[9] {
                6 => Protocol::TCP,
                17 => Protocol::UDP,
                _ => Protocol::OTHER
            },
            source: BigEndian::read_u32(&raw[12..16]),
            destination: BigEndian::read_u32(&raw[16..20]),
        }
    }

    fn set_total_length(&mut self, total_length: u16) {
        self.data.total_length = total_length;
        BigEndian::write_u16(&mut self.raw[2..4], total_length);
    }

    fn set_source(&mut self, source: u32) {
        self.data.source = source;
        BigEndian::write_u32(&mut self.raw[12..16], source);
    }

    fn set_destination(&mut self, destination: u32) {
        self.data.destination = destination;
        BigEndian::write_u32(&mut self.raw[16..20], destination);
    }

    fn switch_source_and_destination(&mut self) {
        let source = self.data.source;
        let destination = self.data.destination;
        self.set_source(destination);
        self.set_destination(source);
    }

    fn compute_checksum(&mut self) {
        // reset checksum field
        self.set_checksum(0);

        let j = self.data.header_length as usize / 2;
        let mut sum = (0..j).map(|i| {
            let range = 2*i..2*(i+1);
            BigEndian::read_u16(&self.raw[range]) as u32
        }).sum::<u32>();
        while (sum & !0xffff) != 0 {
            sum = (sum & 0xffff) + (sum >> 16);
        }

        self.set_checksum(!sum as u16);
    }

    fn get_checksum(&mut self) -> u16 {
        BigEndian::read_u16(&self.raw[10..12])
    }

    fn set_checksum(&mut self, checksum: u16) {
        BigEndian::write_u16(&mut self.raw[10..12], checksum);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use byteorder::{BigEndian, WriteBytesExt};

    fn create_header() -> Vec<u8> {
        let mut raw: Vec<u8> = vec![];
        raw.reserve(20);
        raw.write_u8(4u8 << 4 | 5).unwrap(); // version_and_ihl
        raw.write_u8(0).unwrap(); //ToS
        raw.write_u16::<BigEndian>(28).unwrap(); // total length
        raw.write_u32::<BigEndian>(0).unwrap(); // id_flags_fragment_offset
        raw.write_u8(0).unwrap(); // TTL
        raw.write_u8(17).unwrap(); // protocol (UDP)
        raw.write_u16::<BigEndian>(0).unwrap(); // checksum
        raw.write_u32::<BigEndian>(0x12345678).unwrap(); // source address
        raw.write_u32::<BigEndian>(0x42424242).unwrap(); // destination address
        raw
    }

    #[test]
    fn parse_packet_header() {
        let raw = create_header();
        let data = IPv4Header::parse(&raw[..]);
        assert_eq!(4, data.version);
        assert_eq!(20, data.header_length);
        assert_eq!(28, data.total_length);
        assert_eq!(Protocol::UDP, data.protocol);
        assert_eq!(0x12345678, data.source);
        assert_eq!(0x42424242, data.destination);
    }

    #[test]
    fn edit_packet_header() {
        let mut raw = create_header();
        let mut header = IPv4Header::new(&mut raw[..]);

        header.set_source(0x87654321);
        header.set_destination(0x24242424);
        header.set_total_length(42);
        assert_eq!(0x87654321, header.data.source);
        assert_eq!(0x24242424, header.data.destination);
        assert_eq!(42, header.data.total_length);

        // assert that the buffer has been modified
        let raw_source = BigEndian::read_u32(&header.raw[12..16]);
        let raw_destination = BigEndian::read_u32(&header.raw[16..20]);
        let raw_total_length = BigEndian::read_u16(&header.raw[2..4]);
        assert_eq!(0x87654321, raw_source);
        assert_eq!(0x24242424, raw_destination);
        assert_eq!(42, raw_total_length);

        header.switch_source_and_destination();

        assert_eq!(0x24242424, header.data.source);
        assert_eq!(0x87654321, header.data.destination);

        let raw_source = BigEndian::read_u32(&header.raw[12..16]);
        let raw_destination = BigEndian::read_u32(&header.raw[16..20]);
        assert_eq!(0x24242424, raw_source);
        assert_eq!(0x87654321, raw_destination);
    }

    #[test]
    fn compute_checksum() {
        let mut raw = create_header();
        let mut header = IPv4Header::new(&mut raw[..]);

        // set a fake checksum value to assert that it is correctly computed
        header.set_checksum(0x79);

        header.compute_checksum();

        let mut sum = 0x4500u32 + 0x001Cu32 + 0x0000u32 + 0x0000u32 + 0x0011u32
                    + 0x0000u32 + 0x1234u32 + 0x5678u32 + 0x4242u32 + 0x4242u32;
        while (sum & !0xffff) != 0 {
            sum = (sum & 0xffff) + (sum >> 16);
        }
        let sum = !sum as u16;
        assert_eq!(sum, header.get_checksum());
    }
}
<commit_msg>Introduce IPv4Packet<commit_after>use byteorder::{BigEndian, ByteOrder};
use std::io::Cursor;

pub struct IPv4Packet<'a> {
    raw: &'a mut [u8],
    header: IPv4Header<'a>,
}

pub struct IPv4Header<'a> {
    raw: &'a mut [u8],
    data: IPv4HeaderData,
}

struct IPv4HeaderData {
    version: u8,
    header_length: u8,
    total_length: u16,
    protocol: Protocol,
    source: u32,
    destination: u32,
}

#[derive(Debug, PartialEq)]
enum Protocol {
    TCP,
    UDP,
    OTHER,
}

impl<'a> IPv4Packet<'a> {
    fn new(raw: &'a mut [u8]) -> IPv4Packet<'a> {
        let header = IPv4Header::new(raw);
        IPv4Packet {
            raw: raw,
            header: header,
        }
    }
}

impl<'a> IPv4Header<'a> {
    fn new(raw: &'a mut [u8]) -> IPv4Header<'a> {
        let data = IPv4Header::parse(raw);
        IPv4Header {
            raw: raw,
            data: data,
        }
    }

    fn parse(raw: &[u8]) -> IPv4HeaderData {
        IPv4HeaderData {
            version: raw[0] >> 4,
            header_length: (raw[0] & 0xf) << 2,
            total_length: BigEndian::read_u16(&raw[2..4]),
            protocol: match raw[9] {
                6 => Protocol::TCP,
                17 => Protocol::UDP,
                _ => Protocol::OTHER
            },
            source: BigEndian::read_u32(&raw[12..16]),
            destination: BigEndian::read_u32(&raw[16..20]),
        }
    }

    fn set_total_length(&mut self, total_length: u16) {
        self.data.total_length = total_length;
        BigEndian::write_u16(&mut self.raw[2..4], total_length);
    }

    fn set_source(&mut self, source: u32) {
        self.data.source = source;
        BigEndian::write_u32(&mut self.raw[12..16], source);
    }

    fn set_destination(&mut self, destination: u32) {
        self.data.destination = destination;
        BigEndian::write_u32(&mut self.raw[16..20], destination);
    }

    fn switch_source_and_destination(&mut self) {
        let source = self.data.source;
        let destination = self.data.destination;
        self.set_source(destination);
        self.set_destination(source);
    }

    fn compute_checksum(&mut self) {
        // reset checksum field
        self.set_checksum(0);

        let j = self.data.header_length as usize / 2;
        let mut sum = (0..j).map(|i| {
            let range = 2*i..2*(i+1);
            BigEndian::read_u16(&self.raw[range]) as u32
        }).sum::<u32>();
        while (sum & !0xffff) != 0 {
            sum = (sum & 0xffff) + (sum >> 16);
        }

        self.set_checksum(!sum as u16);
    }

    fn get_checksum(&mut self) -> u16 {
        BigEndian::read_u16(&self.raw[10..12])
    }

    fn set_checksum(&mut self, checksum: u16) {
        BigEndian::write_u16(&mut self.raw[10..12], checksum);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use byteorder::{BigEndian, WriteBytesExt};

    fn create_header() -> Vec<u8> {
        let mut raw: Vec<u8> = vec![];
        raw.reserve(20);
        raw.write_u8(4u8 << 4 | 5).unwrap(); // version_and_ihl
        raw.write_u8(0).unwrap(); //ToS
        raw.write_u16::<BigEndian>(28).unwrap(); // total length
        raw.write_u32::<BigEndian>(0).unwrap(); // id_flags_fragment_offset
        raw.write_u8(0).unwrap(); // TTL
        raw.write_u8(17).unwrap(); // protocol (UDP)
        raw.write_u16::<BigEndian>(0).unwrap(); // checksum
        raw.write_u32::<BigEndian>(0x12345678).unwrap(); // source address
        raw.write_u32::<BigEndian>(0x42424242).unwrap(); // destination address
        raw
    }

    #[test]
    fn parse_packet_header() {
        let raw = create_header();
        let data = IPv4Header::parse(&raw[..]);
        assert_eq!(4, data.version);
        assert_eq!(20, data.header_length);
        assert_eq!(28, data.total_length);
        assert_eq!(Protocol::UDP, data.protocol);
        assert_eq!(0x12345678, data.source);
        assert_eq!(0x42424242, data.destination);
    }

    #[test]
    fn edit_packet_header() {
        let mut raw = create_header();
        let mut header = IPv4Header::new(&mut raw[..]);

        header.set_source(0x87654321);
        header.set_destination(0x24242424);
        header.set_total_length(42);
        assert_eq!(0x87654321, header.data.source);
        assert_eq!(0x24242424, header.data.destination);
        assert_eq!(42, header.data.total_length);

        // assert that the buffer has been modified
        let raw_source = BigEndian::read_u32(&header.raw[12..16]);
        let raw_destination = BigEndian::read_u32(&header.raw[16..20]);
        let raw_total_length = BigEndian::read_u16(&header.raw[2..4]);
        assert_eq!(0x87654321, raw_source);
        assert_eq!(0x24242424, raw_destination);
        assert_eq!(42, raw_total_length);

        header.switch_source_and_destination();

        assert_eq!(0x24242424, header.data.source);
        assert_eq!(0x87654321, header.data.destination);

        let raw_source = BigEndian::read_u32(&header.raw[12..16]);
        let raw_destination = BigEndian::read_u32(&header.raw[16..20]);
        assert_eq!(0x24242424, raw_source);
        assert_eq!(0x87654321, raw_destination);
    }

    #[test]
    fn compute_checksum() {
        let mut raw = create_header();
        let mut header = IPv4Header::new(&mut raw[..]);

        // set a fake checksum value to assert that it is correctly computed
        header.set_checksum(0x79);

        header.compute_checksum();

        let mut sum = 0x4500u32 + 0x001Cu32 + 0x0000u32 + 0x0000u32 + 0x0011u32
                    + 0x0000u32 + 0x1234u32 + 0x5678u32 + 0x4242u32 + 0x4242u32;
        while (sum & !0xffff) != 0 {
            sum = (sum & 0xffff) + (sum >> 16);
        }
        let sum = !sum as u16;
        assert_eq!(sum, header.get_checksum());
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate parser_combinators as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Parser, State, Stream, ParseResult};
use pc::combinator::{between, many, many1, optional, parser, sep_by, unexpected, With, ParserExt};
use pc::char::{any_char, char, digit, satisfy, spaces, Spaces, string};

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>)
}

fn lex<'a, P>(p: P) -> With<Spaces<P::Input>, P>
    where P: Parser
        , P::Input: Stream<Item=char> {
    spaces().with(p)
}
struct Json<I>(::std::marker::PhantomData<fn (I) -> I>);

impl <I> Json<I>
    where I: Stream<Item=char> {

    fn integer(input: State<I>) -> ParseResult<i64, I> {
        let (s, input) = try!(many1::<String, _>(digit())
            .expected("integer")
            .parse_state(input));
        let mut n = 0;
        for c in s.chars() {
            n = n * 10 + (c as i64 - '0' as i64);
        }
        Ok((n, input))
    }

    fn number(input: State<I>) -> ParseResult<f64, I> {
        let i = char('0').map(|_| 0.0)
                 .or(parser(Json::<I>::integer).map(|x| x as f64));
        let fractional = many(digit())
            .map(|digits: String| {
                let mut magnitude = 1.0;
                digits.chars().fold(0.0, |acc, d| {
                    magnitude /= 10.0;
                    match d.to_digit(10) {
                        Some(d) => acc + (d as f64) * magnitude,
                        None => panic!("Not a digit")
                    }
                })
            });

        let exp = satisfy(|c| c == 'e' || c == 'E')
            .with(optional(char('-')).and(parser(Json::<I>::integer)));
        optional(char('-'))
            .and(i)
            .map(|(sign, n)| if sign.is_some() { -n } else { n })
            .and(optional(char('.')).with(fractional))
            .map(|(x, y)| if x > 0.0 { x + y } else { x - y })
            .and(optional(exp))
            .map(|(n, exp_option)| {
                match exp_option {
                    Some((sign, e)) => {
                        let e = if sign.is_some() { -e } else { e };
                        n * 10.0f64.powi(e as i32)
                    }
                    None => n
                }
            })
        .parse_state(input)
    }

    fn char(input: State<I>) -> ParseResult<char, I> {
        let (c, input) = try!(any_char().parse_state(input));
        let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().find(|x| *x == c).is_some()).map(|c| {
            match c {
                '"' => '"',
                '\\' => '\\',
                '/' => '/',
                'b' => '\u{0008}',
                'f' => '\u{000c}',
                'n' => '\n',
                'r' => '\r',
                't' => '\t',
                c => c//Should never happen
            }
        });
        match c {
            '\\' => input.combine(|input| back_slash_char.parse_state(input)),
            '"'  => unexpected("\"").parse_state(input.into_inner()).map(|_| unreachable!()),
            _    => Ok((c, input))
        }
    }
    fn string(input: State<I>) -> ParseResult<String, I> {
        between(char('"'), char('"'), many(parser(Json::<I>::char)))
            .parse_state(input)
    }
    fn object(input: State<I>) -> ParseResult<Value, I> {
        let field = (lex(parser(Json::<I>::string)), lex(char(':')), lex(parser(Json::<I>::value)))
            .map(|t| (t.0, t.1);
        let fields = sep_by(field, char(','));
        between(char('{'), lex(char('}')), fields)
            .map(Value::Object)
            .parse_state(input)
    }

    #[allow(unconditional_recursion)]
    fn value(input: State<I>) -> ParseResult<Value, I>
        where I: Stream<Item=char> {
        let array = between(lex(char('[')), lex(char(']')), sep_by(parser(Json::<I>::value), char(',')))
            .map(Value::Array);

        //Wrap a few of the value parsers to workaround the slow compiletimes
        fn rest<I>(input: State<I>) -> ParseResult<Value, I>
            where I: Stream<Item=char> {
            string("false").map(|_| Value::Bool(false))
                .or(string("true").map(|_| Value::Bool(true)))
                .or(string("null").map(|_| Value::Null))
                .parse_state(input)
        }
        lex(parser(Json::<I>::string).map(Value::String)
            .or(parser(Json::<I>::object))
            .or(array)
            .or(parser(Json::<I>::number).map(Value::Number))
            .or(parser(rest))
        )
            .parse_state(input)
    }

}

#[test]
fn json_test() {
    use self::Value::*;
    let input =
r#"
{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = parser(Json::value)
        .parse(input);
    let expected = Object(vec![
        ("array", Array(vec![Number(1.0), String("".to_string())])),
        ("object", Object(HashMap::new())),
        ("number", Number(3.14)),
        ("int", Number(-100.)),
        ("exp", Number(-1e2)),
        ("exp_neg", Number(23E-2)),
        ("true", Bool(true)),
        ("false", Bool(false)),
        ("null", Null)
    ].into_iter().map(|(k, v)| (k.to_string(), v)).collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = parser(Json::value);
    match parser.parse(&data[..]) {
        Ok((Value::Array(_), "\r\n")) => (),
        Ok(x) => { println!("{:?}", x); assert!(false); }
        Err(err) => { println!("{}", err); assert!(false); }
    }
    bencher.iter(|| {
        let result = parser.parse(&data);
        ::test::black_box(result)
    });
}
<commit_msg>Fix compilation of benches/json.rs<commit_after>#![feature(test)]
extern crate parser_combinators as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Parser, State, Stream, ParseResult};
use pc::combinator::{between, many, many1, optional, parser, sep_by, unexpected, With, ParserExt};
use pc::char::{any_char, char, digit, satisfy, spaces, Spaces, string};

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>)
}

fn lex<'a, P>(p: P) -> With<Spaces<P::Input>, P>
    where P: Parser
        , P::Input: Stream<Item=char> {
    spaces().with(p)
}
struct Json<I>(::std::marker::PhantomData<fn (I) -> I>);

impl <I> Json<I>
    where I: Stream<Item=char> {

    fn integer(input: State<I>) -> ParseResult<i64, I> {
        let (s, input) = try!(many1::<String, _>(digit())
            .expected("integer")
            .parse_state(input));
        let mut n = 0;
        for c in s.chars() {
            n = n * 10 + (c as i64 - '0' as i64);
        }
        Ok((n, input))
    }

    fn number(input: State<I>) -> ParseResult<f64, I> {
        let i = char('0').map(|_| 0.0)
                 .or(parser(Json::<I>::integer).map(|x| x as f64));
        let fractional = many(digit())
            .map(|digits: String| {
                let mut magnitude = 1.0;
                digits.chars().fold(0.0, |acc, d| {
                    magnitude /= 10.0;
                    match d.to_digit(10) {
                        Some(d) => acc + (d as f64) * magnitude,
                        None => panic!("Not a digit")
                    }
                })
            });

        let exp = satisfy(|c| c == 'e' || c == 'E')
            .with(optional(char('-')).and(parser(Json::<I>::integer)));
        optional(char('-'))
            .and(i)
            .map(|(sign, n)| if sign.is_some() { -n } else { n })
            .and(optional(char('.')).with(fractional))
            .map(|(x, y)| if x > 0.0 { x + y } else { x - y })
            .and(optional(exp))
            .map(|(n, exp_option)| {
                match exp_option {
                    Some((sign, e)) => {
                        let e = if sign.is_some() { -e } else { e };
                        n * 10.0f64.powi(e as i32)
                    }
                    None => n
                }
            })
        .parse_state(input)
    }

    fn char(input: State<I>) -> ParseResult<char, I> {
        let (c, input) = try!(any_char().parse_state(input));
        let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().find(|x| *x == c).is_some()).map(|c| {
            match c {
                '"' => '"',
                '\\' => '\\',
                '/' => '/',
                'b' => '\u{0008}',
                'f' => '\u{000c}',
                'n' => '\n',
                'r' => '\r',
                't' => '\t',
                c => c//Should never happen
            }
        });
        match c {
            '\\' => input.combine(|input| back_slash_char.parse_state(input)),
            '"'  => unexpected("\"").parse_state(input.into_inner()).map(|_| unreachable!()),
            _    => Ok((c, input))
        }
    }
    fn string(input: State<I>) -> ParseResult<String, I> {
        between(char('"'), char('"'), many(parser(Json::<I>::char)))
            .parse_state(input)
    }
    fn object(input: State<I>) -> ParseResult<Value, I> {
        let field = (lex(parser(Json::<I>::string)), lex(char(':')), lex(parser(Json::<I>::value)))
            .map(|t| (t.0, t.2));
        let fields = sep_by(field, char(','));
        between(char('{'), lex(char('}')), fields)
            .map(Value::Object)
            .parse_state(input)
    }

    #[allow(unconditional_recursion)]
    fn value(input: State<I>) -> ParseResult<Value, I>
        where I: Stream<Item=char> {
        let array = between(lex(char('[')), lex(char(']')), sep_by(parser(Json::<I>::value), char(',')))
            .map(Value::Array);

        //Wrap a few of the value parsers to workaround the slow compiletimes
        fn rest<I>(input: State<I>) -> ParseResult<Value, I>
            where I: Stream<Item=char> {
            string("false").map(|_| Value::Bool(false))
                .or(string("true").map(|_| Value::Bool(true)))
                .or(string("null").map(|_| Value::Null))
                .parse_state(input)
        }
        lex(parser(Json::<I>::string).map(Value::String)
            .or(parser(Json::<I>::object))
            .or(array)
            .or(parser(Json::<I>::number).map(Value::Number))
            .or(parser(rest))
        )
            .parse_state(input)
    }

}

#[test]
fn json_test() {
    use self::Value::*;
    let input =
r#"
{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = parser(Json::value)
        .parse(input);
    let expected = Object(vec![
        ("array", Array(vec![Number(1.0), String("".to_string())])),
        ("object", Object(HashMap::new())),
        ("number", Number(3.14)),
        ("int", Number(-100.)),
        ("exp", Number(-1e2)),
        ("exp_neg", Number(23E-2)),
        ("true", Bool(true)),
        ("false", Bool(false)),
        ("null", Null)
    ].into_iter().map(|(k, v)| (k.to_string(), v)).collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = parser(Json::value);
    match parser.parse(&data[..]) {
        Ok((Value::Array(_), "\r\n")) => (),
        Ok(x) => { println!("{:?}", x); assert!(false); }
        Err(err) => { println!("{}", err); assert!(false); }
    }
    bencher.iter(|| {
        let result = parser.parse(&data);
        ::test::black_box(result)
    });
}
<|endoftext|>


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

use test_utils::tested_by;
use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
use ra_syntax::{
    AstNode, SourceFile, AstPtr, TreeArc,
    ast::{self, NameOwner, AttrsOwner},
};

use crate::{
    DefDatabase, Name, AsName, Path, HirFileId, ModuleSource,
    ids::{SourceFileItemId, SourceFileItems},
};

#[derive(Debug, Default, PartialEq, Eq)]
pub struct RawItems {
    modules: Arena<Module, ModuleData>,
    imports: Arena<ImportId, ImportData>,
    defs: Arena<Def, DefData>,
    macros: Arena<Macro, MacroData>,
    /// items for top-level module
    items: Vec<RawItem>,
}

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ImportSourceMap {
    map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
}

impl ImportSourceMap {
    pub(crate) fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
        self.map.insert(import, AstPtr::new(segment))
    }

    pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
        let file = match source {
            ModuleSource::SourceFile(file) => &*file,
            ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
        };

        self.map[import].to_node(file).to_owned()
    }
}

impl RawItems {
    pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<RawItems> {
        db.raw_items_with_source_map(file_id).0
    }

    pub(crate) fn raw_items_with_source_map_query(
        db: &impl DefDatabase,
        file_id: HirFileId,
    ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
        let mut collector = RawItemsCollector {
            raw_items: RawItems::default(),
            source_file_items: db.file_items(file_id.into()),
            source_map: ImportSourceMap::default(),
        };
        let source_file = db.hir_parse(file_id);
        collector.process_module(None, &*source_file);
        (Arc::new(collector.raw_items), Arc::new(collector.source_map))
    }

    pub(crate) fn items(&self) -> &[RawItem] {
        &self.items
    }
}

impl Index<Module> for RawItems {
    type Output = ModuleData;
    fn index(&self, idx: Module) -> &ModuleData {
        &self.modules[idx]
    }
}

impl Index<ImportId> for RawItems {
    type Output = ImportData;
    fn index(&self, idx: ImportId) -> &ImportData {
        &self.imports[idx]
    }
}

impl Index<Def> for RawItems {
    type Output = DefData;
    fn index(&self, idx: Def) -> &DefData {
        &self.defs[idx]
    }
}

impl Index<Macro> for RawItems {
    type Output = MacroData;
    fn index(&self, idx: Macro) -> &MacroData {
        &self.macros[idx]
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub(crate) enum RawItem {
    Module(Module),
    Import(ImportId),
    Def(Def),
    Macro(Macro),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct Module(RawId);
impl_arena_id!(Module);

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum ModuleData {
    Declaration { name: Name, source_item_id: SourceFileItemId },
    Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ImportId(RawId);
impl_arena_id!(ImportId);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImportData {
    pub(crate) path: Path,
    pub(crate) alias: Option<Name>,
    pub(crate) is_glob: bool,
    pub(crate) is_prelude: bool,
    pub(crate) is_extern_crate: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct Def(RawId);
impl_arena_id!(Def);

#[derive(Debug, PartialEq, Eq)]
pub(crate) struct DefData {
    pub(crate) source_item_id: SourceFileItemId,
    pub(crate) name: Name,
    pub(crate) kind: DefKind,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub(crate) enum DefKind {
    Function,
    Struct,
    Enum,
    Const,
    Static,
    Trait,
    TypeAlias,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct Macro(RawId);
impl_arena_id!(Macro);

#[derive(Debug, PartialEq, Eq)]
pub(crate) struct MacroData {
    pub(crate) source_item_id: SourceFileItemId,
    pub(crate) path: Path,
    pub(crate) name: Option<Name>,
    pub(crate) export: bool,
}

struct RawItemsCollector {
    raw_items: RawItems,
    source_file_items: Arc<SourceFileItems>,
    source_map: ImportSourceMap,
}

impl RawItemsCollector {
    fn process_module(&mut self, current_module: Option<Module>, body: &impl ast::ModuleItemOwner) {
        for item_or_macro in body.items_with_macros() {
            match item_or_macro {
                ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
                ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
            }
        }
    }

    fn add_item(&mut self, current_module: Option<Module>, item: &ast::ModuleItem) {
        let (kind, name) = match item.kind() {
            ast::ModuleItemKind::Module(module) => {
                self.add_module(current_module, module);
                return;
            }
            ast::ModuleItemKind::UseItem(use_item) => {
                self.add_use_item(current_module, use_item);
                return;
            }
            ast::ModuleItemKind::ExternCrateItem(extern_crate) => {
                self.add_extern_crate_item(current_module, extern_crate);
                return;
            }
            ast::ModuleItemKind::ImplBlock(_) => {
                // impls don't participate in name resolution
                return;
            }
            ast::ModuleItemKind::StructDef(it) => (DefKind::Struct, it.name()),
            ast::ModuleItemKind::EnumDef(it) => (DefKind::Enum, it.name()),
            ast::ModuleItemKind::FnDef(it) => (DefKind::Function, it.name()),
            ast::ModuleItemKind::TraitDef(it) => (DefKind::Trait, it.name()),
            ast::ModuleItemKind::TypeAliasDef(it) => (DefKind::TypeAlias, it.name()),
            ast::ModuleItemKind::ConstDef(it) => (DefKind::Const, it.name()),
            ast::ModuleItemKind::StaticDef(it) => (DefKind::Static, it.name()),
        };
        if let Some(name) = name {
            let name = name.as_name();
            let source_item_id = self.source_file_items.id_of_unchecked(item.syntax());
            let def = self.raw_items.defs.alloc(DefData { name, kind, source_item_id });
            self.push_item(current_module, RawItem::Def(def))
        }
    }

    fn add_module(&mut self, current_module: Option<Module>, module: &ast::Module) {
        let name = match module.name() {
            Some(it) => it.as_name(),
            None => return,
        };
        let source_item_id = self.source_file_items.id_of_unchecked(module.syntax());
        if module.has_semi() {
            let item =
                self.raw_items.modules.alloc(ModuleData::Declaration { name, source_item_id });
            self.push_item(current_module, RawItem::Module(item));
            return;
        }

        if let Some(item_list) = module.item_list() {
            let item = self.raw_items.modules.alloc(ModuleData::Definition {
                name,
                source_item_id,
                items: Vec::new(),
            });
            self.process_module(Some(item), item_list);
            self.push_item(current_module, RawItem::Module(item));
            return;
        }
        tested_by!(name_res_works_for_broken_modules);
    }

    fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) {
        let is_prelude = use_item.has_atom_attr("prelude_import");

        Path::expand_use_item(use_item, |path, segment, alias| {
            let import = self.raw_items.imports.alloc(ImportData {
                path,
                alias,
                is_glob: segment.is_none(),
                is_prelude,
                is_extern_crate: false,
            });
            if let Some(segment) = segment {
                self.source_map.insert(import, segment)
            }
            self.push_item(current_module, RawItem::Import(import))
        })
    }

    fn add_extern_crate_item(
        &mut self,
        current_module: Option<Module>,
        extern_crate: &ast::ExternCrateItem,
    ) {
        if let Some(name_ref) = extern_crate.name_ref() {
            let path = Path::from_name_ref(name_ref);
            let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name);
            let import = self.raw_items.imports.alloc(ImportData {
                path,
                alias,
                is_glob: false,
                is_prelude: false,
                is_extern_crate: true,
            });
            self.push_item(current_module, RawItem::Import(import))
        }
    }

    fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
        let path = match m.path().and_then(Path::from_ast) {
            Some(it) => it,
            _ => return,
        };

        let name = m.name().map(|it| it.as_name());
        let source_item_id = self.source_file_items.id_of_unchecked(m.syntax());
        let export = m.has_atom_attr("macro_export");
        let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, name, export });
        self.push_item(current_module, RawItem::Macro(m));
    }

    fn push_item(&mut self, current_module: Option<Module>, item: RawItem) {
        match current_module {
            Some(module) => match &mut self.raw_items.modules[module] {
                ModuleData::Definition { items, .. } => items,
                ModuleData::Declaration { .. } => unreachable!(),
            },
            None => &mut self.raw_items.items,
        }
        .push(item)
    }
}
<commit_msg>reduce visibility<commit_after>use std::{
    sync::Arc,
    ops::Index,
};

use test_utils::tested_by;
use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
use ra_syntax::{
    AstNode, SourceFile, AstPtr, TreeArc,
    ast::{self, NameOwner, AttrsOwner},
};

use crate::{
    DefDatabase, Name, AsName, Path, HirFileId, ModuleSource,
    ids::{SourceFileItemId, SourceFileItems},
};

/// `RawItems` is a set of top-level items in a file (except for impls).
///
/// It is the input to name resolution algorithm. `RawItems` are not invalidated
/// on most edits.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct RawItems {
    modules: Arena<Module, ModuleData>,
    imports: Arena<ImportId, ImportData>,
    defs: Arena<Def, DefData>,
    macros: Arena<Macro, MacroData>,
    /// items for top-level module
    items: Vec<RawItem>,
}

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ImportSourceMap {
    map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
}

impl ImportSourceMap {
    fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
        self.map.insert(import, AstPtr::new(segment))
    }

    pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
        let file = match source {
            ModuleSource::SourceFile(file) => &*file,
            ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
        };

        self.map[import].to_node(file).to_owned()
    }
}

impl RawItems {
    pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<RawItems> {
        db.raw_items_with_source_map(file_id).0
    }

    pub(crate) fn raw_items_with_source_map_query(
        db: &impl DefDatabase,
        file_id: HirFileId,
    ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
        let mut collector = RawItemsCollector {
            raw_items: RawItems::default(),
            source_file_items: db.file_items(file_id.into()),
            source_map: ImportSourceMap::default(),
        };
        let source_file = db.hir_parse(file_id);
        collector.process_module(None, &*source_file);
        (Arc::new(collector.raw_items), Arc::new(collector.source_map))
    }

    pub(super) fn items(&self) -> &[RawItem] {
        &self.items
    }
}

impl Index<Module> for RawItems {
    type Output = ModuleData;
    fn index(&self, idx: Module) -> &ModuleData {
        &self.modules[idx]
    }
}

impl Index<ImportId> for RawItems {
    type Output = ImportData;
    fn index(&self, idx: ImportId) -> &ImportData {
        &self.imports[idx]
    }
}

impl Index<Def> for RawItems {
    type Output = DefData;
    fn index(&self, idx: Def) -> &DefData {
        &self.defs[idx]
    }
}

impl Index<Macro> for RawItems {
    type Output = MacroData;
    fn index(&self, idx: Macro) -> &MacroData {
        &self.macros[idx]
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub(super) enum RawItem {
    Module(Module),
    Import(ImportId),
    Def(Def),
    Macro(Macro),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(super) struct Module(RawId);
impl_arena_id!(Module);

#[derive(Debug, PartialEq, Eq)]
pub(super) enum ModuleData {
    Declaration { name: Name, source_item_id: SourceFileItemId },
    Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ImportId(RawId);
impl_arena_id!(ImportId);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImportData {
    pub(super) path: Path,
    pub(super) alias: Option<Name>,
    pub(super) is_glob: bool,
    pub(super) is_prelude: bool,
    pub(super) is_extern_crate: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(super) struct Def(RawId);
impl_arena_id!(Def);

#[derive(Debug, PartialEq, Eq)]
pub(super) struct DefData {
    pub(super) source_item_id: SourceFileItemId,
    pub(super) name: Name,
    pub(super) kind: DefKind,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub(super) enum DefKind {
    Function,
    Struct,
    Enum,
    Const,
    Static,
    Trait,
    TypeAlias,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(super) struct Macro(RawId);
impl_arena_id!(Macro);

#[derive(Debug, PartialEq, Eq)]
pub(super) struct MacroData {
    pub(super) source_item_id: SourceFileItemId,
    pub(super) path: Path,
    pub(super) name: Option<Name>,
    pub(super) export: bool,
}

struct RawItemsCollector {
    raw_items: RawItems,
    source_file_items: Arc<SourceFileItems>,
    source_map: ImportSourceMap,
}

impl RawItemsCollector {
    fn process_module(&mut self, current_module: Option<Module>, body: &impl ast::ModuleItemOwner) {
        for item_or_macro in body.items_with_macros() {
            match item_or_macro {
                ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
                ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
            }
        }
    }

    fn add_item(&mut self, current_module: Option<Module>, item: &ast::ModuleItem) {
        let (kind, name) = match item.kind() {
            ast::ModuleItemKind::Module(module) => {
                self.add_module(current_module, module);
                return;
            }
            ast::ModuleItemKind::UseItem(use_item) => {
                self.add_use_item(current_module, use_item);
                return;
            }
            ast::ModuleItemKind::ExternCrateItem(extern_crate) => {
                self.add_extern_crate_item(current_module, extern_crate);
                return;
            }
            ast::ModuleItemKind::ImplBlock(_) => {
                // impls don't participate in name resolution
                return;
            }
            ast::ModuleItemKind::StructDef(it) => (DefKind::Struct, it.name()),
            ast::ModuleItemKind::EnumDef(it) => (DefKind::Enum, it.name()),
            ast::ModuleItemKind::FnDef(it) => (DefKind::Function, it.name()),
            ast::ModuleItemKind::TraitDef(it) => (DefKind::Trait, it.name()),
            ast::ModuleItemKind::TypeAliasDef(it) => (DefKind::TypeAlias, it.name()),
            ast::ModuleItemKind::ConstDef(it) => (DefKind::Const, it.name()),
            ast::ModuleItemKind::StaticDef(it) => (DefKind::Static, it.name()),
        };
        if let Some(name) = name {
            let name = name.as_name();
            let source_item_id = self.source_file_items.id_of_unchecked(item.syntax());
            let def = self.raw_items.defs.alloc(DefData { name, kind, source_item_id });
            self.push_item(current_module, RawItem::Def(def))
        }
    }

    fn add_module(&mut self, current_module: Option<Module>, module: &ast::Module) {
        let name = match module.name() {
            Some(it) => it.as_name(),
            None => return,
        };
        let source_item_id = self.source_file_items.id_of_unchecked(module.syntax());
        if module.has_semi() {
            let item =
                self.raw_items.modules.alloc(ModuleData::Declaration { name, source_item_id });
            self.push_item(current_module, RawItem::Module(item));
            return;
        }

        if let Some(item_list) = module.item_list() {
            let item = self.raw_items.modules.alloc(ModuleData::Definition {
                name,
                source_item_id,
                items: Vec::new(),
            });
            self.process_module(Some(item), item_list);
            self.push_item(current_module, RawItem::Module(item));
            return;
        }
        tested_by!(name_res_works_for_broken_modules);
    }

    fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) {
        let is_prelude = use_item.has_atom_attr("prelude_import");

        Path::expand_use_item(use_item, |path, segment, alias| {
            let import = self.raw_items.imports.alloc(ImportData {
                path,
                alias,
                is_glob: segment.is_none(),
                is_prelude,
                is_extern_crate: false,
            });
            if let Some(segment) = segment {
                self.source_map.insert(import, segment)
            }
            self.push_item(current_module, RawItem::Import(import))
        })
    }

    fn add_extern_crate_item(
        &mut self,
        current_module: Option<Module>,
        extern_crate: &ast::ExternCrateItem,
    ) {
        if let Some(name_ref) = extern_crate.name_ref() {
            let path = Path::from_name_ref(name_ref);
            let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name);
            let import = self.raw_items.imports.alloc(ImportData {
                path,
                alias,
                is_glob: false,
                is_prelude: false,
                is_extern_crate: true,
            });
            self.push_item(current_module, RawItem::Import(import))
        }
    }

    fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
        let path = match m.path().and_then(Path::from_ast) {
            Some(it) => it,
            _ => return,
        };

        let name = m.name().map(|it| it.as_name());
        let source_item_id = self.source_file_items.id_of_unchecked(m.syntax());
        let export = m.has_atom_attr("macro_export");
        let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, name, export });
        self.push_item(current_module, RawItem::Macro(m));
    }

    fn push_item(&mut self, current_module: Option<Module>, item: RawItem) {
        match current_module {
            Some(module) => match &mut self.raw_items.modules[module] {
                ModuleData::Definition { items, .. } => items,
                ModuleData::Declaration { .. } => unreachable!(),
            },
            None => &mut self.raw_items.items,
        }
        .push(item)
    }
}
<|endoftext|>


<commit_before>use languageserver_types::{
    Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
    TextDocumentItem, TextDocumentPositionParams, TextEdit, Url, VersionedTextDocumentIdentifier,
};
use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit};
use ra_editor::{AtomEdit, Edit, LineCol, LineIndex};
use ra_syntax::{SyntaxKind, TextRange, TextUnit};

use crate::{req, server_world::ServerWorld, Result};

pub trait Conv {
    type Output;
    fn conv(self) -> Self::Output;
}

pub trait ConvWith {
    type Ctx;
    type Output;
    fn conv_with(self, ctx: &Self::Ctx) -> Self::Output;
}

pub trait TryConvWith {
    type Ctx;
    type Output;
    fn try_conv_with(self, ctx: &Self::Ctx) -> Result<Self::Output>;
}

impl Conv for SyntaxKind {
    type Output = SymbolKind;

    fn conv(self) -> <Self as Conv>::Output {
        match self {
            SyntaxKind::FN_DEF => SymbolKind::Function,
            SyntaxKind::STRUCT_DEF => SymbolKind::Struct,
            SyntaxKind::ENUM_DEF => SymbolKind::Enum,
            SyntaxKind::TRAIT_DEF => SymbolKind::Interface,
            SyntaxKind::MODULE => SymbolKind::Module,
            SyntaxKind::TYPE_DEF => SymbolKind::TypeParameter,
            SyntaxKind::STATIC_DEF => SymbolKind::Constant,
            SyntaxKind::CONST_DEF => SymbolKind::Constant,
            SyntaxKind::IMPL_ITEM => SymbolKind::Object,
            _ => SymbolKind::Variable,
        }
    }
}

impl ConvWith for Position {
    type Ctx = LineIndex;
    type Output = TextUnit;

    fn conv_with(self, line_index: &LineIndex) -> TextUnit {
        // TODO: UTF-16
        let line_col = LineCol {
            line: self.line as u32,
            col: (self.character as u32).into(),
        };
        line_index.offset(line_col)
    }
}

impl ConvWith for TextUnit {
    type Ctx = LineIndex;
    type Output = Position;

    fn conv_with(self, line_index: &LineIndex) -> Position {
        let line_col = line_index.line_col(self);
        // TODO: UTF-16
        Position::new(line_col.line as u64, u32::from(line_col.col) as u64)
    }
}

impl ConvWith for TextRange {
    type Ctx = LineIndex;
    type Output = Range;

    fn conv_with(self, line_index: &LineIndex) -> Range {
        Range::new(
            self.start().conv_with(line_index),
            self.end().conv_with(line_index),
        )
    }
}

impl ConvWith for Range {
    type Ctx = LineIndex;
    type Output = TextRange;

    fn conv_with(self, line_index: &LineIndex) -> TextRange {
        TextRange::from_to(
            self.start.conv_with(line_index),
            self.end.conv_with(line_index),
        )
    }
}

impl ConvWith for Edit {
    type Ctx = LineIndex;
    type Output = Vec<TextEdit>;

    fn conv_with(self, line_index: &LineIndex) -> Vec<TextEdit> {
        self.into_atoms()
            .into_iter()
            .map_conv_with(line_index)
            .collect()
    }
}

impl ConvWith for AtomEdit {
    type Ctx = LineIndex;
    type Output = TextEdit;

    fn conv_with(self, line_index: &LineIndex) -> TextEdit {
        TextEdit {
            range: self.delete.conv_with(line_index),
            new_text: self.insert,
        }
    }
}

impl<T: ConvWith> ConvWith for Option<T> {
    type Ctx = <T as ConvWith>::Ctx;
    type Output = Option<<T as ConvWith>::Output>;
    fn conv_with(self, ctx: &Self::Ctx) -> Self::Output {
        self.map(|x| ConvWith::conv_with(x, ctx))
    }
}

impl<'a> TryConvWith for &'a Url {
    type Ctx = ServerWorld;
    type Output = FileId;
    fn try_conv_with(self, world: &ServerWorld) -> Result<FileId> {
        world.uri_to_file_id(self)
    }
}

impl TryConvWith for FileId {
    type Ctx = ServerWorld;
    type Output = Url;
    fn try_conv_with(self, world: &ServerWorld) -> Result<Url> {
        world.file_id_to_uri(self)
    }
}

impl<'a> TryConvWith for &'a TextDocumentItem {
    type Ctx = ServerWorld;
    type Output = FileId;
    fn try_conv_with(self, world: &ServerWorld) -> Result<FileId> {
        self.uri.try_conv_with(world)
    }
}

impl<'a> TryConvWith for &'a VersionedTextDocumentIdentifier {
    type Ctx = ServerWorld;
    type Output = FileId;
    fn try_conv_with(self, world: &ServerWorld) -> Result<FileId> {
        self.uri.try_conv_with(world)
    }
}

impl<'a> TryConvWith for &'a TextDocumentIdentifier {
    type Ctx = ServerWorld;
    type Output = FileId;
    fn try_conv_with(self, world: &ServerWorld) -> Result<FileId> {
        world.uri_to_file_id(&self.uri)
    }
}

impl<T: TryConvWith> TryConvWith for Vec<T> {
    type Ctx = <T as TryConvWith>::Ctx;
    type Output = Vec<<T as TryConvWith>::Output>;
    fn try_conv_with(self, ctx: &Self::Ctx) -> Result<Self::Output> {
        let mut res = Vec::with_capacity(self.len());
        for item in self {
            res.push(item.try_conv_with(ctx)?);
        }
        Ok(res)
    }
}

impl TryConvWith for SourceChange {
    type Ctx = ServerWorld;
    type Output = req::SourceChange;
    fn try_conv_with(self, world: &ServerWorld) -> Result<req::SourceChange> {
        let cursor_position = match self.cursor_position {
            None => None,
            Some(pos) => {
                let line_index = world.analysis().file_line_index(pos.file_id);
                let edits = self
                    .source_file_edits
                    .iter()
                    .find(|it| it.file_id == pos.file_id)
                    .map(|it| it.edits.as_slice())
                    .unwrap_or(&[]);
                let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits);
                let position = Position::new(line_col.line as u64, u32::from(line_col.col) as u64);
                Some(TextDocumentPositionParams {
                    text_document: TextDocumentIdentifier::new(pos.file_id.try_conv_with(world)?),
                    position,
                })
            }
        };
        let source_file_edits = self.source_file_edits.try_conv_with(world)?;
        let file_system_edits = self.file_system_edits.try_conv_with(world)?;
        Ok(req::SourceChange {
            label: self.label,
            source_file_edits,
            file_system_edits,
            cursor_position,
        })
    }
}

// HACK: we should translate offset to line/column using linde_index *with edits applied*.
// A naive version of this function would be to apply `edits` to the original text,
// construct a new line index and use that, but it would be slow.
//
// Writing fast & correct version is issue #105, let's use a quick hack in the meantime
fn translate_offset_with_edit(
    pre_edit_index: &LineIndex,
    offset: TextUnit,
    edits: &[AtomEdit],
) -> LineCol {
    let fallback = pre_edit_index.line_col(offset);
    let edit = match edits.first() {
        None => return fallback,
        Some(edit) => edit,
    };
    let end_offset = edit.delete.start() + TextUnit::of_str(&edit.insert);
    if !(edit.delete.start() <= offset && offset <= end_offset) {
        return fallback;
    }
    let rel_offset = offset - edit.delete.start();
    let in_edit_line_col = LineIndex::new(&edit.insert).line_col(rel_offset);
    let edit_line_col = pre_edit_index.line_col(edit.delete.start());
    if in_edit_line_col.line == 0 {
        LineCol {
            line: edit_line_col.line,
            col: edit_line_col.col + in_edit_line_col.col,
        }
    } else {
        LineCol {
            line: edit_line_col.line + in_edit_line_col.line,
            col: in_edit_line_col.col,
        }
    }
}

impl TryConvWith for SourceFileEdit {
    type Ctx = ServerWorld;
    type Output = TextDocumentEdit;
    fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> {
        let text_document = VersionedTextDocumentIdentifier {
            uri: self.file_id.try_conv_with(world)?,
            version: None,
        };
        let line_index = world.analysis().file_line_index(self.file_id);
        let edits = self.edits.into_iter().map_conv_with(&line_index).collect();
        Ok(TextDocumentEdit {
            text_document,
            edits,
        })
    }
}

impl TryConvWith for FileSystemEdit {
    type Ctx = ServerWorld;
    type Output = req::FileSystemEdit;
    fn try_conv_with(self, world: &ServerWorld) -> Result<req::FileSystemEdit> {
        let res = match self {
            FileSystemEdit::CreateFile { anchor, path } => {
                let uri = world.file_id_to_uri(anchor)?;
                let path = &path.as_str()[3..]; // strip `../` b/c url is weird
                let uri = uri.join(path)?;
                req::FileSystemEdit::CreateFile { uri }
            }
            FileSystemEdit::MoveFile { file, path } => {
                let src = world.file_id_to_uri(file)?;
                let path = &path.as_str()[3..]; // strip `../` b/c url is weird
                let dst = src.join(path)?;
                req::FileSystemEdit::MoveFile { src, dst }
            }
        };
        Ok(res)
    }
}

pub fn to_location(
    file_id: FileId,
    range: TextRange,
    world: &ServerWorld,
    line_index: &LineIndex,
) -> Result<Location> {
    let url = file_id.try_conv_with(world)?;
    let loc = Location::new(url, range.conv_with(line_index));
    Ok(loc)
}

pub trait MapConvWith<'a>: Sized + 'a {
    type Ctx;
    type Output;

    fn map_conv_with(self, ctx: &'a Self::Ctx) -> ConvWithIter<'a, Self, Self::Ctx> {
        ConvWithIter { iter: self, ctx }
    }
}

impl<'a, I> MapConvWith<'a> for I
where
    I: Iterator + 'a,
    I::Item: ConvWith,
{
    type Ctx = <I::Item as ConvWith>::Ctx;
    type Output = <I::Item as ConvWith>::Output;
}

pub struct ConvWithIter<'a, I, Ctx: 'a> {
    iter: I,
    ctx: &'a Ctx,
}

impl<'a, I, Ctx> Iterator for ConvWithIter<'a, I, Ctx>
where
    I: Iterator,
    I::Item: ConvWith<Ctx = Ctx>,
{
    type Item = <I::Item as ConvWith>::Output;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|item| item.conv_with(self.ctx))
    }
}
<commit_msg>clippy: cast_lossless<commit_after>use languageserver_types::{
    Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
    TextDocumentItem, TextDocumentPositionParams, TextEdit, Url, VersionedTextDocumentIdentifier,
};
use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit};
use ra_editor::{AtomEdit, Edit, LineCol, LineIndex};
use ra_syntax::{SyntaxKind, TextRange, TextUnit};

use crate::{req, server_world::ServerWorld, Result};

pub trait Conv {
    type Output;
    fn conv(self) -> Self::Output;
}

pub trait ConvWith {
    type Ctx;
    type Output;
    fn conv_with(self, ctx: &Self::Ctx) -> Self::Output;
}

pub trait TryConvWith {
    type Ctx;
    type Output;
    fn try_conv_with(self, ctx: &Self::Ctx) -> Result<Self::Output>;
}

impl Conv for SyntaxKind {
    type Output = SymbolKind;

    fn conv(self) -> <Self as Conv>::Output {
        match self {
            SyntaxKind::FN_DEF => SymbolKind::Function,
            SyntaxKind::STRUCT_DEF => SymbolKind::Struct,
            SyntaxKind::ENUM_DEF => SymbolKind::Enum,
            SyntaxKind::TRAIT_DEF => SymbolKind::Interface,
            SyntaxKind::MODULE => SymbolKind::Module,
            SyntaxKind::TYPE_DEF => SymbolKind::TypeParameter,
            SyntaxKind::STATIC_DEF => SymbolKind::Constant,
            SyntaxKind::CONST_DEF => SymbolKind::Constant,
            SyntaxKind::IMPL_ITEM => SymbolKind::Object,
            _ => SymbolKind::Variable,
        }
    }
}

impl ConvWith for Position {
    type Ctx = LineIndex;
    type Output = TextUnit;

    fn conv_with(self, line_index: &LineIndex) -> TextUnit {
        // TODO: UTF-16
        let line_col = LineCol {
            line: self.line as u32,
            col: (self.character as u32).into(),
        };
        line_index.offset(line_col)
    }
}

impl ConvWith for TextUnit {
    type Ctx = LineIndex;
    type Output = Position;

    fn conv_with(self, line_index: &LineIndex) -> Position {
        let line_col = line_index.line_col(self);
        // TODO: UTF-16
        Position::new(u64::from(line_col.line), u64::from(u32::from(line_col.col)))
    }
}

impl ConvWith for TextRange {
    type Ctx = LineIndex;
    type Output = Range;

    fn conv_with(self, line_index: &LineIndex) -> Range {
        Range::new(
            self.start().conv_with(line_index),
            self.end().conv_with(line_index),
        )
    }
}

impl ConvWith for Range {
    type Ctx = LineIndex;
    type Output = TextRange;

    fn conv_with(self, line_index: &LineIndex) -> TextRange {
        TextRange::from_to(
            self.start.conv_with(line_index),
            self.end.conv_with(line_index),
        )
    }
}

impl ConvWith for Edit {
    type Ctx = LineIndex;
    type Output = Vec<TextEdit>;

    fn conv_with(self, line_index: &LineIndex) -> Vec<TextEdit> {
        self.into_atoms()
            .into_iter()
            .map_conv_with(line_index)
            .collect()
    }
}

impl ConvWith for AtomEdit {
    type Ctx = LineIndex;
    type Output = TextEdit;

    fn conv_with(self, line_index: &LineIndex) -> TextEdit {
        TextEdit {
            range: self.delete.conv_with(line_index),
            new_text: self.insert,
        }
    }
}

impl<T: ConvWith> ConvWith for Option<T> {
    type Ctx = <T as ConvWith>::Ctx;
    type Output = Option<<T as ConvWith>::Output>;
    fn conv_with(self, ctx: &Self::Ctx) -> Self::Output {
        self.map(|x| ConvWith::conv_with(x, ctx))
    }
}

impl<'a> TryConvWith for &'a Url {
    type Ctx = ServerWorld;
    type Output = FileId;
    fn try_conv_with(self, world: &ServerWorld) -> Result<FileId> {
        world.uri_to_file_id(self)
    }
}

impl TryConvWith for FileId {
    type Ctx = ServerWorld;
    type Output = Url;
    fn try_conv_with(self, world: &ServerWorld) -> Result<Url> {
        world.file_id_to_uri(self)
    }
}

impl<'a> TryConvWith for &'a TextDocumentItem {
    type Ctx = ServerWorld;
    type Output = FileId;
    fn try_conv_with(self, world: &ServerWorld) -> Result<FileId> {
        self.uri.try_conv_with(world)
    }
}

impl<'a> TryConvWith for &'a VersionedTextDocumentIdentifier {
    type Ctx = ServerWorld;
    type Output = FileId;
    fn try_conv_with(self, world: &ServerWorld) -> Result<FileId> {
        self.uri.try_conv_with(world)
    }
}

impl<'a> TryConvWith for &'a TextDocumentIdentifier {
    type Ctx = ServerWorld;
    type Output = FileId;
    fn try_conv_with(self, world: &ServerWorld) -> Result<FileId> {
        world.uri_to_file_id(&self.uri)
    }
}

impl<T: TryConvWith> TryConvWith for Vec<T> {
    type Ctx = <T as TryConvWith>::Ctx;
    type Output = Vec<<T as TryConvWith>::Output>;
    fn try_conv_with(self, ctx: &Self::Ctx) -> Result<Self::Output> {
        let mut res = Vec::with_capacity(self.len());
        for item in self {
            res.push(item.try_conv_with(ctx)?);
        }
        Ok(res)
    }
}

impl TryConvWith for SourceChange {
    type Ctx = ServerWorld;
    type Output = req::SourceChange;
    fn try_conv_with(self, world: &ServerWorld) -> Result<req::SourceChange> {
        let cursor_position = match self.cursor_position {
            None => None,
            Some(pos) => {
                let line_index = world.analysis().file_line_index(pos.file_id);
                let edits = self
                    .source_file_edits
                    .iter()
                    .find(|it| it.file_id == pos.file_id)
                    .map(|it| it.edits.as_slice())
                    .unwrap_or(&[]);
                let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits);
                let position = Position::new(u64::from(line_col.line), u64::from(u32::from(line_col.col)));
                Some(TextDocumentPositionParams {
                    text_document: TextDocumentIdentifier::new(pos.file_id.try_conv_with(world)?),
                    position,
                })
            }
        };
        let source_file_edits = self.source_file_edits.try_conv_with(world)?;
        let file_system_edits = self.file_system_edits.try_conv_with(world)?;
        Ok(req::SourceChange {
            label: self.label,
            source_file_edits,
            file_system_edits,
            cursor_position,
        })
    }
}

// HACK: we should translate offset to line/column using linde_index *with edits applied*.
// A naive version of this function would be to apply `edits` to the original text,
// construct a new line index and use that, but it would be slow.
//
// Writing fast & correct version is issue #105, let's use a quick hack in the meantime
fn translate_offset_with_edit(
    pre_edit_index: &LineIndex,
    offset: TextUnit,
    edits: &[AtomEdit],
) -> LineCol {
    let fallback = pre_edit_index.line_col(offset);
    let edit = match edits.first() {
        None => return fallback,
        Some(edit) => edit,
    };
    let end_offset = edit.delete.start() + TextUnit::of_str(&edit.insert);
    if !(edit.delete.start() <= offset && offset <= end_offset) {
        return fallback;
    }
    let rel_offset = offset - edit.delete.start();
    let in_edit_line_col = LineIndex::new(&edit.insert).line_col(rel_offset);
    let edit_line_col = pre_edit_index.line_col(edit.delete.start());
    if in_edit_line_col.line == 0 {
        LineCol {
            line: edit_line_col.line,
            col: edit_line_col.col + in_edit_line_col.col,
        }
    } else {
        LineCol {
            line: edit_line_col.line + in_edit_line_col.line,
            col: in_edit_line_col.col,
        }
    }
}

impl TryConvWith for SourceFileEdit {
    type Ctx = ServerWorld;
    type Output = TextDocumentEdit;
    fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> {
        let text_document = VersionedTextDocumentIdentifier {
            uri: self.file_id.try_conv_with(world)?,
            version: None,
        };
        let line_index = world.analysis().file_line_index(self.file_id);
        let edits = self.edits.into_iter().map_conv_with(&line_index).collect();
        Ok(TextDocumentEdit {
            text_document,
            edits,
        })
    }
}

impl TryConvWith for FileSystemEdit {
    type Ctx = ServerWorld;
    type Output = req::FileSystemEdit;
    fn try_conv_with(self, world: &ServerWorld) -> Result<req::FileSystemEdit> {
        let res = match self {
            FileSystemEdit::CreateFile { anchor, path } => {
                let uri = world.file_id_to_uri(anchor)?;
                let path = &path.as_str()[3..]; // strip `../` b/c url is weird
                let uri = uri.join(path)?;
                req::FileSystemEdit::CreateFile { uri }
            }
            FileSystemEdit::MoveFile { file, path } => {
                let src = world.file_id_to_uri(file)?;
                let path = &path.as_str()[3..]; // strip `../` b/c url is weird
                let dst = src.join(path)?;
                req::FileSystemEdit::MoveFile { src, dst }
            }
        };
        Ok(res)
    }
}

pub fn to_location(
    file_id: FileId,
    range: TextRange,
    world: &ServerWorld,
    line_index: &LineIndex,
) -> Result<Location> {
    let url = file_id.try_conv_with(world)?;
    let loc = Location::new(url, range.conv_with(line_index));
    Ok(loc)
}

pub trait MapConvWith<'a>: Sized + 'a {
    type Ctx;
    type Output;

    fn map_conv_with(self, ctx: &'a Self::Ctx) -> ConvWithIter<'a, Self, Self::Ctx> {
        ConvWithIter { iter: self, ctx }
    }
}

impl<'a, I> MapConvWith<'a> for I
where
    I: Iterator + 'a,
    I::Item: ConvWith,
{
    type Ctx = <I::Item as ConvWith>::Ctx;
    type Output = <I::Item as ConvWith>::Output;
}

pub struct ConvWithIter<'a, I, Ctx: 'a> {
    iter: I,
    ctx: &'a Ctx,
}

impl<'a, I, Ctx> Iterator for ConvWithIter<'a, I, Ctx>
where
    I: Iterator,
    I::Item: ConvWith<Ctx = Ctx>,
{
    type Item = <I::Item as ConvWith>::Output;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|item| item.conv_with(self.ctx))
    }
}
<|endoftext|>


<commit_before>extern crate rsoundio;

use std::f32::consts;
use std::thread;
use std::time::Duration;

#[test]
fn test_outstream() {
    println!("test: OutStream");
    let sio = rsoundio::SoundIo::new();
    sio.connect_backend(rsoundio::ffi::SioBackend::Dummy).unwrap();
    println!("current backend: {}", sio.current_backend().unwrap());
    sio.flush_events();
    let fmt;
    let dev_idx = sio.default_output_device_index().unwrap();
    let mut frames: Vec<Vec<f32>> = vec![vec![], vec![]];
    let dev = sio.get_output_device(dev_idx).unwrap();
    println!("device: {}, ref_count: {}", dev, dev.ref_count());
    let mut stream = dev.create_outstream().unwrap();
    assert!(stream.open().is_none());
    fmt = stream.current_format().unwrap();
    println!("current format: {}", fmt);
    let f = 4400f32;
    let sr = stream.get_sample_rate();
    let layout = stream.get_layout();
    let channels = layout.channel_count();
    let phi = 2.0 * f * consts::PI / (sr as f32);
    let l: Vec<f32> = (0..4096).map(|i| f32::sin(i as f32 * phi)).collect();
    let r = l.clone();
    frames = vec![l, r];
    let cb = |out: rsoundio::OutStream, min_frame_count: i32, max_frame_count: i32| {
        let frames_written = out.write_stream_f32(min_frame_count, &frames).unwrap();
        assert!(frames_written > 0);
        out.get_latency().map(|latency| assert!(latency >= 0.0));
    };
    stream.register_write_callback(Box::new(cb));
    let ucb = |out: rsoundio::OutStream| println!("Underflow!");
    stream.register_underflow_callback(Box::new(ucb));
    let ecb = |out: rsoundio::OutStream, err: rsoundio::ffi::SioError| println!("Error: {}", err);
    stream.register_error_callback(Box::new(ecb));
    assert!(stream.start().is_none());
    //sio.wait_events();
    thread::sleep(Duration::new(1,0));
    assert!(stream.pause(true).is_none());
    thread::sleep(Duration::new(1,0));
    assert!(stream.pause(false).is_none());
    assert!(stream.clear_buffer().is_none());
    thread::sleep(Duration::new(1,0));
    stream.destroy();
    dev.dec_ref();
}
<commit_msg>Fix wrong use of return type<commit_after>extern crate rsoundio;

use std::f32::consts;
use std::thread;
use std::time::Duration;

#[test]
fn test_outstream() {
    println!("test: OutStream");
    let sio = rsoundio::SoundIo::new();
    sio.connect_backend(rsoundio::ffi::SioBackend::Dummy).unwrap();
    println!("current backend: {}", sio.current_backend().unwrap());
    sio.flush_events();
    let fmt;
    let dev_idx = sio.default_output_device_index().unwrap();
    let mut frames: Vec<Vec<f32>> = vec![vec![], vec![]];
    let dev = sio.get_output_device(dev_idx).unwrap();
    println!("device: {}, ref_count: {}", dev, dev.ref_count());
    let mut stream = dev.create_outstream().unwrap();
    stream.open().unwrap();
    fmt = stream.current_format().unwrap();
    println!("current format: {}", fmt);
    let f = 4400f32;
    let sr = stream.get_sample_rate();
    let layout = stream.get_layout();
    let channels = layout.channel_count();
    let phi = 2.0 * f * consts::PI / (sr as f32);
    let l: Vec<f32> = (0..4096).map(|i| f32::sin(i as f32 * phi)).collect();
    let r = l.clone();
    frames = vec![l, r];
    let cb = |out: rsoundio::OutStream, min_frame_count: i32, max_frame_count: i32| {
        let frames_written = out.write_stream_f32(min_frame_count, &frames).unwrap();
        assert!(frames_written > 0);
        out.get_latency().map(|latency| assert!(latency >= 0.0));
    };
    stream.register_write_callback(Box::new(cb));
    let ucb = |out: rsoundio::OutStream| println!("Underflow!");
    stream.register_underflow_callback(Box::new(ucb));
    let ecb = |out: rsoundio::OutStream, err: rsoundio::ffi::SioError| println!("Error: {}", err);
    stream.register_error_callback(Box::new(ecb));
    assert!(stream.start().is_none());
    //sio.wait_events();
    thread::sleep(Duration::new(1,0));
    assert!(stream.pause(true).is_none());
    thread::sleep(Duration::new(1,0));
    assert!(stream.pause(false).is_none());
    assert!(stream.clear_buffer().is_none());
    thread::sleep(Duration::new(1,0));
    stream.destroy();
    dev.dec_ref();
}
<|endoftext|>


<commit_before>use crate::{Angle, Color, OnLinePos, OnPlanePos, Point, RelativeDir};

/// Describes a position on a colorful gradient.
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct GradientStop {
    pub pos: Option<OnLinePos>,
    pub color: Color,
}

impl GradientStop {
    /// Creates a new stop mark.
    pub fn new(pos: Option<OnLinePos>, color: Color) -> GradientStop {
        GradientStop { pos, color }
    }
}

impl From<(OnLinePos, Color)> for GradientStop {
    fn from(d: (OnLinePos, Color)) -> Self {
        Self {
            pos: Some(d.0),
            color: d.1,
        }
    }
}

impl From<(f64, Color)> for GradientStop {
    fn from(d: (f64, Color)) -> Self {
        Self {
            pos: Some(OnLinePos::from_unit_percent(d.0)),
            color: d.1,
        }
    }
}

impl From<Color> for GradientStop {
    fn from(color: Color) -> Self {
        Self { pos: None, color }
    }
}

impl Default for GradientStop {
    fn default() -> GradientStop {
        GradientStop {
            pos: None,
            color: Color::default(),
        }
    }
}

/// Describes the coordinates of a colorful linear gradient.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum LinearGradientCoords {
    /// Defines the linear gradient by point A to point B.
    Ends { start: Point, end: Point },
    /// Defines the linear gradient using an angle and a displacement from the center of the target figure.
    Angle {
        angle: Angle,
        // Defines a displacement from the center of the target shape.
        displacement: OnPlanePos,
    },
    // Defines a gradient as one that crosses the figure in a given direction.
    Direction {
        direction: RelativeDir,
        displacement: OnPlanePos,
    },
}

impl LinearGradientCoords {
    /// Creates a `LinearGradientCoords` from its ends.
    pub fn from_ends(start: impl Into<Point>, end: impl Into<Point>) -> LinearGradientCoords {
        LinearGradientCoords::Ends {
            start: start.into(),
            end: end.into(),
        }
    }

    /// Creates a `LinearGradientCoords` from its angle.
    pub fn from_angle(angle: Angle) -> LinearGradientCoords {
        LinearGradientCoords::Angle {
            angle,
            displacement: OnPlanePos::default(),
        }
    }

    /// Sets the displacement if `self` is defined by its angle, otherwise, this does nothing.
    pub fn with_displacement(&mut self, displacement: impl Into<OnPlanePos>) -> Self {
        if let LinearGradientCoords::Angle {
            angle: _,
            displacement: disp,
        } = self
        {
            *disp = displacement.into();
        }
        *self
    }
}

impl Default for LinearGradientCoords {
    fn default() -> LinearGradientCoords {
        LinearGradientCoords::Direction {
            direction: RelativeDir::Top,
            displacement: OnPlanePos::default(),
        }
    }
}

/// Describes a colorful gradient.
#[derive(Clone, PartialEq, Debug)]
pub struct Gradient {
    pub kind: GradientKind,
    pub stops: Vec<GradientStop>,
    pub repeat: bool,
}

impl Default for Gradient {
    fn default() -> Self {
        Self {
            kind: GradientKind::Linear(LinearGradientCoords::default()),
            stops: vec![
                GradientStop {
                    pos: None,
                    color: Color::rgb(0, 0, 0),
                },
                GradientStop {
                    pos: None,
                    color: Color::rgb(255, 255, 255),
                },
            ],
            repeat: false,
        }
    }
}

/// Describes the kind of a gradient.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum GradientKind {
    Linear(LinearGradientCoords),
    // Radial(RadialGradient),
}

impl Default for GradientKind {
    fn default() -> GradientKind {
        GradientKind::Linear(LinearGradientCoords::default())
    }
}
<commit_msg>utils: derived implementation of default<commit_after>use crate::{Angle, Color, OnLinePos, OnPlanePos, Point, RelativeDir};

/// Describes a position on a colorful gradient.
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct GradientStop {
    pub pos: Option<OnLinePos>,
    pub color: Color,
}

impl GradientStop {
    /// Creates a new stop mark.
    pub fn new(pos: Option<OnLinePos>, color: Color) -> GradientStop {
        GradientStop { pos, color }
    }
}

impl From<(OnLinePos, Color)> for GradientStop {
    fn from(d: (OnLinePos, Color)) -> Self {
        Self {
            pos: Some(d.0),
            color: d.1,
        }
    }
}

impl From<(f64, Color)> for GradientStop {
    fn from(d: (f64, Color)) -> Self {
        Self {
            pos: Some(OnLinePos::from_unit_percent(d.0)),
            color: d.1,
        }
    }
}

impl From<Color> for GradientStop {
    fn from(color: Color) -> Self {
        Self { pos: None, color }
    }
}

/// Describes the coordinates of a colorful linear gradient.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum LinearGradientCoords {
    /// Defines the linear gradient by point A to point B.
    Ends { start: Point, end: Point },
    /// Defines the linear gradient using an angle and a displacement from the center of the target figure.
    Angle {
        angle: Angle,
        // Defines a displacement from the center of the target shape.
        displacement: OnPlanePos,
    },
    // Defines a gradient as one that crosses the figure in a given direction.
    Direction {
        direction: RelativeDir,
        displacement: OnPlanePos,
    },
}

impl LinearGradientCoords {
    /// Creates a `LinearGradientCoords` from its ends.
    pub fn from_ends(start: impl Into<Point>, end: impl Into<Point>) -> LinearGradientCoords {
        LinearGradientCoords::Ends {
            start: start.into(),
            end: end.into(),
        }
    }

    /// Creates a `LinearGradientCoords` from its angle.
    pub fn from_angle(angle: Angle) -> LinearGradientCoords {
        LinearGradientCoords::Angle {
            angle,
            displacement: OnPlanePos::default(),
        }
    }

    /// Sets the displacement if `self` is defined by its angle, otherwise, this does nothing.
    pub fn with_displacement(&mut self, displacement: impl Into<OnPlanePos>) -> Self {
        if let LinearGradientCoords::Angle {
            angle: _,
            displacement: disp,
        } = self
        {
            *disp = displacement.into();
        }
        *self
    }
}

impl Default for LinearGradientCoords {
    fn default() -> LinearGradientCoords {
        LinearGradientCoords::Direction {
            direction: RelativeDir::Top,
            displacement: OnPlanePos::default(),
        }
    }
}

/// Describes a colorful gradient.
#[derive(Clone, PartialEq, Debug)]
pub struct Gradient {
    pub kind: GradientKind,
    pub stops: Vec<GradientStop>,
    pub repeat: bool,
}

impl Default for Gradient {
    fn default() -> Self {
        Self {
            kind: GradientKind::Linear(LinearGradientCoords::default()),
            stops: vec![
                GradientStop {
                    pos: None,
                    color: Color::rgb(0, 0, 0),
                },
                GradientStop {
                    pos: None,
                    color: Color::rgb(255, 255, 255),
                },
            ],
            repeat: false,
        }
    }
}

/// Describes the kind of a gradient.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum GradientKind {
    Linear(LinearGradientCoords),
    // Radial(RadialGradient),
}

impl Default for GradientKind {
    fn default() -> GradientKind {
        GradientKind::Linear(LinearGradientCoords::default())
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ----------------

// This program exercises the Rust GIF decoder at
// https://github.com/PistonDevelopers/image-gif
//
// Wuffs' C code doesn't depend on Rust per se, but this program gives some
// performance data for specific Rust GIF implementations. The equivalent Wuffs
// benchmarks (on the same test image) are run via:
//
// wuffs bench std/gif
//
// The Wuffs benchmark reports megabytes per second. This program reports
// megapixels per second. The two concepts should be equivalent, since GIF
// images' pixel data are always 1 byte per pixel indices into a color palette.
//
// To run this program, do "cargo run --release" from the parent directory (the
// directory containing the Cargo.toml file).

// TODO: unify this program, bench-rust-gif-dot-rs, with bench-rust-gif, the
// other Rust GIF benchmark program. They are two separate programs because
// both libraries want to be named "gif", and the cargo package manager cannot
// handle duplicate names (https://github.com/rust-lang/cargo/issues/1311).

extern crate gif;

use std::time::Instant;

const ITERSCALE: u64 = 10;
const REPS: u64 = 5;

fn main() {
    let mut dst = vec![0u8; 64 * 1024 * 1024];

    for _ in 0..REPS {
        bench(
            "1k_bw",
            &mut dst[..32 * 32],
            include_bytes!("../../../test/data/pjw-thumbnail.gif"),
            2000, // iters_unscaled
            32, // width
            32, // height
            1, // first_pixel
            1, // last_pixel
        );

        bench(
            "1k_color",
            &mut dst[..36 * 28],
            include_bytes!("../../../test/data/hippopotamus.regular.gif"),
            1000, // iters_unscaled
            36, // width
            28, // height
            82, // first_pixel
            225, // last_pixel
        );

        bench(
            "10k_indexed",
            &mut dst[..90 * 112],
            include_bytes!("../../../test/data/hat.gif"),
            100, // iters_unscaled
            90, // width
            112, // height
            0, // first_pixel
            0, // last_pixel
        );

        bench(
            "20k",
            &mut dst[..160 * 120],
            include_bytes!("../../../test/data/bricks-gray.gif"),
            50, // iters_unscaled
            160, // width
            120, // height
            85, // first_pixel
            6, // last_pixel
        );

        bench(
            "100k_artificial",
            &mut dst[..312 * 442],
            include_bytes!("../../../test/data/hibiscus.primitive.gif"),
            15, // iters_unscaled
            312, // width
            442, // height
            102, // first_pixel
            102, // last_pixel
        );

        bench(
            "100k_realistic",
            &mut dst[..312 * 442],
            include_bytes!("../../../test/data/hibiscus.regular.gif"),
            10, // iters_unscaled
            312, // width
            442, // height
            0, // first_pixel
            0, // last_pixel
        );

        bench(
            "1000k",
            &mut dst[..1165 * 859],
            include_bytes!("../../../test/data/harvesters.gif"),
            1, // iters_unscaled
            1165, // width
            859, // height
            0, // first_pixel
            1, // last_pixel
        );
    }
}

fn bench(
    name: &str, // Benchmark name.
    dst: &mut [u8], // Destination buffer.
    src: &[u8], // Source data.
    iters_unscaled: u64, // Base number of iterations.
    width: u64, // Image width in pixels.
    height: u64, // Image height in pixels.
    first_pixel: u8, // Top left pixel's palette index.
    last_pixel: u8, // Bottom right pixel's palette index.
) {
    let start = Instant::now();

    let iters = iters_unscaled * ITERSCALE;
    for _ in 0..iters {
        decode(&mut dst[..], src, width, height, first_pixel, last_pixel);
    }

    let elapsed = start.elapsed();
    let elapsed_nanos = elapsed.as_secs() * 1_000_000_000 + (elapsed.subsec_nanos() as u64);

    let total_pixels: u64 = iters * width * height;
    let kp_per_s: u64 = total_pixels * 1_000_000 / elapsed_nanos;

    print!(
        "Benchmarkrust_gif_decode_{:16}   {:8}   {:12} ns/op   {:3}.{:03} MB/s\n",
        name,
        iters,
        elapsed_nanos / iters,
        kp_per_s / 1_000,
        kp_per_s % 1_000
    );
}

fn decode(dst: &mut [u8], src: &[u8], width: u64, height: u64, first_pixel: u8, last_pixel: u8) {
    // GIF images are 1 byte per pixel.
    let num_bytes = (width * height * 1) as usize;

    // Set up the hard-coded sanity check, executed below.
    dst[0] = 0xFE;
    dst[num_bytes - 1] = 0xFE;

    let mut reader = gif::Decoder::new(src).read_info().unwrap();
    reader.next_frame_info().unwrap().unwrap();

    if reader.buffer_size() != num_bytes {
        panic!("wrong num_bytes")
    }

    reader.read_into_buffer(dst).unwrap();

    // A hard-coded sanity check that we decoded the pixel data correctly.
    if (dst[0] != first_pixel) || (dst[num_bytes - 1] != last_pixel) {
        panic!("wrong dst pixels")
    }
}
<commit_msg>Have bench-rust-gif process animated / RGBA images<commit_after>// Copyright 2018 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ----------------

// This program exercises the Rust GIF decoder at
// https://github.com/image-rs/image-gif
// which is the top result for https://crates.io/search?q=gif
//
// Wuffs' C code doesn't depend on Rust per se, but this program gives some
// performance data for specific Rust GIF implementations. The equivalent Wuffs
// benchmarks (on the same test images) are run via:
//
// wuffs bench std/gif
//
// To run this program, do "cargo run --release" from the parent directory (the
// directory containing the Cargo.toml file).

// TODO: unify this program, bench-rust-gif-dot-rs, with bench-rust-gif, the
// other Rust GIF benchmark program. They are two separate programs because
// both libraries want to be named "gif", and the cargo package manager cannot
// handle duplicate names (https://github.com/rust-lang/cargo/issues/1311).

extern crate gif;

use gif::SetParameter;
use std::time::Instant;

const ITERSCALE: u64 = 10;
const REPS: u64 = 5;

fn main() {
    let mut dst = vec![0u8; 64 * 1024 * 1024];

    for _ in 0..REPS {
        bench(
            "1k_bw",
            &mut dst[..],
            include_bytes!("../../../test/data/pjw-thumbnail.gif"),
            2000, // iters_unscaled
        );

        bench(
            "1k_color",
            &mut dst[..],
            include_bytes!("../../../test/data/hippopotamus.regular.gif"),
            1000, // iters_unscaled
        );

        bench(
            "10k_bgra",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            100, // iters_unscaled
        );

        bench(
            "10k_indexed",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            100, // iters_unscaled
        );

        bench(
            "20k",
            &mut dst[..],
            include_bytes!("../../../test/data/bricks-gray.gif"),
            50, // iters_unscaled
        );

        bench(
            "100k_artificial",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.primitive.gif"),
            15, // iters_unscaled
        );

        bench(
            "100k_realistic",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.regular.gif"),
            10, // iters_unscaled
        );

        bench(
            "1000k",
            &mut dst[..],
            include_bytes!("../../../test/data/harvesters.gif"),
            1, // iters_unscaled
        );

        bench(
            "anim_screencap",
            &mut dst[..],
            include_bytes!("../../../test/data/gifplayer-muybridge.gif"),
            1, // iters_unscaled
        );
    }
}

fn bench(
    name: &str, // Benchmark name.
    dst: &mut [u8], // Destination buffer.
    src: &[u8], // Source data.
    iters_unscaled: u64, // Base number of iterations.
) {
    let iters = iters_unscaled * ITERSCALE;
    let output_32_bit_color = name.ends_with("_bgra");
    let mut num_bytes = 0u64;

    let start = Instant::now();
    for _ in 0..iters {
        num_bytes += decode(&mut dst[..], src, output_32_bit_color);
    }
    let elapsed = start.elapsed();

    let elapsed_nanos = (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64);
    let kb_per_s: u64 = num_bytes * 1_000_000 / elapsed_nanos;
    print!(
        "Benchmarkrust_gif_decode_{:16}   {:8}   {:12} ns/op   {:3}.{:03} MB/s\n",
        name,
        iters,
        elapsed_nanos / iters,
        kb_per_s / 1_000,
        kb_per_s % 1_000
    );
}

// decode returns the number of bytes processed.
fn decode(dst: &mut [u8], src: &[u8], output_32_bit_color: bool) -> u64 {
    let mut decoder = gif::Decoder::new(src);
    if output_32_bit_color {
        decoder.set(gif::ColorOutput::RGBA);
    }

    let mut num_bytes = 0u64;
    let mut reader = decoder.read_info().unwrap();
    while let Some(_) = reader.next_frame_info().unwrap() {
        num_bytes += reader.buffer_size() as u64;
        reader.read_into_buffer(dst).unwrap();
    }
    num_bytes
}
<|endoftext|>


<commit_before>// check-pass
trait Foo {
    type Item;
}

trait Bar<T> {}

fn baz<T>()
where
    T: Foo,
    T: Bar<T::Item>,
{
}

fn main() {}
<commit_msg>Add description on test<commit_after>// check-pass

// The goal of this test is to ensure that T: Bar<T::Item>
// in the where clause does not cycle

trait Foo {
    type Item;
}

trait Bar<T> {}

fn baz<T>()
where
    T: Foo,
    T: Bar<T::Item>,
{
}

fn main() {}
<|endoftext|>