<commit_before>extern crate rustc_serialize;
#[macro_use]
extern crate nickel;
extern crate redis;
extern crate r2d2;
extern crate r2d2_redis;
extern crate plugin;
extern crate typemap;

extern crate core;

use std::env;
use std::collections::HashMap;
use r2d2::NopErrorHandler;
use nickel::{Nickel, HttpRouter, JsonBody, MediaType, QueryString};
use nickel::status::StatusCode;
use core::ops::Deref;
use redis::{Commands, Connection, RedisError};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;

use redis_middleware::{RedisMiddleware, RedisRequestExtensions};
mod redis_middleware;

#[derive(RustcDecodable, RustcEncodable)]
struct RatingSubmission {
    uuid: String,
    mod_str: String,
    rating: Rating,
}

#[derive(Clone, Copy, Debug)]
enum Rating {
    Poor = 0,
    BelowAverage,
    Average,
    AboveAverage,
    Excellent,
}

impl From<u8> for Rating {
    fn from(rating: u8) -> Self {
        match rating {
            0 => Rating::Poor,
            1 => Rating::BelowAverage,
            2 => Rating::Average,
            3 => Rating::AboveAverage,
            _ => Rating::Excellent,
        }
    }
}

impl Decodable for Rating {
    fn decode<D: Decoder>(d: &mut D) -> Result<Rating, D::Error> {
        let r = try!(d.read_u8());
        Ok(Rating::from(r))
    }
}

impl Encodable for Rating {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let as_u8 = *self as u8;
        s.emit_u8(as_u8)
    }
}

#[derive(RustcEncodable)]
struct RatingResults {
    average: HashMap<String, Rating>,
    own: Option<HashMap<String, Rating>>,
}

fn incr_requests(conn: &Connection) {
    if let Err(_) = conn.incr::<_, _, u64>("requests", 1) {
        println!("failed to incr request counter.")
    }
}

fn get_mod_rating(conn: &Connection, mod_str: &str) -> Result<(Rating, u32), RedisError> {
    let ratings = try!(conn.hvals::<_, Vec<u8>>(mod_str));
    let length = ratings.len() as u32;
    let mut sum = 0u32;
    for rating in ratings {
        sum += rating as u32;
    }
    match length {
        0 => Ok((Rating::Poor, length)),
        _ => Ok((Rating::from((sum / length) as u8), length)),
    }
}

const OK_RESP: (StatusCode, &'static str) = (StatusCode::Ok, "ok");

fn main() {
    let mut webserver = Nickel::new();

    let redis_url = env::var("DATABASE_URL").unwrap_or("redis://localhost/3".to_owned());
    println!("connecting to redis @ {}", redis_url);

    let redispool = RedisMiddleware::new(&*redis_url, 3, Box::new(NopErrorHandler)).unwrap();
    webserver.utilize(redispool);

    webserver.post("/submit",
                   middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let sbm = try_with!(response, {
            request.json_as::<RatingSubmission>().map_err(|e| (StatusCode::BadRequest, e))
        });
        println!("{} rates {} as {:?}", sbm.uuid, sbm.mod_str, sbm.rating);
        let _: bool = try_with!(response, {
            redis_conn.hset("mods", &*sbm.mod_str, true).map_err(|e| (StatusCode::BadRequest, e))
        });
        let _: u8 = try_with!(response, {
            redis_conn.hset(sbm.mod_str, sbm.uuid, sbm.rating as u8).map_err(|e|
                (StatusCode::BadRequest, e)
            )
        });
        OK_RESP
    });

    webserver.get("/rating/:mod",
                  middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let mod_str = request.param("mod").unwrap();
        let result = try_with!(response, {
            get_mod_rating(redis_conn, mod_str).map_err(|e| (StatusCode::BadRequest, e))
        });
        match result {
            (_, 0) => (StatusCode::NotFound, "Not Found!".to_owned()),
            (rating, sbm) => (StatusCode::Ok, format!("{:?}, {} submissions", rating, sbm)),
        }
    });

    webserver.get("/ratings",
                  middleware! { |request, mut response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);

        let mods = try_with!(response, {
            redis_conn.hkeys::<_, Vec<String>>("mods").map_err(|e| (StatusCode::BadRequest, e))
        });

        let mut own_ratings: HashMap<String, Rating> = HashMap::new();
        let mut average_ratings: HashMap<String, Rating> = HashMap::new();

        for mod_str in mods {
            let mod_str = mod_str.as_str();
            let (rating, sbm) = try_with!(response, {
                get_mod_rating(redis_conn, mod_str).map_err(|e| (StatusCode::BadRequest, e))
            });
            if sbm == 0 {
                continue;
            }
            average_ratings.insert(mod_str.to_owned(), rating);
            if let Some(uuid) = request.query().get("uuid") {
                if let Ok(rating) = redis_conn.hget::<_, _, u8>(mod_str, uuid) {
                    own_ratings.insert(mod_str.to_owned(), Rating::from(rating));
                }
            }
        }

        let result = RatingResults {
            average: average_ratings,
            own: match request.query().get("uuid") {
                Some(_) => Some(own_ratings),
                None => None,
            },
        };
        response.set(MediaType::Json);
        json::encode(&result).unwrap()
    });

    webserver.listen("127.0.0.1:7998")
}
<commit_msg>transmit amount of ratings<commit_after>extern crate rustc_serialize;
#[macro_use]
extern crate nickel;
extern crate redis;
extern crate r2d2;
extern crate r2d2_redis;
extern crate plugin;
extern crate typemap;

extern crate core;

use std::env;
use std::collections::HashMap;
use r2d2::NopErrorHandler;
use nickel::{Nickel, HttpRouter, JsonBody, MediaType, QueryString};
use nickel::status::StatusCode;
use core::ops::Deref;
use redis::{Commands, Connection, RedisError};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;

use redis_middleware::{RedisMiddleware, RedisRequestExtensions};
mod redis_middleware;

#[derive(RustcDecodable, RustcEncodable)]
struct RatingSubmission {
    uuid: String,
    mod_str: String,
    rating: Rating,
}

#[derive(Clone, Copy, Debug)]
enum Rating {
    Poor = 0,
    BelowAverage,
    Average,
    AboveAverage,
    Excellent,
}

impl From<u8> for Rating {
    fn from(rating: u8) -> Self {
        match rating {
            0 => Rating::Poor,
            1 => Rating::BelowAverage,
            2 => Rating::Average,
            3 => Rating::AboveAverage,
            _ => Rating::Excellent,
        }
    }
}

impl Decodable for Rating {
    fn decode<D: Decoder>(d: &mut D) -> Result<Rating, D::Error> {
        let r = try!(d.read_u8());
        Ok(Rating::from(r))
    }
}

impl Encodable for Rating {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let as_u8 = *self as u8;
        s.emit_u8(as_u8)
    }
}

#[derive(RustcEncodable)]
struct RatingResults {
    average: HashMap<String, Rating>,
    amount: HashMap<String, usize>,
    own: Option<HashMap<String, Rating>>,
}

fn incr_requests(conn: &Connection) {
    if let Err(_) = conn.incr::<_, _, u64>("requests", 1) {
        println!("failed to incr request counter.")
    }
}

fn get_mod_rating(conn: &Connection, mod_str: &str) -> Result<(Rating, u32), RedisError> {
    let ratings = try!(conn.hvals::<_, Vec<u8>>(mod_str));
    let length = ratings.len() as u32;
    let mut sum = 0u32;
    for rating in ratings {
        sum += rating as u32;
    }
    match length {
        0 => Ok((Rating::Poor, length)),
        _ => Ok((Rating::from((sum / length) as u8), length)),
    }
}

const OK_RESP: (StatusCode, &'static str) = (StatusCode::Ok, "ok");

fn main() {
    let mut webserver = Nickel::new();

    let redis_url = env::var("DATABASE_URL").unwrap_or("redis://localhost/3".to_owned());
    println!("connecting to redis @ {}", redis_url);

    let redispool = RedisMiddleware::new(&*redis_url, 3, Box::new(NopErrorHandler)).unwrap();
    webserver.utilize(redispool);

    webserver.post("/submit",
                   middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let sbm = try_with!(response, {
            request.json_as::<RatingSubmission>().map_err(|e| (StatusCode::BadRequest, e))
        });
        println!("{} rates {} as {:?}", sbm.uuid, sbm.mod_str, sbm.rating);
        let _: bool = try_with!(response, {
            redis_conn.hset("mods", &*sbm.mod_str, true).map_err(|e| (StatusCode::BadRequest, e))
        });
        let _: u8 = try_with!(response, {
            redis_conn.hset(sbm.mod_str, sbm.uuid, sbm.rating as u8).map_err(|e|
                (StatusCode::BadRequest, e)
            )
        });
        OK_RESP
    });

    webserver.get("/rating/:mod",
                  middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let mod_str = request.param("mod").unwrap();
        let result = try_with!(response, {
            get_mod_rating(redis_conn, mod_str).map_err(|e| (StatusCode::BadRequest, e))
        });
        match result {
            (_, 0) => (StatusCode::NotFound, "Not Found!".to_owned()),
            (rating, sbm) => (StatusCode::Ok, format!("{:?}, {} submissions", rating, sbm)),
        }
    });

    webserver.get("/ratings",
                  middleware! { |request, mut response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);

        let mods = try_with!(response, {
            redis_conn.hkeys::<_, Vec<String>>("mods").map_err(|e| (StatusCode::BadRequest, e))
        });

        let mut own_ratings: HashMap<String, Rating> = HashMap::new();
        let mut amount_ratings: HashMap<String, usize> = HashMap::new();
        let mut average_ratings: HashMap<String, Rating> = HashMap::new();

        for mod_str in mods {
            let mod_str = mod_str.as_str();
            let (rating, sbm) = try_with!(response, {
                get_mod_rating(redis_conn, mod_str).map_err(|e| (StatusCode::BadRequest, e))
            });
            if sbm == 0 {
                continue;
            }
            average_ratings.insert(mod_str.to_owned(), rating);
            amount_ratings.insert(mod_str.to_owned(), sbm);
            if let Some(uuid) = request.query().get("uuid") {
                if let Ok(rating) = redis_conn.hget::<_, _, u8>(mod_str, uuid) {
                    own_ratings.insert(mod_str.to_owned(), Rating::from(rating));
                }
            }
        }

        let result = RatingResults {
            average: average_ratings,
            amount: amount_ratings,
            own: match request.query().get("uuid") {
                Some(_) => Some(own_ratings),
                None => None,
            },
        };
        response.set(MediaType::Json);
        json::encode(&result).unwrap()
    });

    webserver.listen("127.0.0.1:7998")
}
<|endoftext|>


<commit_before>#[desc = "C64 emulator"];
#[copyright = "Andreas Neuhaus <info@zargony.com>"];
#[license = "MIT"];

use cpu::mos65xx::Mos6510;
use mem::{Addressable, Ram, Rom};

pub mod cpu {
	pub mod mos65xx;
}
pub mod mem;

fn main () {
	let mut c64 = C64::new();
	c64.run();
}

// General information on C64 : http://unusedino.de/ec64/technical/aay/c64/
// Useful emulator information: http://emudocs.org/?page=Commodore%2064
// C64 memory map overview: http://www.c64-wiki.com/index.php/Memory_Map
// Details about the PLA: http://www.c64-wiki.de/index.php/PLA_(C64-Chip)
// Even more PLA details: http://skoe.de/docs/c64-dissected/pla/c64_pla_dissected_r1.1_a4ss.pdf

// 64K RAM (not every part is always accessible)
// 8K BASIC ROM at $A000
// 4K character ROM at $D000
// 8K kernal ROM at $E000

struct C64Memory {
	ram: Ram<u16>,
	kernal: Rom<u16>,
	basic: Rom<u16>,
	characters: Rom<u16>,
}

impl C64Memory {
	fn new () -> C64Memory {
		C64Memory {
			ram: Ram::new(),
			kernal: Rom::new(&Path::new("kernal.rom")),
			basic: Rom::new(&Path::new("basic.rom")),
			characters: Rom::new(&Path::new("characters.rom")),
		}
	}
}

impl Addressable<u16> for C64Memory {
	fn get (&self, addr: u16) -> u8 {
		match addr {
			// TODO: Switch memory access based on LORAM/HIRAM/CHAREN
			0xa000..0xbfff => self.basic.get(addr - 0xa000),
			0xd000..0xdfff => self.characters.get(addr - 0xd000),
			0xe000..0xffff => self.kernal.get(addr - 0xe000),
			_              => self.ram.get(addr),
		}
	}

	fn set (&mut self, addr: u16, data: u8) {
		self.ram.set(addr, data);
	}
}

pub struct C64 {
	priv cpu: Mos6510,
	priv mem: C64Memory,
}

impl C64 {
	pub fn new () -> C64 {
		C64 {
			cpu: Mos6510::new(),
			mem: C64Memory::new(),
		}
	}

	pub fn run (&mut self) {
		// TODO
	}
}
<commit_msg>Fix C64 ROM paths<commit_after>#[desc = "C64 emulator"];
#[copyright = "Andreas Neuhaus <info@zargony.com>"];
#[license = "MIT"];

use cpu::mos65xx::Mos6510;
use mem::{Addressable, Ram, Rom};

pub mod cpu {
	pub mod mos65xx;
}
pub mod mem;

fn main () {
	let mut c64 = C64::new();
	c64.run();
}

// General information on C64 : http://unusedino.de/ec64/technical/aay/c64/
// Useful emulator information: http://emudocs.org/?page=Commodore%2064
// C64 memory map overview: http://www.c64-wiki.com/index.php/Memory_Map
// Details about the PLA: http://www.c64-wiki.de/index.php/PLA_(C64-Chip)
// Even more PLA details: http://skoe.de/docs/c64-dissected/pla/c64_pla_dissected_r1.1_a4ss.pdf

// 64K RAM (not every part is always accessible)
// 8K BASIC ROM at $A000
// 4K character ROM at $D000
// 8K kernal ROM at $E000

struct C64Memory {
	ram: Ram<u16>,
	kernal: Rom<u16>,
	basic: Rom<u16>,
	characters: Rom<u16>,
}

impl C64Memory {
	fn new () -> C64Memory {
		C64Memory {
			ram: Ram::new(),
			kernal: Rom::new(&Path::new("c64/kernal.rom")),
			basic: Rom::new(&Path::new("c64/basic.rom")),
			characters: Rom::new(&Path::new("c64/characters.rom")),
		}
	}
}

impl Addressable<u16> for C64Memory {
	fn get (&self, addr: u16) -> u8 {
		match addr {
			// TODO: Switch memory access based on LORAM/HIRAM/CHAREN
			0xa000..0xbfff => self.basic.get(addr - 0xa000),
			0xd000..0xdfff => self.characters.get(addr - 0xd000),
			0xe000..0xffff => self.kernal.get(addr - 0xe000),
			_              => self.ram.get(addr),
		}
	}

	fn set (&mut self, addr: u16, data: u8) {
		self.ram.set(addr, data);
	}
}

pub struct C64 {
	priv cpu: Mos6510,
	priv mem: C64Memory,
}

impl C64 {
	pub fn new () -> C64 {
		C64 {
			cpu: Mos6510::new(),
			mem: C64Memory::new(),
		}
	}

	pub fn run (&mut self) {
		// TODO
	}
}
<|endoftext|>


<commit_before>extern crate termion;

use termion::{TermRead, TermWrite, IntoRawMode, Color, Style, Key};
use termion::terminal_size;
use std::io::{Read, Write, Stdout, Stdin};
use std::io::{stdout, stdin};
use std;

use utility::string::*;
use model::ListTopicItem;

pub struct Index {
    title: String,
    selected_topic_index: usize,
}

impl Index {
    pub fn new() -> Self {
        Index {
            title: String::from("高登"),
            selected_topic_index: 0,
        }
    }

    pub fn select_topic(&mut self, index: usize) {
        self.selected_topic_index = index;
    }

    pub fn get_selected_topic(&self) -> usize {
        self.selected_topic_index
    }

    pub fn print(&mut self, stdout: &mut termion::RawTerminal<std::io::StdoutLock>, collection: &Vec<ListTopicItem>) {

        if self.selected_topic_index > self.body_height() {
            self.selected_topic_index = self.body_height();
        }

        let width = terminal_size().unwrap().0 as usize;

        print_header(stdout, width as usize, &self.title);
        print_body(stdout,
                   self.body_width(),
                   2,
                   self.body_height(),
                   &collection,
                   self.selected_topic_index);
    }

    pub fn body_height(&self) -> usize {

        let h = terminal_size().unwrap().1;

        if h >= 3 {
            h as usize - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {

        let w = terminal_size().unwrap().0;

        if w >= 2 {
            w as usize - 2
        } else {
            0
        }
    }

}

fn print_header(stdout: &mut termion::RawTerminal<std::io::StdoutLock>, width: usize, text: &str) {
    // print header
    let padding = ((width - text.len()) / 2) as u16;
    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    stdout.goto(padding, 0).unwrap();
    stdout.color(Color::White).unwrap();
    stdout.bg_color(Color::Black).unwrap();
    stdout.style(Style::Bold).unwrap();
    stdout.write(text.as_bytes()).unwrap();

    stdout.goto(0, 1).unwrap();
    stdout.color(Color::Yellow).unwrap();
    stdout.bg_color(Color::Black).unwrap();
    stdout.style(Style::Bold).unwrap();
    stdout.write(header_bottom.as_bytes()).unwrap();

    stdout.hide_cursor().unwrap();
    stdout.reset().unwrap();
}

fn print_body(stdout: &mut termion::RawTerminal<std::io::StdoutLock>,
    width: usize,
    offset_y: usize,
    rows: usize,
    collection: &Vec<ListTopicItem>,
    selected_topic_index: usize){

    let right_offset = 3;
    let author_max_width = 12;
    let no_max_width = 5;
    let title_max_width = width - no_max_width - author_max_width - right_offset;

    for (i, item) in collection.iter().take(rows).enumerate() {

        let original_title = item.title.text.clone();
        let title: String = substring(&original_title, title_max_width);
        let title_len = jks_len(&title);

        let title_spacin_minus = no_max_width + title_len + author_max_width + right_offset;
        let title_spacing_width = if width > title_spacin_minus {
            width - title_spacin_minus
        } else {
            0
        };
        let title_spacing = (0..title_spacing_width).map(|_| " ").collect::<Vec<_>>().join("");

        let author = item.author.name.clone();
        let author_spacing_width = author_max_width - jks_len(&author) + right_offset;
        let author_spacing = (0..author_spacing_width).map(|_| " ").collect::<Vec<_>>().join("");

        if selected_topic_index == i + 1 {
            stdout.goto(0, (i + offset_y) as u16).unwrap();
            stdout.color(Color::Black).unwrap();
            stdout.bg_color(Color::Yellow).unwrap();
            stdout.style(Style::Reset).unwrap();
            stdout.write(&format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
                     no = i + 1,
                     title = title,
                     title_spacing = title_spacing,
                     author = &author,
                     author_spacing = author_spacing).as_bytes()).unwrap();

            // rustbox.print(0,
            //               i + offset_y,
            //               rustbox::RB_NORMAL,
            //               Color::Black,
            //               Color::Yellow,
            //               &format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
            //                        no = i + 1,
            //                        title = title,
            //                        title_spacing = title_spacing,
            //                        author = &author,
            //                        author_spacing = author_spacing));
        } else {

            stdout.goto(0, (i + offset_y) as u16).unwrap();
            stdout.color(Color::White).unwrap();
            stdout.bg_color(Color::Black).unwrap();
            stdout.style(Style::Reset).unwrap();
            stdout.write(&format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
                     no = i + 1,
                     title = title,
                     title_spacing = title_spacing,
                     author = &author,
                     author_spacing = author_spacing).as_bytes()).unwrap();

            // rustbox.print(0,
            //               i + offset_y,
            //               rustbox::RB_NORMAL,
            //               Color::White,
            //               Color::Black,
            //               &format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
            //                        no = i + 1,
            //                        title = title,
            //                        title_spacing = title_spacing,
            //                        author = &author,
            //                        author_spacing = author_spacing));
            stdout.hide_cursor().unwrap();
            stdout.reset().unwrap();
        }

    }
}
<commit_msg>[FIX] index highlight is not working<commit_after>extern crate termion;

use termion::{TermRead, TermWrite, IntoRawMode, Color, Style, Key};
use termion::terminal_size;
use std::io::{Read, Write, Stdout, Stdin};
use std::io::{stdout, stdin};
use std;

use utility::string::*;
use model::ListTopicItem;

pub struct Index {
    title: String,
    selected_topic_index: usize,
}

impl Index {
    pub fn new() -> Self {
        Index {
            title: String::from("高登"),
            selected_topic_index: 0,
        }
    }

    pub fn select_topic(&mut self, index: usize) {
        self.selected_topic_index = index;
    }

    pub fn get_selected_topic(&self) -> usize {
        self.selected_topic_index
    }

    pub fn print(&mut self, stdout: &mut termion::RawTerminal<std::io::StdoutLock>, collection: &Vec<ListTopicItem>) {

        if self.selected_topic_index > self.body_height() {
            self.selected_topic_index = self.body_height();
        }

        let width = terminal_size().unwrap().0 as usize;

        print_header(stdout, width as usize, &self.title);
        print_body(stdout,
                   self.body_width(),
                   2,
                   self.body_height(),
                   &collection,
                   self.selected_topic_index);
    }

    pub fn body_height(&self) -> usize {

        let h = terminal_size().unwrap().1;

        if h >= 3 {
            h as usize - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {

        let w = terminal_size().unwrap().0;

        if w >= 2 {
            w as usize - 2
        } else {
            0
        }
    }

}

fn print_header(stdout: &mut termion::RawTerminal<std::io::StdoutLock>, width: usize, text: &str) {
    // print header
    let padding = ((width - text.len()) / 2) as u16;
    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    stdout.goto(padding, 0).unwrap();
    stdout.color(Color::White).unwrap();
    stdout.bg_color(Color::Black).unwrap();
    stdout.style(Style::Bold).unwrap();
    stdout.write(text.as_bytes()).unwrap();

    stdout.goto(0, 1).unwrap();
    stdout.color(Color::Yellow).unwrap();
    stdout.bg_color(Color::Black).unwrap();
    stdout.style(Style::Bold).unwrap();
    stdout.write(header_bottom.as_bytes()).unwrap();

    stdout.hide_cursor().unwrap();
    stdout.reset().unwrap();
}

fn print_body(stdout: &mut termion::RawTerminal<std::io::StdoutLock>,
    width: usize,
    offset_y: usize,
    rows: usize,
    collection: &Vec<ListTopicItem>,
    selected_topic_index: usize){

    let right_offset = 3;
    let author_max_width = 12;
    let no_max_width = 5;
    let title_max_width = width - no_max_width - author_max_width - right_offset;

    for (i, item) in collection.iter().take(rows).enumerate() {

        let original_title = item.title.text.clone();
        let title: String = substring(&original_title, title_max_width);
        let title_len = jks_len(&title);

        let title_spacin_minus = no_max_width + title_len + author_max_width + right_offset;
        let title_spacing_width = if width > title_spacin_minus {
            width - title_spacin_minus
        } else {
            0
        };
        let title_spacing = (0..title_spacing_width).map(|_| " ").collect::<Vec<_>>().join("");

        let author = item.author.name.clone();
        let author_spacing_width = author_max_width - jks_len(&author) + right_offset;
        let author_spacing = (0..author_spacing_width).map(|_| " ").collect::<Vec<_>>().join("");

        if selected_topic_index == i + 1 {
            stdout.goto(0, (i + offset_y) as u16).unwrap();
            stdout.style(Style::Reset).unwrap();
            stdout.color(Color::Black).unwrap();
            stdout.bg_color(Color::Yellow).unwrap();
            stdout.write(&format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
                     no = i + 1,
                     title = title,
                     title_spacing = title_spacing,
                     author = &author,
                     author_spacing = author_spacing).as_bytes()).unwrap();

            // rustbox.print(0,
            //               i + offset_y,
            //               rustbox::RB_NORMAL,
            //               Color::Black,
            //               Color::Yellow,
            //               &format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
            //                        no = i + 1,
            //                        title = title,
            //                        title_spacing = title_spacing,
            //                        author = &author,
            //                        author_spacing = author_spacing));
        } else {

            stdout.goto(0, (i + offset_y) as u16).unwrap();
            stdout.style(Style::Reset).unwrap();
            stdout.color(Color::White).unwrap();
            stdout.bg_color(Color::Black).unwrap();
            stdout.write(&format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
                     no = i + 1,
                     title = title,
                     title_spacing = title_spacing,
                     author = &author,
                     author_spacing = author_spacing).as_bytes()).unwrap();

            // rustbox.print(0,
            //               i + offset_y,
            //               rustbox::RB_NORMAL,
            //               Color::White,
            //               Color::Black,
            //               &format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
            //                        no = i + 1,
            //                        title = title,
            //                        title_spacing = title_spacing,
            //                        author = &author,
            //                        author_spacing = author_spacing));
            stdout.hide_cursor().unwrap();
            stdout.reset().unwrap();
        }

    }
}
<|endoftext|>


<commit_before>use core::cmp::Eq;

pub trait Dimensional<T>: Eq, Index<uint, T> {
    static pure fn dim() -> uint;
    pure fn to_ptr() -> *T;
}<commit_msg>Remove Eq from dimensional trait<commit_after>use core::cmp::Eq;

pub trait Dimensional<T>: Index<uint, T> {
    static pure fn dim() -> uint;
    pure fn to_ptr() -> *T;
}<|endoftext|>


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

//! A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
//! and margins in CSS.

use length::Length;
use num::Zero;
use core::fmt;
use core::ops::{Add, Neg};
use core::marker::PhantomData;
use core::cmp::{Eq, PartialEq};
use core::hash::{Hash};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::Vector2D;

/// A group of 2D side offsets, which correspond to top/left/bottom/right for borders, padding,
/// and margins in CSS, optionally tagged with a unit.
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")))]
pub struct SideOffsets2D<T, U> {
    pub top: T,
    pub right: T,
    pub bottom: T,
    pub left: T,
    #[doc(hidden)]
    pub _unit: PhantomData<U>,
}

impl<T: Copy, U> Copy for SideOffsets2D<T, U> {}

impl<T: Clone, U> Clone for SideOffsets2D<T, U> {
    fn clone(&self) -> Self {
        SideOffsets2D {
            top: self.top.clone(),
            right: self.right.clone(),
            bottom: self.bottom.clone(),
            left: self.left.clone(),
            _unit: PhantomData,
        }
    }
}

impl<T, U> Eq for SideOffsets2D<T, U> where T: Eq {}

impl<T, U> PartialEq for SideOffsets2D<T, U>
    where T: PartialEq
{
    fn eq(&self, other: &Self) -> bool {
        self.top == other.top &&
            self.right == other.right &&
            self.bottom == other.bottom &&
            self.left == other.left
    }
}

impl<T, U> Hash for SideOffsets2D<T, U>
    where T: Hash
{
    fn hash<H: ::core::hash::Hasher>(&self, h: &mut H) {
        self.top.hash(h);
        self.right.hash(h);
        self.bottom.hash(h);
        self.left.hash(h);
    }
}

impl<T: fmt::Debug, U> fmt::Debug for SideOffsets2D<T, U> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "({:?},{:?},{:?},{:?})",
            self.top, self.right, self.bottom, self.left
        )
    }
}

impl<T: Default, U> Default for SideOffsets2D<T, U> {
    fn default() -> Self {
        SideOffsets2D {
            top: Default::default(),
            right: Default::default(),
            bottom: Default::default(),
            left: Default::default(),
            _unit: PhantomData,
        }
    }
}

impl<T, U> SideOffsets2D<T, U> {
    /// Constructor taking a scalar for each side.
    pub const fn new(top: T, right: T, bottom: T, left: T) -> Self {
        SideOffsets2D {
            top,
            right,
            bottom,
            left,
            _unit: PhantomData,
        }
    }

    /// Constructor taking a typed Length for each side.
    pub fn from_lengths(
        top: Length<T, U>,
        right: Length<T, U>,
        bottom: Length<T, U>,
        left: Length<T, U>,
    ) -> Self {
        SideOffsets2D::new(top.0, right.0, bottom.0, left.0)
    }

    /// Construct side offsets from min and a max vector offsets.
    ///
    /// The outer rect of the resulting side offsets is equivalent to translating
    /// a rectangle's upper-left corner with the min vector and translating the
    /// bottom-right corner with the max vector.
    pub fn from_vectors_outer(min: Vector2D<T, U>, max: Vector2D<T,U>) -> Self
    where
        T: Neg<Output = T>
    {
        SideOffsets2D {
            left: -min.x,
            top: -min.y,
            right: max.x,
            bottom: max.y,
            _unit: PhantomData,
        }
    }

    /// Construct side offsets from min and a max vector offsets.
    ///
    /// The inner rect of the resulting side offsets is equivalent to translating
    /// a rectangle's upper-left corner with the min vector and translating the
    /// bottom-right corner with the max vector.
    pub fn from_vectors_inner(min: Vector2D<T, U>, max: Vector2D<T,U>) -> Self
    where
        T: Neg<Output = T>
    {
        SideOffsets2D {
            left: min.x,
            top: min.y,
            right: -max.x,
            bottom: -max.y,
            _unit: PhantomData,
        }
    }
}

impl<T: Copy, U> SideOffsets2D<T, U> {
    /// Constructor setting the same value to all sides, taking a scalar value directly.
    pub fn new_all_same(all: T) -> Self {
        SideOffsets2D::new(all, all, all, all)
    }

    /// Constructor setting the same value to all sides, taking a typed Length.
    pub fn from_length_all_same(all: Length<T, U>) -> Self {
        SideOffsets2D::new_all_same(all.0)
    }
}

impl<T, U> SideOffsets2D<T, U>
where
    T: Add<T, Output = T> + Copy,
{
    pub fn horizontal(&self) -> T {
        self.left + self.right
    }

    pub fn vertical(&self) -> T {
        self.top + self.bottom
    }
}

impl<T, U> Add for SideOffsets2D<T, U>
where
    T: Add<T, Output = T>,
{
    type Output = Self;
    fn add(self, other: Self) -> Self {
        SideOffsets2D::new(
            self.top + other.top,
            self.right + other.right,
            self.bottom + other.bottom,
            self.left + other.left,
        )
    }
}

impl<T: Zero, U> SideOffsets2D<T, U> {
    /// Constructor, setting all sides to zero.
    pub fn zero() -> Self {
        SideOffsets2D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero())
    }
}

#[test]
fn from_vectors() {
    use crate::{vec2, point2};
    type Box2D = crate::default::Box2D<i32>;

    let b = Box2D {
        min: point2(10, 10),
        max: point2(20, 20),
    };

    let outer = b.outer_box(SideOffsets2D::from_vectors_outer(vec2(-1, -2), vec2(3, 4)));
    let inner = b.inner_box(SideOffsets2D::from_vectors_inner(vec2(1, 2), vec2(-3, -4)));

    assert_eq!(outer, Box2D { min: point2(9, 8), max: point2(23, 24) });
    assert_eq!(inner, Box2D { min: point2(11, 12), max: point2(17, 16) });
}
<commit_msg>Consolidate the doc around confusing side offset constructor.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
//! and margins in CSS.

use length::Length;
use num::Zero;
use core::fmt;
use core::ops::{Add, Neg};
use core::marker::PhantomData;
use core::cmp::{Eq, PartialEq};
use core::hash::{Hash};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::Vector2D;

/// A group of 2D side offsets, which correspond to top/right/bottom/left for borders, padding,
/// and margins in CSS, optionally tagged with a unit.
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")))]
pub struct SideOffsets2D<T, U> {
    pub top: T,
    pub right: T,
    pub bottom: T,
    pub left: T,
    #[doc(hidden)]
    pub _unit: PhantomData<U>,
}

impl<T: Copy, U> Copy for SideOffsets2D<T, U> {}

impl<T: Clone, U> Clone for SideOffsets2D<T, U> {
    fn clone(&self) -> Self {
        SideOffsets2D {
            top: self.top.clone(),
            right: self.right.clone(),
            bottom: self.bottom.clone(),
            left: self.left.clone(),
            _unit: PhantomData,
        }
    }
}

impl<T, U> Eq for SideOffsets2D<T, U> where T: Eq {}

impl<T, U> PartialEq for SideOffsets2D<T, U>
    where T: PartialEq
{
    fn eq(&self, other: &Self) -> bool {
        self.top == other.top &&
            self.right == other.right &&
            self.bottom == other.bottom &&
            self.left == other.left
    }
}

impl<T, U> Hash for SideOffsets2D<T, U>
    where T: Hash
{
    fn hash<H: ::core::hash::Hasher>(&self, h: &mut H) {
        self.top.hash(h);
        self.right.hash(h);
        self.bottom.hash(h);
        self.left.hash(h);
    }
}

impl<T: fmt::Debug, U> fmt::Debug for SideOffsets2D<T, U> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "({:?},{:?},{:?},{:?})",
            self.top, self.right, self.bottom, self.left
        )
    }
}

impl<T: Default, U> Default for SideOffsets2D<T, U> {
    fn default() -> Self {
        SideOffsets2D {
            top: Default::default(),
            right: Default::default(),
            bottom: Default::default(),
            left: Default::default(),
            _unit: PhantomData,
        }
    }
}

impl<T, U> SideOffsets2D<T, U> {
    /// Constructor taking a scalar for each side.
    ///
    /// Sides are specified in top-right-bottom-left order following
    /// CSS's convention.
    pub const fn new(top: T, right: T, bottom: T, left: T) -> Self {
        SideOffsets2D {
            top,
            right,
            bottom,
            left,
            _unit: PhantomData,
        }
    }

    /// Constructor taking a typed Length for each side.
    ///
    /// Sides are specified in top-right-bottom-left order following
    /// CSS's convention.
    pub fn from_lengths(
        top: Length<T, U>,
        right: Length<T, U>,
        bottom: Length<T, U>,
        left: Length<T, U>,
    ) -> Self {
        SideOffsets2D::new(top.0, right.0, bottom.0, left.0)
    }

    /// Construct side offsets from min and a max vector offsets.
    ///
    /// The outer rect of the resulting side offsets is equivalent to translating
    /// a rectangle's upper-left corner with the min vector and translating the
    /// bottom-right corner with the max vector.
    pub fn from_vectors_outer(min: Vector2D<T, U>, max: Vector2D<T,U>) -> Self
    where
        T: Neg<Output = T>
    {
        SideOffsets2D {
            left: -min.x,
            top: -min.y,
            right: max.x,
            bottom: max.y,
            _unit: PhantomData,
        }
    }

    /// Construct side offsets from min and a max vector offsets.
    ///
    /// The inner rect of the resulting side offsets is equivalent to translating
    /// a rectangle's upper-left corner with the min vector and translating the
    /// bottom-right corner with the max vector.
    pub fn from_vectors_inner(min: Vector2D<T, U>, max: Vector2D<T,U>) -> Self
    where
        T: Neg<Output = T>
    {
        SideOffsets2D {
            left: min.x,
            top: min.y,
            right: -max.x,
            bottom: -max.y,
            _unit: PhantomData,
        }
    }
}

impl<T: Copy, U> SideOffsets2D<T, U> {
    /// Constructor setting the same value to all sides, taking a scalar value directly.
    pub fn new_all_same(all: T) -> Self {
        SideOffsets2D::new(all, all, all, all)
    }

    /// Constructor setting the same value to all sides, taking a typed Length.
    pub fn from_length_all_same(all: Length<T, U>) -> Self {
        SideOffsets2D::new_all_same(all.0)
    }
}

impl<T, U> SideOffsets2D<T, U>
where
    T: Add<T, Output = T> + Copy,
{
    pub fn horizontal(&self) -> T {
        self.left + self.right
    }

    pub fn vertical(&self) -> T {
        self.top + self.bottom
    }
}

impl<T, U> Add for SideOffsets2D<T, U>
where
    T: Add<T, Output = T>,
{
    type Output = Self;
    fn add(self, other: Self) -> Self {
        SideOffsets2D::new(
            self.top + other.top,
            self.right + other.right,
            self.bottom + other.bottom,
            self.left + other.left,
        )
    }
}

impl<T: Zero, U> SideOffsets2D<T, U> {
    /// Constructor, setting all sides to zero.
    pub fn zero() -> Self {
        SideOffsets2D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero())
    }
}

#[test]
fn from_vectors() {
    use crate::{vec2, point2};
    type Box2D = crate::default::Box2D<i32>;

    let b = Box2D {
        min: point2(10, 10),
        max: point2(20, 20),
    };

    let outer = b.outer_box(SideOffsets2D::from_vectors_outer(vec2(-1, -2), vec2(3, 4)));
    let inner = b.inner_box(SideOffsets2D::from_vectors_inner(vec2(1, 2), vec2(-3, -4)));

    assert_eq!(outer, Box2D { min: point2(9, 8), max: point2(23, 24) });
    assert_eq!(inner, Box2D { min: point2(11, 12), max: point2(17, 16) });
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use interner::StringKey;
use std::fmt;

#[derive(PartialEq, Debug, Ord, PartialOrd, Eq, Clone)]
pub enum Type {
    Named(StringKey),
    List(Box<Type>),
    NonNull(Box<Type>),
}

impl Type {
    pub fn inner(&self) -> Type {
        match self {
            Type::Named(t) => Type::Named(*t),
            Type::List(of) => of.inner(),
            Type::NonNull(of) => of.inner(),
        }
    }
}

#[derive(PartialEq, Debug)]
pub enum TypeSystemDefinition {
    SchemaDefinition {
        directives: Vec<Directive>,
        operation_types: Vec<OperationTypeDefinition>,
    },
    ObjectTypeExtension {
        name: StringKey,
        interfaces: Vec<StringKey>,
        fields: Vec<FieldDefinition>,
        directives: Vec<Directive>,
    },
    ObjectTypeDefinition {
        name: StringKey,
        interfaces: Vec<StringKey>,
        fields: Vec<FieldDefinition>,
        directives: Vec<Directive>,
    },
    InterfaceTypeDefinition {
        name: StringKey,
        interfaces: Vec<StringKey>,
        fields: Vec<FieldDefinition>,
        directives: Vec<Directive>,
    },
    InterfaceTypeExtension {
        name: StringKey,
        fields: Vec<FieldDefinition>,
        directives: Vec<Directive>,
    },
    UnionTypeDefinition {
        name: StringKey,
        directives: Vec<Directive>,
        members: Vec<StringKey>,
    },
    DirectiveDefinition {
        name: StringKey,
        arguments: Vec<InputValueDefinition>,
        repeatable: bool,
        locations: Vec<DirectiveLocation>,
    },
    InputObjectTypeDefinition {
        name: StringKey,
        directives: Vec<Directive>,
        fields: Vec<InputValueDefinition>,
    },
    EnumTypeDefinition {
        name: StringKey,
        directives: Vec<Directive>,
        values: Vec<EnumValueDefinition>,
    },
    ScalarTypeDefinition {
        name: StringKey,
        directives: Vec<Directive>,
    },
}

#[derive(PartialEq, Debug)]
pub struct OperationTypeDefinition {
    pub operation: OperationType,
    pub type_: StringKey,
}

#[derive(PartialEq, Debug)]
pub struct EnumValueDefinition {
    pub name: StringKey,
    pub directives: Vec<Directive>,
}

#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub enum DirectiveLocation {
    Query,
    Mutation,
    Subscription,
    Field,
    FragmentDefinition,
    FragmentSpread,
    InlineFragment,
    Schema,
    Scalar,
    Object,
    FieldDefinition,
    ArgumentDefinition,
    Interface,
    Union,
    Enum,
    EnumValue,
    InputObject,
    InputFieldDefinition,
    VariableDefinition,
}

impl fmt::Display for DirectiveLocation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DirectiveLocation::Query => write!(f, "QUERY"),
            DirectiveLocation::Mutation => write!(f, "MUTATION"),
            DirectiveLocation::Subscription => write!(f, "SUBSCRIPTION"),
            DirectiveLocation::Field => write!(f, "FIELD"),
            DirectiveLocation::FragmentDefinition => write!(f, "FRAGMENT_DEFINITION"),
            DirectiveLocation::FragmentSpread => write!(f, "FRAGMENT_SPREAD"),
            DirectiveLocation::InlineFragment => write!(f, "INLINE_FRAGMENT"),
            DirectiveLocation::Schema => write!(f, "SCHEMA"),
            DirectiveLocation::Scalar => write!(f, "SCALAR"),
            DirectiveLocation::Object => write!(f, "OBJECT"),
            DirectiveLocation::FieldDefinition => write!(f, "FIELD_DEFINITION"),
            DirectiveLocation::ArgumentDefinition => write!(f, "ARGUMENT_DEFINITION"),
            DirectiveLocation::Interface => write!(f, "INTERFACE"),
            DirectiveLocation::Union => write!(f, "UNION"),
            DirectiveLocation::Enum => write!(f, "ENUM"),
            DirectiveLocation::EnumValue => write!(f, "ENUM_VALUE"),
            DirectiveLocation::InputObject => write!(f, "INPUT_OBJECT"),
            DirectiveLocation::InputFieldDefinition => write!(f, "INPUT_FIELD_DEFINITION"),
            DirectiveLocation::VariableDefinition => write!(f, "VARIABLE_DEFINITION"),
        }
    }
}

#[derive(PartialEq, Debug, Copy, Clone)]
pub enum OperationType {
    Query,
    Mutation,
    Subscription,
}

#[derive(PartialEq, Debug, Clone)]
pub struct InputValueDefinition {
    pub name: StringKey,
    pub type_: Type,
    pub default_value: Option<Value>,
    pub directives: Vec<Directive>,
}

#[derive(PartialEq, Debug, Clone)]
pub struct FieldDefinition {
    pub name: StringKey,
    pub type_: Type,
    pub arguments: Vec<InputValueDefinition>,
    pub directives: Vec<Directive>,
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Value {
    Null,
    String(String),
    Boolean(bool),
    Enum(StringKey),
    Int(String),
    Float(String),
    List(ListValue),
    Object(ObjectValue),
}
impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Value::String(value) => write!(f, "\"{}\"", value),
            Value::Int(value) | Value::Float(value) => write!(f, "{}", value),
            Value::Boolean(value) => write!(f, "{}", value),
            Value::Enum(value) => write!(f, "{}", value),
            Value::List(value) => write!(f, "{}", value),
            Value::Object(value) => write!(f, "{}", value),
            _null => write!(f, "UNKNOWN"),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ListValue {
    pub values: Vec<Value>,
}
impl fmt::Display for ListValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[")?;
        let mut first = true;
        for item in &self.values {
            if first {
                first = false;
            } else {
                write!(f, ", ")?;
            }
            write!(f, "{}", item)?;
        }
        write!(f, "]")
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ObjectValue {
    pub fields: Vec<ObjectField>,
}
impl fmt::Display for ObjectValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{{")?;
        let mut first = true;
        for field in &self.fields {
            if first {
                first = false;
            } else {
                write!(f, ", ")?;
            }
            write!(f, "{}: {}", field.name, field.value)?;
        }
        write!(f, "}}")
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ObjectField {
    pub name: StringKey,
    pub value: Value,
}

#[derive(PartialEq, Debug, Clone)]
pub struct Argument {
    pub name: StringKey,
    pub value: Value,
}

#[derive(PartialEq, Debug, Clone)]
pub struct Directive {
    pub name: StringKey,
    pub arguments: Vec<Argument>,
}
<commit_msg>Add write_list fn to type_system_nodes<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use interner::StringKey;
use std::fmt;

#[derive(PartialEq, Debug, Ord, PartialOrd, Eq, Clone)]
pub enum Type {
    Named(StringKey),
    List(Box<Type>),
    NonNull(Box<Type>),
}

impl Type {
    pub fn inner(&self) -> Type {
        match self {
            Type::Named(t) => Type::Named(*t),
            Type::List(of) => of.inner(),
            Type::NonNull(of) => of.inner(),
        }
    }
}

#[derive(PartialEq, Debug)]
pub enum TypeSystemDefinition {
    SchemaDefinition {
        directives: Vec<Directive>,
        operation_types: Vec<OperationTypeDefinition>,
    },
    ObjectTypeExtension {
        name: StringKey,
        interfaces: Vec<StringKey>,
        fields: Vec<FieldDefinition>,
        directives: Vec<Directive>,
    },
    ObjectTypeDefinition {
        name: StringKey,
        interfaces: Vec<StringKey>,
        fields: Vec<FieldDefinition>,
        directives: Vec<Directive>,
    },
    InterfaceTypeDefinition {
        name: StringKey,
        interfaces: Vec<StringKey>,
        fields: Vec<FieldDefinition>,
        directives: Vec<Directive>,
    },
    InterfaceTypeExtension {
        name: StringKey,
        fields: Vec<FieldDefinition>,
        directives: Vec<Directive>,
    },
    UnionTypeDefinition {
        name: StringKey,
        directives: Vec<Directive>,
        members: Vec<StringKey>,
    },
    DirectiveDefinition {
        name: StringKey,
        arguments: Vec<InputValueDefinition>,
        repeatable: bool,
        locations: Vec<DirectiveLocation>,
    },
    InputObjectTypeDefinition {
        name: StringKey,
        directives: Vec<Directive>,
        fields: Vec<InputValueDefinition>,
    },
    EnumTypeDefinition {
        name: StringKey,
        directives: Vec<Directive>,
        values: Vec<EnumValueDefinition>,
    },
    ScalarTypeDefinition {
        name: StringKey,
        directives: Vec<Directive>,
    },
}

#[derive(PartialEq, Debug)]
pub struct OperationTypeDefinition {
    pub operation: OperationType,
    pub type_: StringKey,
}

#[derive(PartialEq, Debug)]
pub struct EnumValueDefinition {
    pub name: StringKey,
    pub directives: Vec<Directive>,
}

#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub enum DirectiveLocation {
    Query,
    Mutation,
    Subscription,
    Field,
    FragmentDefinition,
    FragmentSpread,
    InlineFragment,
    Schema,
    Scalar,
    Object,
    FieldDefinition,
    ArgumentDefinition,
    Interface,
    Union,
    Enum,
    EnumValue,
    InputObject,
    InputFieldDefinition,
    VariableDefinition,
}

impl fmt::Display for DirectiveLocation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DirectiveLocation::Query => write!(f, "QUERY"),
            DirectiveLocation::Mutation => write!(f, "MUTATION"),
            DirectiveLocation::Subscription => write!(f, "SUBSCRIPTION"),
            DirectiveLocation::Field => write!(f, "FIELD"),
            DirectiveLocation::FragmentDefinition => write!(f, "FRAGMENT_DEFINITION"),
            DirectiveLocation::FragmentSpread => write!(f, "FRAGMENT_SPREAD"),
            DirectiveLocation::InlineFragment => write!(f, "INLINE_FRAGMENT"),
            DirectiveLocation::Schema => write!(f, "SCHEMA"),
            DirectiveLocation::Scalar => write!(f, "SCALAR"),
            DirectiveLocation::Object => write!(f, "OBJECT"),
            DirectiveLocation::FieldDefinition => write!(f, "FIELD_DEFINITION"),
            DirectiveLocation::ArgumentDefinition => write!(f, "ARGUMENT_DEFINITION"),
            DirectiveLocation::Interface => write!(f, "INTERFACE"),
            DirectiveLocation::Union => write!(f, "UNION"),
            DirectiveLocation::Enum => write!(f, "ENUM"),
            DirectiveLocation::EnumValue => write!(f, "ENUM_VALUE"),
            DirectiveLocation::InputObject => write!(f, "INPUT_OBJECT"),
            DirectiveLocation::InputFieldDefinition => write!(f, "INPUT_FIELD_DEFINITION"),
            DirectiveLocation::VariableDefinition => write!(f, "VARIABLE_DEFINITION"),
        }
    }
}

#[derive(PartialEq, Debug, Copy, Clone)]
pub enum OperationType {
    Query,
    Mutation,
    Subscription,
}

#[derive(PartialEq, Debug, Clone)]
pub struct InputValueDefinition {
    pub name: StringKey,
    pub type_: Type,
    pub default_value: Option<Value>,
    pub directives: Vec<Directive>,
}

#[derive(PartialEq, Debug, Clone)]
pub struct FieldDefinition {
    pub name: StringKey,
    pub type_: Type,
    pub arguments: Vec<InputValueDefinition>,
    pub directives: Vec<Directive>,
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Value {
    Null,
    String(String),
    Boolean(bool),
    Enum(StringKey),
    Int(String),
    Float(String),
    List(ListValue),
    Object(ObjectValue),
}
impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Value::String(value) => write!(f, "\"{}\"", value),
            Value::Int(value) | Value::Float(value) => write!(f, "{}", value),
            Value::Boolean(value) => write!(f, "{}", value),
            Value::Enum(value) => write!(f, "{}", value),
            Value::List(value) => write!(f, "{}", value),
            Value::Object(value) => write!(f, "{}", value),
            _null => write!(f, "UNKNOWN"),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ListValue {
    pub values: Vec<Value>,
}
impl fmt::Display for ListValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[")?;
        write_list(f, &self.values, ", ")?;
        write!(f, "]")
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ObjectValue {
    pub fields: Vec<ObjectField>,
}
impl fmt::Display for ObjectValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{{")?;
        write_list(f, &self.fields, ", ")?;
        write!(f, "}}")
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ObjectField {
    pub name: StringKey,
    pub value: Value,
}

impl fmt::Display for ObjectField {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}", self.name, self.value)
    }
}

#[derive(PartialEq, Debug, Clone)]
pub struct Argument {
    pub name: StringKey,
    pub value: Value,
}

#[derive(PartialEq, Debug, Clone)]
pub struct Directive {
    pub name: StringKey,
    pub arguments: Vec<Argument>,
}

fn write_list(
    f: &mut fmt::Formatter<'_>,
    list: &[impl fmt::Display],
    separator: &str,
) -> fmt::Result {
    let v = list
        .iter()
        .map(|elem| elem.to_string())
        .collect::<Vec<String>>()
        .join(separator);
    write!(f, "{}", v)
}
<|endoftext|>


<commit_before>//! Simplifying Candidates
//!
//! *Simplifying* a match pair `place @ pattern` means breaking it down
//! into bindings or other, simpler match pairs. For example:
//!
//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
//! - `place @ x` can be simplified to `[]` by binding `x` to `place`
//!
//! The `simplify_candidate` routine just repeatedly applies these
//! sort of simplifications until there is nothing left to
//! simplify. Match pairs cannot be simplified if they require some
//! sort of test: for example, testing which variant an enum is, or
//! testing a value against a constant.

use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
use crate::build::Builder;
use crate::thir::{self, *};
use rustc_attr::{SignedInt, UnsignedInt};
use rustc_hir::RangeEnd;
use rustc_middle::mir::Place;
use rustc_middle::ty;
use rustc_middle::ty::layout::IntegerExt;
use rustc_target::abi::{Integer, Size};

use std::mem;

impl<'a, 'tcx> Builder<'a, 'tcx> {
    /// Simplify a candidate so that all match pairs require a test.
    ///
    /// This method will also split a candidate, in which the only
    /// match-pair is an or-pattern, into multiple candidates.
    /// This is so that
    ///
    /// match x {
    ///     0 | 1 => { ... },
    ///     2 | 3 => { ... },
    /// }
    ///
    /// only generates a single switch. If this happens this method returns
    /// `true`.
    pub(super) fn simplify_candidate<'pat>(
        &mut self,
        candidate: &mut Candidate<'pat, 'tcx>,
    ) -> bool {
        // repeatedly simplify match pairs until fixed point is reached
        debug!(?candidate, "simplify_candidate");

        // existing_bindings and new_bindings exists to keep the semantics in order.
        // Reversing the binding order for bindings after `@` changes the binding order in places
        // it shouldn't be changed, for example `let (Some(a), Some(b)) = (x, y)`
        //
        // To avoid this, the binding occurs in the following manner:
        // * the bindings for one iteration of the following loop occurs in order (i.e. left to
        // right)
        // * the bindings from the previous iteration of the loop is prepended to the bindings from
        // the current iteration (in the implementation this is done by mem::swap and extend)
        // * after all iterations, these new bindings are then appended to the bindings that were
        // prexisting (i.e. `candidate.binding` when the function was called).
        //
        // example:
        // candidate.bindings = [1, 2, 3]
        // binding in iter 1: [4, 5]
        // binding in iter 2: [6, 7]
        //
        // final binding: [1, 2, 3, 6, 7, 4, 5]
        let mut existing_bindings = mem::take(&mut candidate.bindings);
        let mut new_bindings = Vec::new();
        loop {
            let match_pairs = mem::take(&mut candidate.match_pairs);

            if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, place }] =
                *match_pairs
            {
                existing_bindings.extend_from_slice(&new_bindings);
                mem::swap(&mut candidate.bindings, &mut existing_bindings);
                candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats);
                return true;
            }

            let mut changed = false;
            for match_pair in match_pairs {
                match self.simplify_match_pair(match_pair, candidate) {
                    Ok(()) => {
                        changed = true;
                    }
                    Err(match_pair) => {
                        candidate.match_pairs.push(match_pair);
                    }
                }
            }
            // Avoid issue #69971: the binding order should be right to left if there are more
            // bindings after `@` to please the borrow checker
            // Ex
            // struct NonCopyStruct {
            //     copy_field: u32,
            // }
            //
            // fn foo1(x: NonCopyStruct) {
            //     let y @ NonCopyStruct { copy_field: z } = x;
            //     // the above should turn into
            //     let z = x.copy_field;
            //     let y = x;
            // }
            candidate.bindings.extend_from_slice(&new_bindings);
            mem::swap(&mut candidate.bindings, &mut new_bindings);
            candidate.bindings.clear();

            if !changed {
                existing_bindings.extend_from_slice(&new_bindings);
                mem::swap(&mut candidate.bindings, &mut existing_bindings);
                // Move or-patterns to the end, because they can result in us
                // creating additional candidates, so we want to test them as
                // late as possible.
                candidate
                    .match_pairs
                    .sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. }));
                debug!(simplified = ?candidate, "simplify_candidate");
                return false; // if we were not able to simplify any, done.
            }
        }
    }

    /// Given `candidate` that has a single or-pattern for its match-pairs,
    /// creates a fresh candidate for each of its input subpatterns passed via
    /// `pats`.
    fn create_or_subcandidates<'pat>(
        &mut self,
        candidate: &Candidate<'pat, 'tcx>,
        place: Place<'tcx>,
        pats: &'pat [Pat<'tcx>],
    ) -> Vec<Candidate<'pat, 'tcx>> {
        pats.iter()
            .map(|pat| {
                let mut candidate = Candidate::new(place, pat, candidate.has_guard);
                self.simplify_candidate(&mut candidate);
                candidate
            })
            .collect()
    }

    /// Tries to simplify `match_pair`, returning `Ok(())` if
    /// successful. If successful, new match pairs and bindings will
    /// have been pushed into the candidate. If no simplification is
    /// possible, `Err` is returned and no changes are made to
    /// candidate.
    fn simplify_match_pair<'pat>(
        &mut self,
        match_pair: MatchPair<'pat, 'tcx>,
        candidate: &mut Candidate<'pat, 'tcx>,
    ) -> Result<(), MatchPair<'pat, 'tcx>> {
        let tcx = self.hir.tcx();
        match *match_pair.pattern.kind {
            PatKind::AscribeUserType {
                ref subpattern,
                ascription: thir::pattern::Ascription { variance, user_ty, user_ty_span },
            } => {
                // Apply the type ascription to the value at `match_pair.place`, which is the
                // value being matched, taking the variance field into account.
                candidate.ascriptions.push(Ascription {
                    span: user_ty_span,
                    user_ty,
                    source: match_pair.place,
                    variance,
                });

                candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));

                Ok(())
            }

            PatKind::Wild => {
                // nothing left to do
                Ok(())
            }

            PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => {
                candidate.bindings.push(Binding {
                    name,
                    mutability,
                    span: match_pair.pattern.span,
                    source: match_pair.place,
                    var_id: var,
                    var_ty: ty,
                    binding_mode: mode,
                });

                if let Some(subpattern) = subpattern.as_ref() {
                    // this is the `x @ P` case; have to keep matching against `P` now
                    candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
                }

                Ok(())
            }

            PatKind::Constant { .. } => {
                // FIXME normalize patterns when possible
                Err(match_pair)
            }

            PatKind::Range(PatRange { lo, hi, end }) => {
                let (range, bias) = match *lo.ty.kind() {
                    ty::Char => {
                        (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
                    }
                    ty::Int(ity) => {
                        let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
                        let max = size.truncate(u128::MAX);
                        let bias = 1u128 << (size.bits() - 1);
                        (Some((0, max, size)), bias)
                    }
                    ty::Uint(uty) => {
                        let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
                        let max = size.truncate(u128::MAX);
                        (Some((0, max, size)), 0)
                    }
                    _ => (None, 0),
                };
                if let Some((min, max, sz)) = range {
                    if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
                        // We want to compare ranges numerically, but the order of the bitwise
                        // representation of signed integers does not match their numeric order.
                        // Thus, to correct the ordering, we need to shift the range of signed
                        // integers to correct the comparison. This is achieved by XORing with a
                        // bias (see pattern/_match.rs for another pertinent example of this
                        // pattern).
                        let (lo, hi) = (lo ^ bias, hi ^ bias);
                        if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
                            // Irrefutable pattern match.
                            return Ok(());
                        }
                    }
                }
                Err(match_pair)
            }

            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
                    // irrefutable
                    self.prefix_slice_suffix(
                        &mut candidate.match_pairs,
                        &match_pair.place,
                        prefix,
                        slice.as_ref(),
                        suffix,
                    );
                    Ok(())
                } else {
                    Err(match_pair)
                }
            }

            PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
                let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
                    i == variant_index || {
                        self.hir.tcx().features().exhaustive_patterns
                            && !v
                                .uninhabited_from(
                                    self.hir.tcx(),
                                    substs,
                                    adt_def.adt_kind(),
                                    self.hir.param_env,
                                )
                                .is_empty()
                    }
                }) && (adt_def.did.is_local()
                    || !adt_def.is_variant_list_non_exhaustive());
                if irrefutable {
                    let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index);
                    candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
                    Ok(())
                } else {
                    Err(match_pair)
                }
            }

            PatKind::Array { ref prefix, ref slice, ref suffix } => {
                self.prefix_slice_suffix(
                    &mut candidate.match_pairs,
                    &match_pair.place,
                    prefix,
                    slice.as_ref(),
                    suffix,
                );
                Ok(())
            }

            PatKind::Leaf { ref subpatterns } => {
                // tuple struct, match subpats (if any)
                candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
                Ok(())
            }

            PatKind::Deref { ref subpattern } => {
                let place = tcx.mk_place_deref(match_pair.place);
                candidate.match_pairs.push(MatchPair::new(place, subpattern));
                Ok(())
            }

            PatKind::Or { .. } => Err(match_pair),
        }
    }
}
<commit_msg>Fix typo in simplify.rs<commit_after>//! Simplifying Candidates
//!
//! *Simplifying* a match pair `place @ pattern` means breaking it down
//! into bindings or other, simpler match pairs. For example:
//!
//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
//! - `place @ x` can be simplified to `[]` by binding `x` to `place`
//!
//! The `simplify_candidate` routine just repeatedly applies these
//! sort of simplifications until there is nothing left to
//! simplify. Match pairs cannot be simplified if they require some
//! sort of test: for example, testing which variant an enum is, or
//! testing a value against a constant.

use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
use crate::build::Builder;
use crate::thir::{self, *};
use rustc_attr::{SignedInt, UnsignedInt};
use rustc_hir::RangeEnd;
use rustc_middle::mir::Place;
use rustc_middle::ty;
use rustc_middle::ty::layout::IntegerExt;
use rustc_target::abi::{Integer, Size};

use std::mem;

impl<'a, 'tcx> Builder<'a, 'tcx> {
    /// Simplify a candidate so that all match pairs require a test.
    ///
    /// This method will also split a candidate, in which the only
    /// match-pair is an or-pattern, into multiple candidates.
    /// This is so that
    ///
    /// match x {
    ///     0 | 1 => { ... },
    ///     2 | 3 => { ... },
    /// }
    ///
    /// only generates a single switch. If this happens this method returns
    /// `true`.
    pub(super) fn simplify_candidate<'pat>(
        &mut self,
        candidate: &mut Candidate<'pat, 'tcx>,
    ) -> bool {
        // repeatedly simplify match pairs until fixed point is reached
        debug!(?candidate, "simplify_candidate");

        // existing_bindings and new_bindings exists to keep the semantics in order.
        // Reversing the binding order for bindings after `@` changes the binding order in places
        // it shouldn't be changed, for example `let (Some(a), Some(b)) = (x, y)`
        //
        // To avoid this, the binding occurs in the following manner:
        // * the bindings for one iteration of the following loop occurs in order (i.e. left to
        // right)
        // * the bindings from the previous iteration of the loop is prepended to the bindings from
        // the current iteration (in the implementation this is done by mem::swap and extend)
        // * after all iterations, these new bindings are then appended to the bindings that were
        // preexisting (i.e. `candidate.binding` when the function was called).
        //
        // example:
        // candidate.bindings = [1, 2, 3]
        // binding in iter 1: [4, 5]
        // binding in iter 2: [6, 7]
        //
        // final binding: [1, 2, 3, 6, 7, 4, 5]
        let mut existing_bindings = mem::take(&mut candidate.bindings);
        let mut new_bindings = Vec::new();
        loop {
            let match_pairs = mem::take(&mut candidate.match_pairs);

            if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, place }] =
                *match_pairs
            {
                existing_bindings.extend_from_slice(&new_bindings);
                mem::swap(&mut candidate.bindings, &mut existing_bindings);
                candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats);
                return true;
            }

            let mut changed = false;
            for match_pair in match_pairs {
                match self.simplify_match_pair(match_pair, candidate) {
                    Ok(()) => {
                        changed = true;
                    }
                    Err(match_pair) => {
                        candidate.match_pairs.push(match_pair);
                    }
                }
            }
            // Avoid issue #69971: the binding order should be right to left if there are more
            // bindings after `@` to please the borrow checker
            // Ex
            // struct NonCopyStruct {
            //     copy_field: u32,
            // }
            //
            // fn foo1(x: NonCopyStruct) {
            //     let y @ NonCopyStruct { copy_field: z } = x;
            //     // the above should turn into
            //     let z = x.copy_field;
            //     let y = x;
            // }
            candidate.bindings.extend_from_slice(&new_bindings);
            mem::swap(&mut candidate.bindings, &mut new_bindings);
            candidate.bindings.clear();

            if !changed {
                existing_bindings.extend_from_slice(&new_bindings);
                mem::swap(&mut candidate.bindings, &mut existing_bindings);
                // Move or-patterns to the end, because they can result in us
                // creating additional candidates, so we want to test them as
                // late as possible.
                candidate
                    .match_pairs
                    .sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. }));
                debug!(simplified = ?candidate, "simplify_candidate");
                return false; // if we were not able to simplify any, done.
            }
        }
    }

    /// Given `candidate` that has a single or-pattern for its match-pairs,
    /// creates a fresh candidate for each of its input subpatterns passed via
    /// `pats`.
    fn create_or_subcandidates<'pat>(
        &mut self,
        candidate: &Candidate<'pat, 'tcx>,
        place: Place<'tcx>,
        pats: &'pat [Pat<'tcx>],
    ) -> Vec<Candidate<'pat, 'tcx>> {
        pats.iter()
            .map(|pat| {
                let mut candidate = Candidate::new(place, pat, candidate.has_guard);
                self.simplify_candidate(&mut candidate);
                candidate
            })
            .collect()
    }

    /// Tries to simplify `match_pair`, returning `Ok(())` if
    /// successful. If successful, new match pairs and bindings will
    /// have been pushed into the candidate. If no simplification is
    /// possible, `Err` is returned and no changes are made to
    /// candidate.
    fn simplify_match_pair<'pat>(
        &mut self,
        match_pair: MatchPair<'pat, 'tcx>,
        candidate: &mut Candidate<'pat, 'tcx>,
    ) -> Result<(), MatchPair<'pat, 'tcx>> {
        let tcx = self.hir.tcx();
        match *match_pair.pattern.kind {
            PatKind::AscribeUserType {
                ref subpattern,
                ascription: thir::pattern::Ascription { variance, user_ty, user_ty_span },
            } => {
                // Apply the type ascription to the value at `match_pair.place`, which is the
                // value being matched, taking the variance field into account.
                candidate.ascriptions.push(Ascription {
                    span: user_ty_span,
                    user_ty,
                    source: match_pair.place,
                    variance,
                });

                candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));

                Ok(())
            }

            PatKind::Wild => {
                // nothing left to do
                Ok(())
            }

            PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => {
                candidate.bindings.push(Binding {
                    name,
                    mutability,
                    span: match_pair.pattern.span,
                    source: match_pair.place,
                    var_id: var,
                    var_ty: ty,
                    binding_mode: mode,
                });

                if let Some(subpattern) = subpattern.as_ref() {
                    // this is the `x @ P` case; have to keep matching against `P` now
                    candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
                }

                Ok(())
            }

            PatKind::Constant { .. } => {
                // FIXME normalize patterns when possible
                Err(match_pair)
            }

            PatKind::Range(PatRange { lo, hi, end }) => {
                let (range, bias) = match *lo.ty.kind() {
                    ty::Char => {
                        (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
                    }
                    ty::Int(ity) => {
                        let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
                        let max = size.truncate(u128::MAX);
                        let bias = 1u128 << (size.bits() - 1);
                        (Some((0, max, size)), bias)
                    }
                    ty::Uint(uty) => {
                        let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
                        let max = size.truncate(u128::MAX);
                        (Some((0, max, size)), 0)
                    }
                    _ => (None, 0),
                };
                if let Some((min, max, sz)) = range {
                    if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
                        // We want to compare ranges numerically, but the order of the bitwise
                        // representation of signed integers does not match their numeric order.
                        // Thus, to correct the ordering, we need to shift the range of signed
                        // integers to correct the comparison. This is achieved by XORing with a
                        // bias (see pattern/_match.rs for another pertinent example of this
                        // pattern).
                        let (lo, hi) = (lo ^ bias, hi ^ bias);
                        if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
                            // Irrefutable pattern match.
                            return Ok(());
                        }
                    }
                }
                Err(match_pair)
            }

            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
                    // irrefutable
                    self.prefix_slice_suffix(
                        &mut candidate.match_pairs,
                        &match_pair.place,
                        prefix,
                        slice.as_ref(),
                        suffix,
                    );
                    Ok(())
                } else {
                    Err(match_pair)
                }
            }

            PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
                let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
                    i == variant_index || {
                        self.hir.tcx().features().exhaustive_patterns
                            && !v
                                .uninhabited_from(
                                    self.hir.tcx(),
                                    substs,
                                    adt_def.adt_kind(),
                                    self.hir.param_env,
                                )
                                .is_empty()
                    }
                }) && (adt_def.did.is_local()
                    || !adt_def.is_variant_list_non_exhaustive());
                if irrefutable {
                    let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index);
                    candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
                    Ok(())
                } else {
                    Err(match_pair)
                }
            }

            PatKind::Array { ref prefix, ref slice, ref suffix } => {
                self.prefix_slice_suffix(
                    &mut candidate.match_pairs,
                    &match_pair.place,
                    prefix,
                    slice.as_ref(),
                    suffix,
                );
                Ok(())
            }

            PatKind::Leaf { ref subpatterns } => {
                // tuple struct, match subpats (if any)
                candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
                Ok(())
            }

            PatKind::Deref { ref subpattern } => {
                let place = tcx.mk_place_deref(match_pair.place);
                candidate.match_pairs.push(MatchPair::new(place, subpattern));
                Ok(())
            }

            PatKind::Or { .. } => Err(match_pair),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate rmpv;
extern crate test;

use test::Bencher;

use rmpv::decode::*;

// Encoded value: [1, 0, [[["127.0.0.1", 59074]], 1, {0: ["read", {}, {0: ["value", {}], 1: ["error", {}]}], 1: ["write", {}, {0: ["value", {}], 1: ["error", {}]}], 2: ["remove", {}, {0: ["value", {}], 1: ["error", {}]}], 3: ["find", {}, {0: ["value", {}], 1: ["error", {}]}]}], [[80, 81, 82]]].
const COMPLEX: [u8; 137] = [
    0x94, 0x01, 0x00, 0x93, 0x91, 0x92, 0xa9, 0x31,
    0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31,
    0xcd, 0xe6, 0xc2, 0x01, 0x84, 0x00, 0x93, 0xa4,
    0x72, 0x65, 0x61, 0x64, 0x80, 0x82, 0x00, 0x92,
    0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80, 0x01,
    0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x80,
    0x01, 0x93, 0xa5, 0x77, 0x72, 0x69, 0x74, 0x65,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x02, 0x93, 0xa6, 0x72,
    0x65, 0x6d, 0x6f, 0x76, 0x65, 0x80, 0x82, 0x00,
    0x92, 0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80,
    0x01, 0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72,
    0x80, 0x03, 0x93, 0xa4, 0x66, 0x69, 0x6e, 0x64,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x91, 0x93, 0x50, 0x51,
    0x52,
];

#[bench]
fn from_string_read_value(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_string_read_value_ref(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_complex_read_value(b: &mut Bencher) {
    b.iter(|| {
        let res = read_value(&mut &COMPLEX[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = COMPLEX.len() as u64;
}

 #[bench]
 fn from_complex_read_value_ref(b: &mut Bencher) {
     b.iter(|| {
         let res = read_value_ref(&mut &COMPLEX[..]).unwrap();
         test::black_box(res);
     });
     b.bytes = COMPLEX.len() as u64;
 }

#[bench]
fn from_complex_write_value_ref(b: &mut Bencher) {
    use rmpv::ValueRef::*;
    use rmpv::encode::write_value_ref;

    let val = Array(vec![
        Nil,
        Integer(42.into()),
        F64(3.1415),
        String("Lorem ipsum dolor sit amet.".into()),
        Map(vec![
            (String("key".into()), String("value".into())),
        ]),
    ]);

    let mut buf = [0u8; 64];

    b.iter(|| {
        let res = write_value_ref(&mut &mut buf[..], &val).unwrap();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}

#[bench]
fn from_complex_read_value_ref_to_owned(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap().to_owned();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}
<commit_msg>Add benchmarks for decoding large bin32/array values<commit_after>#![feature(test)]

extern crate rmpv;
extern crate test;

use test::Bencher;

use rmpv::decode::*;

// Encoded value: [1, 0, [[["127.0.0.1", 59074]], 1, {0: ["read", {}, {0: ["value", {}], 1: ["error", {}]}], 1: ["write", {}, {0: ["value", {}], 1: ["error", {}]}], 2: ["remove", {}, {0: ["value", {}], 1: ["error", {}]}], 3: ["find", {}, {0: ["value", {}], 1: ["error", {}]}]}], [[80, 81, 82]]].
const COMPLEX: [u8; 137] = [
    0x94, 0x01, 0x00, 0x93, 0x91, 0x92, 0xa9, 0x31,
    0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31,
    0xcd, 0xe6, 0xc2, 0x01, 0x84, 0x00, 0x93, 0xa4,
    0x72, 0x65, 0x61, 0x64, 0x80, 0x82, 0x00, 0x92,
    0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80, 0x01,
    0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x80,
    0x01, 0x93, 0xa5, 0x77, 0x72, 0x69, 0x74, 0x65,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x02, 0x93, 0xa6, 0x72,
    0x65, 0x6d, 0x6f, 0x76, 0x65, 0x80, 0x82, 0x00,
    0x92, 0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80,
    0x01, 0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72,
    0x80, 0x03, 0x93, 0xa4, 0x66, 0x69, 0x6e, 0x64,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x91, 0x93, 0x50, 0x51,
    0x52,
];

#[bench]
fn from_string_read_value(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_string_read_value_ref(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_complex_read_value(b: &mut Bencher) {
    b.iter(|| {
        let res = read_value(&mut &COMPLEX[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = COMPLEX.len() as u64;
}

 #[bench]
 fn from_complex_read_value_ref(b: &mut Bencher) {
     b.iter(|| {
         let res = read_value_ref(&mut &COMPLEX[..]).unwrap();
         test::black_box(res);
     });
     b.bytes = COMPLEX.len() as u64;
 }

#[bench]
fn from_complex_write_value_ref(b: &mut Bencher) {
    use rmpv::ValueRef::*;
    use rmpv::encode::write_value_ref;

    let val = Array(vec![
        Nil,
        Integer(42.into()),
        F64(3.1415),
        String("Lorem ipsum dolor sit amet.".into()),
        Map(vec![
            (String("key".into()), String("value".into())),
        ]),
    ]);

    let mut buf = [0u8; 64];

    b.iter(|| {
        let res = write_value_ref(&mut &mut buf[..], &val).unwrap();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}

#[bench]
fn from_complex_read_value_ref_to_owned(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap().to_owned();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}

/// Read a single large bin32 value.
fn read_large_bin32(b: &mut Bencher, size: u32) {
    // Creat buffer, fill it with bytes
    let mut buf = Vec::with_capacity(size as usize);
    buf.resize(size as usize, 42);

    // Write header (bin32 format family containing size-5 bytes)
    let size_bytes: [u8; 4] = (size - 5).to_be_bytes();
    buf[0] = 0xc6;
    buf[1] = size_bytes[0];
    buf[2] = size_bytes[1];
    buf[3] = size_bytes[2];
    buf[4] = size_bytes[3];

    // Read value
    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = size as u64;
}

#[bench]
fn read_bin32_50kib(b: &mut Bencher) {
    read_large_bin32(b, 50 * 1024);
}

#[bench]
fn read_bin32_100kib(b: &mut Bencher) {
    read_large_bin32(b, 100 * 1024);
}

#[bench]
fn read_bin32_1mib(b: &mut Bencher) {
    read_large_bin32(b, 1024 * 1024);
}

#[bench]
fn read_bin32_20mib(b: &mut Bencher) {
    read_large_bin32(b, 20 * 1024 * 1024);
}

#[bench]
fn read_bin32_100mib(b: &mut Bencher) {
    read_large_bin32(b, 100 * 1024 * 1024);
}

/// Read a flat array containing positive 32-bit unsigned integers.
fn read_large_array(b: &mut Bencher, element_count: usize) {
    // Creat buffer, fill it with bytes
    let size = element_count * 5 /* uint32 size */ + 5 /* array overhead */;
    let mut buf = Vec::with_capacity(size);
    buf.resize(size, 0);

    // Write header
    let size_bytes: [u8; 4] = (size as u32 - 5).to_be_bytes();
    buf[0] = 0xc6;
    buf[1] = size_bytes[0];
    buf[2] = size_bytes[1];
    buf[3] = size_bytes[2];
    buf[4] = size_bytes[3];

    // Write elements
    let elements = &mut buf[5..];
    for i in 0..element_count {
        let offset = i * 5;
        let value_bytes = 42u32.to_be_bytes();
        elements[offset] = 0xce; // u32
        elements[offset + 1] = value_bytes[0];
        elements[offset + 2] = value_bytes[1];
        elements[offset + 3] = value_bytes[2];
        elements[offset + 4] = value_bytes[3];
    }

    // Read value
    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = size as u64;
}

#[bench]
fn read_array_50kib(b: &mut Bencher) {
    read_large_array(b, 50 * 1024);
}

#[bench]
fn read_array_100kib(b: &mut Bencher) {
    read_large_array(b, 100 * 1024);
}

#[bench]
fn read_array_1mib(b: &mut Bencher) {
    read_large_array(b, 1024 * 1024);
}

#[bench]
fn read_array_20mib(b: &mut Bencher) {
    read_large_array(b, 20 * 1024 * 1024);
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate rmpv;
extern crate test;

use test::Bencher;

use rmpv::decode::*;

// Encoded value: [1, 0, [[["127.0.0.1", 59074]], 1, {0: ["read", {}, {0: ["value", {}], 1: ["error", {}]}], 1: ["write", {}, {0: ["value", {}], 1: ["error", {}]}], 2: ["remove", {}, {0: ["value", {}], 1: ["error", {}]}], 3: ["find", {}, {0: ["value", {}], 1: ["error", {}]}]}], [[80, 81, 82]]].
const COMPLEX: &[u8] = [
    0x94, 0x01, 0x00, 0x93, 0x91, 0x92, 0xa9, 0x31,
    0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31,
    0xcd, 0xe6, 0xc2, 0x01, 0x84, 0x00, 0x93, 0xa4,
    0x72, 0x65, 0x61, 0x64, 0x80, 0x82, 0x00, 0x92,
    0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80, 0x01,
    0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x80,
    0x01, 0x93, 0xa5, 0x77, 0x72, 0x69, 0x74, 0x65,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x02, 0x93, 0xa6, 0x72,
    0x65, 0x6d, 0x6f, 0x76, 0x65, 0x80, 0x82, 0x00,
    0x92, 0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80,
    0x01, 0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72,
    0x80, 0x03, 0x93, 0xa4, 0x66, 0x69, 0x6e, 0x64,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x91, 0x93, 0x50, 0x51,
    0x52,
];

#[bench]
fn from_string_read_value(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_string_read_value_ref(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_complex_read_value(b: &mut Bencher) {
    b.iter(|| {
        let res = read_value(&mut &COMPLEX[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}

#[bench]
fn from_complex_read_value_ref(b: &mut Bencher) {
    b.iter(|| {
        let res = read_value_ref(&mut &COMPLEX[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}

#[bench]
fn from_complex_write_value_ref(b: &mut Bencher) {
    use rmpv::ValueRef::*;
    use rmpv::encode::write_value_ref;

    let val = Array(vec![Nil, U64(42), F64(3.1415),
        String("Lorem ipsum dolor sit amet."), Map(vec![(String("key"), String("value"))])]);

    let mut buf = [0u8; 64];

    b.iter(|| {
        let res = write_value_ref(&mut &mut buf[..], &val).unwrap();
        test::black_box(res);
    });
    b.bytes = 51;
}

#[bench]
fn from_complex_read_value_ref_to_owned(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap().to_owned();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}
<commit_msg>Fix benchmarks<commit_after>#![feature(test)]

extern crate rmpv;
extern crate test;

use test::Bencher;

use rmpv::decode::*;

// Encoded value: [1, 0, [[["127.0.0.1", 59074]], 1, {0: ["read", {}, {0: ["value", {}], 1: ["error", {}]}], 1: ["write", {}, {0: ["value", {}], 1: ["error", {}]}], 2: ["remove", {}, {0: ["value", {}], 1: ["error", {}]}], 3: ["find", {}, {0: ["value", {}], 1: ["error", {}]}]}], [[80, 81, 82]]].
const COMPLEX: [u8; 137] = [
    0x94, 0x01, 0x00, 0x93, 0x91, 0x92, 0xa9, 0x31,
    0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31,
    0xcd, 0xe6, 0xc2, 0x01, 0x84, 0x00, 0x93, 0xa4,
    0x72, 0x65, 0x61, 0x64, 0x80, 0x82, 0x00, 0x92,
    0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80, 0x01,
    0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x80,
    0x01, 0x93, 0xa5, 0x77, 0x72, 0x69, 0x74, 0x65,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x02, 0x93, 0xa6, 0x72,
    0x65, 0x6d, 0x6f, 0x76, 0x65, 0x80, 0x82, 0x00,
    0x92, 0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80,
    0x01, 0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72,
    0x80, 0x03, 0x93, 0xa4, 0x66, 0x69, 0x6e, 0x64,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x91, 0x93, 0x50, 0x51,
    0x52,
];

#[bench]
fn from_string_read_value(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_string_read_value_ref(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_complex_read_value(b: &mut Bencher) {
    b.iter(|| {
        let res = read_value(&mut &COMPLEX[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = COMPLEX.len() as u64;
}

 #[bench]
 fn from_complex_read_value_ref(b: &mut Bencher) {
     b.iter(|| {
         let res = read_value_ref(&mut &COMPLEX[..]).unwrap();
         test::black_box(res);
     });
     b.bytes = COMPLEX.len() as u64;
 }

#[bench]
fn from_complex_write_value_ref(b: &mut Bencher) {
    use rmpv::ValueRef::*;
    use rmpv::encode::write_value_ref;

    let val = Array(vec![
        Nil,
        Integer(42.into()),
        F64(3.1415),
        String("Lorem ipsum dolor sit amet.".into()),
        Map(vec![
            (String("key".into()), String("value".into())),
        ]),
    ]);

    let mut buf = [0u8; 64];

    b.iter(|| {
        let res = write_value_ref(&mut &mut buf[..], &val).unwrap();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}

#[bench]
fn from_complex_read_value_ref_to_owned(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap().to_owned();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}
<|endoftext|>