<commit_before>use extra::treemap::TreeMap;
//use headers::Headers;
use std::rt;

//use std::rt::io::net::tcp::TcpStream;
//use TcpStream = super::adapter::ExtraNetTcpStream;
// Use whatever server is using at present
use TcpStream = super::server::TcpStream;

use super::status;
use super::headers;

/**
 * The HTTP version tag which will be used for the response.
 *
 * At present, responses will always respond with `HTTP/1.1`, as there doesn't
 * seem much value in responding HTTP/1.0 when we don't really support it.
 * Others do this too, so there's my justification.
 */
static RESPONSE_HTTP_VERSION: &'static str = "HTTP/1.1";
// Maybe we could provide a response interface

fn to_owned_bytes(s: ~str) -> ~[u8] {
    // XXX: Rust compiler bug(?) prevents me from doing `s.as_bytes().to_owned()` in one step
    let b = s.as_bytes();
    b.to_owned()
}

macro_rules! bfmt (
        ($($expr:expr),*) => (to_owned_bytes(fmt!($($expr),*)))
        )

/*
/**
 * A HTTP Response.
 *
 * - `headers`: A hashmap with the headers to send (Content-type and -length are done seperatley).
 * - `status` - A status code for the response. For now only used for the first lne of the response.
 * /
pub struct Response {
    headers: ~TreeMap<~str, ~str>,
    status: status::Status,
}

impl Response {

    fn init(@mut self) {
        // Default to text/html
        //self.headers = ~TreeMap<~str, ~str>::new();
        self.set_header(~"Content-Type", ~"text/html");
    }

    fn write_status(&self, socket: &TcpSocket) {
        socket.write(to_owned_bytes(fmt!("%s %?\r\n", RESPONSE_HTTP_VERSION, self.status)));
    }

    fn write_headers(&self, socket: &TcpSocket) {
        for self.headers.iter().advance |(key, value)| {
            socket.write(to_owned_bytes(fmt!("%s: %s\r\n", *key, *value)));
        }
        socket.write(to_owned_bytes(~"\r\n"));
    }

    fn set_header<V: ToStr>(@mut self, name: ~str, value: V) {
        // TODO: apply some normalisation to the headers
        self.headers.insert(name, value.to_str());
    }

    fn auto_content_length(@mut self) {
        // Returns true if the key did not already exist in the map, but we don't care
        self.set_header(~"Content-Length", self.content.len());
    }

    /// Write the response to a socket using the HTTP version specified by version_number.
    // TODO: is this different for different versions?
    pub fn write(&self, version_number: (int, int), socket: &TcpSocket) {
        self.write_status(socket);
        self.write_headers(socket);
        socket.write(to_owned_bytes(copy self.content));
    }
}*/

pub struct ResponseWriter {
    // The place to write to (typically a TCP stream, rt::io::net::tcp::TcpStream)
    priv writer: TcpStream,
    priv headers_written: bool,
    headers: ~headers::Headers,
    status: status::Status,
}

impl ResponseWriter {
    /// Create a `ResponseWriter` writing to the specified location
    pub fn new(writer: TcpStream) -> ResponseWriter {
        ResponseWriter {
            writer: writer,
            headers_written: false,
            //headers: headers::Headers::new(),
            headers: ~TreeMap::new(),
            status: status::Ok,
        }
    }

    /// Write a response with the specified Content-Type and content; the Content-Length header is
    /// set based upon the contents
    pub fn write_content_auto(&mut self, content_type: ~str, content: ~str) {
        self.headers.insert(~"Content-Type", content_type);
        let cbytes = content.as_bytes();
        self.headers.insert(~"Content-Length", cbytes.len().to_str());
        self.write_headers();
        self.write(cbytes);
    }

    /// Write the Status-Line and headers of the response, in preparation for writing the body.
    ///
    /// If the headers have already been written, this will fail.
    pub fn write_headers(&mut self) {
        // This marks the beginning of the response (RFC2616 §6)
        if self.headers_written {
            fail!("ResponseWriter.write_headers() called, but headers already written");
        }

        // TODO: compare performance of bfmt!("foo %s", ...) and write(bytes!("foo ")) write(...)
        // (Titchy case, but could be good to get an idea of the perf characteristics; there's an
        // extremely remote possibility it might affect things later.)

        // Write the Status-Line (RFC2616 §6.1)
        // XXX: might be better not to hardcode HTTP/1.1.
        self.writer.write(bfmt!("HTTP/1.1 %s\r\n", self.status.to_str()));

        // Write the miscellaneous varieties of headers
        // XXX: this is not in the slightest bit sufficient; much more filtration is required.
        for self.headers.iter().advance |(name, value)| {
            self.writer.write(bfmt!("%s: %s\r\n", *name, *value));
        }
        self.writer.write(bytes!("\r\n"));
        self.headers_written = true;
    }
}

impl rt::io::Writer for ResponseWriter {

    pub fn write(&mut self, buf: &[u8]) {
        if (!self.headers_written) {
            self.write_headers();
        }
        self.writer.write(buf);
    }

    pub fn flush(&mut self) {
        self.writer.flush();
    }

}
<commit_msg>Add a necessary use statement.<commit_after>use extra::treemap::TreeMap;
//use headers::Headers;
use std::rt;
use std::rt::io::Writer;

//use std::rt::io::net::tcp::TcpStream;
//use TcpStream = super::adapter::ExtraNetTcpStream;
// Use whatever server is using at present
use TcpStream = super::server::TcpStream;

use super::status;
use super::headers;

/**
 * The HTTP version tag which will be used for the response.
 *
 * At present, responses will always respond with `HTTP/1.1`, as there doesn't
 * seem much value in responding HTTP/1.0 when we don't really support it.
 * Others do this too, so there's my justification.
 */
static RESPONSE_HTTP_VERSION: &'static str = "HTTP/1.1";
// Maybe we could provide a response interface

fn to_owned_bytes(s: ~str) -> ~[u8] {
    // XXX: Rust compiler bug(?) prevents me from doing `s.as_bytes().to_owned()` in one step
    let b = s.as_bytes();
    b.to_owned()
}

macro_rules! bfmt (
        ($($expr:expr),*) => (to_owned_bytes(fmt!($($expr),*)))
        )

/*
/**
 * A HTTP Response.
 *
 * - `headers`: A hashmap with the headers to send (Content-type and -length are done seperatley).
 * - `status` - A status code for the response. For now only used for the first lne of the response.
 * /
pub struct Response {
    headers: ~TreeMap<~str, ~str>,
    status: status::Status,
}

impl Response {

    fn init(@mut self) {
        // Default to text/html
        //self.headers = ~TreeMap<~str, ~str>::new();
        self.set_header(~"Content-Type", ~"text/html");
    }

    fn write_status(&self, socket: &TcpSocket) {
        socket.write(to_owned_bytes(fmt!("%s %?\r\n", RESPONSE_HTTP_VERSION, self.status)));
    }

    fn write_headers(&self, socket: &TcpSocket) {
        for self.headers.iter().advance |(key, value)| {
            socket.write(to_owned_bytes(fmt!("%s: %s\r\n", *key, *value)));
        }
        socket.write(to_owned_bytes(~"\r\n"));
    }

    fn set_header<V: ToStr>(@mut self, name: ~str, value: V) {
        // TODO: apply some normalisation to the headers
        self.headers.insert(name, value.to_str());
    }

    fn auto_content_length(@mut self) {
        // Returns true if the key did not already exist in the map, but we don't care
        self.set_header(~"Content-Length", self.content.len());
    }

    /// Write the response to a socket using the HTTP version specified by version_number.
    // TODO: is this different for different versions?
    pub fn write(&self, version_number: (int, int), socket: &TcpSocket) {
        self.write_status(socket);
        self.write_headers(socket);
        socket.write(to_owned_bytes(copy self.content));
    }
}*/

pub struct ResponseWriter {
    // The place to write to (typically a TCP stream, rt::io::net::tcp::TcpStream)
    priv writer: TcpStream,
    priv headers_written: bool,
    headers: ~headers::Headers,
    status: status::Status,
}

impl ResponseWriter {
    /// Create a `ResponseWriter` writing to the specified location
    pub fn new(writer: TcpStream) -> ResponseWriter {
        ResponseWriter {
            writer: writer,
            headers_written: false,
            //headers: headers::Headers::new(),
            headers: ~TreeMap::new(),
            status: status::Ok,
        }
    }

    /// Write a response with the specified Content-Type and content; the Content-Length header is
    /// set based upon the contents
    pub fn write_content_auto(&mut self, content_type: ~str, content: ~str) {
        self.headers.insert(~"Content-Type", content_type);
        let cbytes = content.as_bytes();
        self.headers.insert(~"Content-Length", cbytes.len().to_str());
        self.write_headers();
        self.write(cbytes);
    }

    /// Write the Status-Line and headers of the response, in preparation for writing the body.
    ///
    /// If the headers have already been written, this will fail.
    pub fn write_headers(&mut self) {
        // This marks the beginning of the response (RFC2616 §6)
        if self.headers_written {
            fail!("ResponseWriter.write_headers() called, but headers already written");
        }

        // TODO: compare performance of bfmt!("foo %s", ...) and write(bytes!("foo ")) write(...)
        // (Titchy case, but could be good to get an idea of the perf characteristics; there's an
        // extremely remote possibility it might affect things later.)

        // Write the Status-Line (RFC2616 §6.1)
        // XXX: might be better not to hardcode HTTP/1.1.
        self.writer.write(bfmt!("HTTP/1.1 %s\r\n", self.status.to_str()));

        // Write the miscellaneous varieties of headers
        // XXX: this is not in the slightest bit sufficient; much more filtration is required.
        for self.headers.iter().advance |(name, value)| {
            self.writer.write(bfmt!("%s: %s\r\n", *name, *value));
        }
        self.writer.write(bytes!("\r\n"));
        self.headers_written = true;
    }
}

impl rt::io::Writer for ResponseWriter {

    pub fn write(&mut self, buf: &[u8]) {
        if (!self.headers_written) {
            self.write_headers();
        }
        self.writer.write(buf);
    }

    pub fn flush(&mut self) {
        self.writer.flush();
    }

}
<|endoftext|>


<commit_before>mod advent_of_code;

use std::cmp::Ordering;

use std::collections::HashMap;

use std::io;
use std::io::BufRead;

const CHECKSUM_SIZE: usize = 5;

fn compare_counts(a: &(char, usize), b: &(char, usize))
    -> Ordering
{
    let mut cmp = b.1.cmp(&a.1);
    if cmp == Ordering::Equal
    {
        cmp = a.0.cmp(&b.0);
    }
    return cmp;
}

fn compute_checksum(name: &str)
    -> String
{
    let mut counts: HashMap<char, usize> = HashMap::new();

    for letter in name.chars()
    {
        if letter == '-'
        {
            continue;
        }

        let count = counts.entry(letter).or_insert(0);
        *count += 1;
    }

    let mut sorted_counts: Vec<(char, usize)> = counts.into_iter().collect();
    sorted_counts.sort_by(compare_counts);

    let mut checksum = String::with_capacity(CHECKSUM_SIZE);

    for pair in sorted_counts[..CHECKSUM_SIZE].iter()
    {
        let (letter, _) = *pair;
        checksum.push(letter);
    }

    return checksum;
}

#[derive(PartialEq, Eq, Hash, Clone, Debug)]
struct Room<'a>
{
    checksum: &'a str,
    name: &'a str,
    sector_id: i32,
}

impl<'a> Room<'a>
{
    fn decode(text: &'a str)
        -> Room<'a>
    {
        let last_dash = text.rfind('-').unwrap();
        let checksum_outer_size = CHECKSUM_SIZE + 2;

        return Room {
            name: text[.. last_dash].as_ref(),
            sector_id: text[last_dash + 1 .. text.len() - checksum_outer_size].parse::<i32>().unwrap(),
            checksum: text[text.len() - 1 - CHECKSUM_SIZE .. text.len() - 1].as_ref(),
        };
    }
}

#[cfg(test)]
mod test
{
    use compute_checksum;
    use Room;

    #[test]
    fn test_decode_room()
    {
        let input = "aaaaa-bbb-z-y-x-123[abxyz]";
        let expected = Room {
            checksum: "abxyz",
            name: "aaaaa-bbb-z-y-x",
            sector_id: 123,
        };
        let actual = Room::decode(input);
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_checksum_1()
    {
        let input = "aaaaa-bbb-z-y-x";
        let expected = "abxyz";
        let actual = compute_checksum(input);
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_checksum_2()
    {
        let input = "a-b-c-d-e-f-g-h";
        let expected = "abcde";
        let actual = compute_checksum(input);
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_checksum_3()
    {
        let input = "not-a-real-room";
        let expected = "oarel";
        let actual = compute_checksum(input);
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_checksum_4()
    {
        let input = "totally-real-room";
        let expected = "loart";
        let actual = compute_checksum(input);
        assert_eq!(expected, actual);
    }
}

#[cfg(not(test))]
fn main()
{
    let stdin = io::stdin();
    let mut total_sector_id = 0;

    for wrapped_line in stdin.lock().lines()
    {
        let line = wrapped_line.unwrap();
        let room = Room::decode(&line);
        if room.checksum == compute_checksum(room.name)
        {
            total_sector_id += room.sector_id;
        }
    }

    println!("{}", total_sector_id);
}
<commit_msg>Add a rot_n function<commit_after>mod advent_of_code;

use std::cmp::Ordering;

use std::collections::HashMap;

use std::io;
use std::io::BufRead;

const CHECKSUM_SIZE: usize = 5;

fn compare_counts(a: &(char, usize), b: &(char, usize))
    -> Ordering
{
    let mut cmp = b.1.cmp(&a.1);
    if cmp == Ordering::Equal
    {
        cmp = a.0.cmp(&b.0);
    }
    return cmp;
}

fn compute_checksum(name: &str)
    -> String
{
    let mut counts: HashMap<char, usize> = HashMap::new();

    for letter in name.chars()
    {
        if letter == '-'
        {
            continue;
        }

        let count = counts.entry(letter).or_insert(0);
        *count += 1;
    }

    let mut sorted_counts: Vec<(char, usize)> = counts.into_iter().collect();
    sorted_counts.sort_by(compare_counts);

    let mut checksum = String::with_capacity(CHECKSUM_SIZE);

    for pair in sorted_counts[..CHECKSUM_SIZE].iter()
    {
        let (letter, _) = *pair;
        checksum.push(letter);
    }

    return checksum;
}

fn rot_n(letter: char, n: i32)
    -> char
{
    let origin = 'a' as u8;
    let letter_value = letter as u8 - origin;
    let rotated_value = ((letter_value as i32 + n) % 26) as u8;
    let new_letter = (rotated_value + origin) as char;
    return new_letter;
}

#[derive(PartialEq, Eq, Hash, Clone, Debug)]
struct Room<'a>
{
    checksum: &'a str,
    name: &'a str,
    sector_id: i32,
}

impl<'a> Room<'a>
{
    fn decode(text: &'a str)
        -> Room<'a>
    {
        let last_dash = text.rfind('-').unwrap();
        let checksum_outer_size = CHECKSUM_SIZE + 2;

        return Room {
            name: text[.. last_dash].as_ref(),
            sector_id: text[last_dash + 1 .. text.len() - checksum_outer_size].parse::<i32>().unwrap(),
            checksum: text[text.len() - 1 - CHECKSUM_SIZE .. text.len() - 1].as_ref(),
        };
    }
}

#[cfg(test)]
mod test
{
    use compute_checksum;
    use rot_n;
    use Room;

    #[test]
    fn test_decode_room()
    {
        let input = "aaaaa-bbb-z-y-x-123[abxyz]";
        let expected = Room {
            checksum: "abxyz",
            name: "aaaaa-bbb-z-y-x",
            sector_id: 123,
        };
        let actual = Room::decode(input);
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_checksum_1()
    {
        let input = "aaaaa-bbb-z-y-x";
        let expected = "abxyz";
        let actual = compute_checksum(input);
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_checksum_2()
    {
        let input = "a-b-c-d-e-f-g-h";
        let expected = "abcde";
        let actual = compute_checksum(input);
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_checksum_3()
    {
        let input = "not-a-real-room";
        let expected = "oarel";
        let actual = compute_checksum(input);
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_checksum_4()
    {
        let input = "totally-real-room";
        let expected = "loart";
        let actual = compute_checksum(input);
        assert_eq!(expected, actual);
    }

    fn assert_rot_n(input: char, n: i32, expected: char)
    {
        let actual = rot_n(input, n);
        assert_eq!(expected, actual);
    }

    fn assert_rot_26(input: char)
    {
        assert_rot_n(input, 26, input)
    }

    #[test]
    fn test_rot_2_a()
    {
        assert_rot_n('a', 2, 'c');
    }

    #[test]
    fn test_rot_2_q()
    {
        assert_rot_n('q', 2, 's');
    }

    #[test]
    fn test_rot_2_z()
    {
        assert_rot_n('z', 2, 'b');
    }

    #[test]
    fn test_rot_26_a()
    {
        assert_rot_26('a');
    }

    #[test]
    fn test_rot_26_q()
    {
        assert_rot_26('q');
    }

    #[test]
    fn test_rot_26_z()
    {
        assert_rot_26('z');
    }

    #[test]
    fn test_rot_32_a()
    {
        assert_rot_n('a', 32, 'g');
    }

    #[test]
    fn test_rot_32_q()
    {
        assert_rot_n('q', 32, 'w');
    }

    #[test]
    fn test_rot_32_z()
    {
        assert_rot_n('z', 32, 'f');
    }
}

#[cfg(not(test))]
fn main()
{
    let stdin = io::stdin();
    let mut total_sector_id = 0;

    for wrapped_line in stdin.lock().lines()
    {
        let line = wrapped_line.unwrap();
        let room = Room::decode(&line);
        if room.checksum == compute_checksum(room.name)
        {
            total_sector_id += room.sector_id;
        }
    }

    println!("{}", total_sector_id);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io;
use std::collections::VecDeque;
use std::rc::{Rc, Weak};
use std::cell::RefCell;
use futures::{self, task, Async, Poll};
use futures::future::Future;
use futures::sync::oneshot;

use capnp::{Error};

use serialize::{self, AsOutputSegments};

enum State<W, M> where W: io::Write, M: AsOutputSegments {
    Writing(serialize::Write<W, M>, oneshot::Sender<M>),
    BetweenWrites(W),
    Empty,
}

/// A queue of messages being written.
#[must_use = "futures do nothing unless polled"]
pub struct WriteQueue<W, M> where W: io::Write, M: AsOutputSegments {
    inner: Rc<RefCell<Inner<M>>>,
    state: State<W, M>,
}

struct Inner<M> {
    queue: VecDeque<(M, oneshot::Sender<M>)>,
    sender_count: usize,
    task: Option<task::Task>,

    // If set, then the queue has been requested to end, and we should complete the oneshot once
    // the queue has been emptied.
    end_notifier: Option<(Result<(), Error>, oneshot::Sender<()>)>
}

/// A handle that allows message to be sent to a `WriteQueue`.
pub struct Sender<M> where M: AsOutputSegments {
    inner: Weak<RefCell<Inner<M>>>,
}

impl <M> Clone for Sender<M> where M: AsOutputSegments {
    fn clone(&self) -> Sender<M> {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().sender_count += 1;
            }
        }
        Sender { inner: self.inner.clone() }
    }
}

impl <M> Drop for Sender<M> where M: AsOutputSegments {
    fn drop(&mut self) {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().sender_count -= 1;
            }
        }
    }
}

/// Creates a new WriteQueue that wraps the given writer.
pub fn write_queue<W, M>(writer: W) -> (Sender<M>, WriteQueue<W, M>)
    where W: io::Write, M: AsOutputSegments
{
    let inner = Rc::new(RefCell::new(Inner {
        queue: VecDeque::new(),
        task: None,
        sender_count: 1,
        end_notifier: None,
    }));

    let sender = Sender { inner: Rc::downgrade(&inner) };

    let queue = WriteQueue {
        inner: inner,
        state: State::BetweenWrites(writer),
    };

    (sender, queue)
}

impl <M> Sender<M> where M: AsOutputSegments + 'static {
    /// Enqueues a message to be written.
    pub fn send(&mut self, message: M) -> Box<Future<Item=M, Error=Error>> {
        let (complete, oneshot) = futures::oneshot();

        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                if rc_inner.borrow().end_notifier.is_some() {
                    drop(complete)
                } else {
                    rc_inner.borrow_mut().queue.push_back((message, complete));
                }

                match rc_inner.borrow_mut().task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }

        Box::new(
            oneshot.map_err(
                |oneshot::Canceled| Error::disconnected("WriteQueue has terminated".into())))
    }

    /// Returns the number of messages queued to be written, not including any in-progress write.
    pub fn len(&mut self) -> usize {
        match self.inner.upgrade() {
            None => 0,
            Some(rc_inner) => rc_inner.borrow().queue.len(),
        }

    }

    /// Commands the queue to stop writing messages once it is empty. After this method has been called,
    /// any new calls to `send()` will return a future that immediately resolves to an error.
    /// If the passed-in `result` is an error, then the `WriteQueue` will resolve to that error.
    pub fn terminate(&mut self, result: Result<(), Error>) -> Box<Future<Item=(), Error=Error>> {
        let (complete, receiver) = futures::oneshot();

        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                // TODO: what if end_notifier is already full? Maybe it should be a vector?
                rc_inner.borrow_mut().end_notifier = Some((result, complete));

                match rc_inner.borrow_mut().task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }

        Box::new(
            receiver.map_err(
                |oneshot::Canceled| Error::disconnected("WriteQueue has terminated".into())))
    }
}

enum IntermediateState<W, M> where W: io::Write, M: AsOutputSegments {
    WriteDone(M, W),
    StartWrite(M, oneshot::Sender<M>),
    Resolve,
}

impl <W, M> Future for WriteQueue<W, M> where W: io::Write, M: AsOutputSegments {
    type Item = W; // Resolves when all senders have been dropped and all messages written.
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let next = match self.state {
                State::Writing(ref mut write, ref mut _complete) => {
                    let (w, m) = try_ready!(Future::poll(write));
                    IntermediateState::WriteDone(m, w)
                }
                State::BetweenWrites(ref mut _writer) => {
                    let front = self.inner.borrow_mut().queue.pop_front();
                    match front {
                        Some((m, complete)) => {
                            IntermediateState::StartWrite(m, complete)
                        }
                        None => {
                            let count = self.inner.borrow().sender_count;
                            let ended = self.inner.borrow().end_notifier.is_some();
                            if count == 0 || ended {
                                IntermediateState::Resolve
                            } else {
                                self.inner.borrow_mut().task = Some(task::park());
                                return Ok(Async::NotReady)
                            }
                        }
                    }
                }
                State::Empty => unreachable!(),
            };

            match next {
                IntermediateState::WriteDone(m, w) => {
                    match ::std::mem::replace(&mut self.state, State::BetweenWrites(w)) {
                        State::Writing(_, complete) => {
                            complete.send(m)
                        }
                        _ => unreachable!(),
                    }
                }
                IntermediateState::StartWrite(m, c) => {
                    let new_state = match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(w) => {
                            State::Writing(::serialize::write_message(w, m), c)
                        }
                        _ => unreachable!(),
                    };
                    self.state = new_state;
                }
                IntermediateState::Resolve => {
                    let end_notifier = self.inner.borrow_mut().end_notifier.take();
                    match end_notifier {
                        None => (),
                        Some((result, complete)) => {
                            complete.send(());
                            if let Err(e) = result {
                                return Err(e)
                            }
                        }
                    }
                    match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(w) => {
                            return Ok(Async::Ready(w))
                        }
                        _ => unreachable!(),
                    }
                }
            }
        }
    }
}
<commit_msg>Unwrapped errors from Sender sends, ignoring the returned Result.<commit_after>// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io;
use std::collections::VecDeque;
use std::rc::{Rc, Weak};
use std::cell::RefCell;
use futures::{self, task, Async, Poll};
use futures::future::Future;
use futures::sync::oneshot;

use capnp::{Error};

use serialize::{self, AsOutputSegments};

enum State<W, M> where W: io::Write, M: AsOutputSegments {
    Writing(serialize::Write<W, M>, oneshot::Sender<M>),
    BetweenWrites(W),
    Empty,
}

/// A queue of messages being written.
#[must_use = "futures do nothing unless polled"]
pub struct WriteQueue<W, M> where W: io::Write, M: AsOutputSegments {
    inner: Rc<RefCell<Inner<M>>>,
    state: State<W, M>,
}

struct Inner<M> {
    queue: VecDeque<(M, oneshot::Sender<M>)>,
    sender_count: usize,
    task: Option<task::Task>,

    // If set, then the queue has been requested to end, and we should complete the oneshot once
    // the queue has been emptied.
    end_notifier: Option<(Result<(), Error>, oneshot::Sender<()>)>
}

/// A handle that allows message to be sent to a `WriteQueue`.
pub struct Sender<M> where M: AsOutputSegments {
    inner: Weak<RefCell<Inner<M>>>,
}

impl <M> Clone for Sender<M> where M: AsOutputSegments {
    fn clone(&self) -> Sender<M> {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().sender_count += 1;
            }
        }
        Sender { inner: self.inner.clone() }
    }
}

impl <M> Drop for Sender<M> where M: AsOutputSegments {
    fn drop(&mut self) {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().sender_count -= 1;
            }
        }
    }
}

/// Creates a new WriteQueue that wraps the given writer.
pub fn write_queue<W, M>(writer: W) -> (Sender<M>, WriteQueue<W, M>)
    where W: io::Write, M: AsOutputSegments
{
    let inner = Rc::new(RefCell::new(Inner {
        queue: VecDeque::new(),
        task: None,
        sender_count: 1,
        end_notifier: None,
    }));

    let sender = Sender { inner: Rc::downgrade(&inner) };

    let queue = WriteQueue {
        inner: inner,
        state: State::BetweenWrites(writer),
    };

    (sender, queue)
}

impl <M> Sender<M> where M: AsOutputSegments + 'static {
    /// Enqueues a message to be written.
    pub fn send(&mut self, message: M) -> Box<Future<Item=M, Error=Error>> {
        let (complete, oneshot) = futures::oneshot();

        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                if rc_inner.borrow().end_notifier.is_some() {
                    drop(complete)
                } else {
                    rc_inner.borrow_mut().queue.push_back((message, complete));
                }

                match rc_inner.borrow_mut().task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }

        Box::new(
            oneshot.map_err(
                |oneshot::Canceled| Error::disconnected("WriteQueue has terminated".into())))
    }

    /// Returns the number of messages queued to be written, not including any in-progress write.
    pub fn len(&mut self) -> usize {
        match self.inner.upgrade() {
            None => 0,
            Some(rc_inner) => rc_inner.borrow().queue.len(),
        }

    }

    /// Commands the queue to stop writing messages once it is empty. After this method has been called,
    /// any new calls to `send()` will return a future that immediately resolves to an error.
    /// If the passed-in `result` is an error, then the `WriteQueue` will resolve to that error.
    pub fn terminate(&mut self, result: Result<(), Error>) -> Box<Future<Item=(), Error=Error>> {
        let (complete, receiver) = futures::oneshot();

        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                // TODO: what if end_notifier is already full? Maybe it should be a vector?
                rc_inner.borrow_mut().end_notifier = Some((result, complete));

                match rc_inner.borrow_mut().task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }

        Box::new(
            receiver.map_err(
                |oneshot::Canceled| Error::disconnected("WriteQueue has terminated".into())))
    }
}

enum IntermediateState<W, M> where W: io::Write, M: AsOutputSegments {
    WriteDone(M, W),
    StartWrite(M, oneshot::Sender<M>),
    Resolve,
}

impl <W, M> Future for WriteQueue<W, M> where W: io::Write, M: AsOutputSegments {
    type Item = W; // Resolves when all senders have been dropped and all messages written.
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let next = match self.state {
                State::Writing(ref mut write, ref mut _complete) => {
                    let (w, m) = try_ready!(Future::poll(write));
                    IntermediateState::WriteDone(m, w)
                }
                State::BetweenWrites(ref mut _writer) => {
                    let front = self.inner.borrow_mut().queue.pop_front();
                    match front {
                        Some((m, complete)) => {
                            IntermediateState::StartWrite(m, complete)
                        }
                        None => {
                            let count = self.inner.borrow().sender_count;
                            let ended = self.inner.borrow().end_notifier.is_some();
                            if count == 0 || ended {
                                IntermediateState::Resolve
                            } else {
                                self.inner.borrow_mut().task = Some(task::park());
                                return Ok(Async::NotReady)
                            }
                        }
                    }
                }
                State::Empty => unreachable!(),
            };

            match next {
                IntermediateState::WriteDone(m, w) => {
                    match ::std::mem::replace(&mut self.state, State::BetweenWrites(w)) {
                        State::Writing(_, complete) => {
                            complete.send(m).unwrap_or(());
                        }
                        _ => unreachable!(),
                    }
                }
                IntermediateState::StartWrite(m, c) => {
                    let new_state = match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(w) => {
                            State::Writing(::serialize::write_message(w, m), c)
                        }
                        _ => unreachable!(),
                    };
                    self.state = new_state;
                }
                IntermediateState::Resolve => {
                    let end_notifier = self.inner.borrow_mut().end_notifier.take();
                    match end_notifier {
                        None => (),
                        Some((result, complete)) => {
                            complete.send(()).unwrap_or(());
                            if let Err(e) = result {
                                return Err(e)
                            }
                        }
                    }
                    match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(w) => {
                            return Ok(Async::Ready(w))
                        }
                        _ => unreachable!(),
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! This module provides `StaticIndex` which is used for powering
//! read-only code browsers and emitting LSIF

use std::collections::HashMap;

use hir::{db::HirDatabase, Crate, Module, Semantics};
use ide_db::{
    base_db::{FileId, FileRange, SourceDatabaseExt},
    defs::{Definition, IdentClass},
    FxHashSet, RootDatabase,
};
use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};

use crate::{
    hover::hover_for_definition,
    moniker::{crate_for_file, def_to_moniker, MonikerResult},
    Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig,
    TryToNav,
};

/// A static representation of fully analyzed source code.
///
/// The intended use-case is powering read-only code browsers and emitting LSIF
#[derive(Debug)]
pub struct StaticIndex<'a> {
    pub files: Vec<StaticIndexedFile>,
    pub tokens: TokenStore,
    analysis: &'a Analysis,
    db: &'a RootDatabase,
    def_map: HashMap<Definition, TokenId>,
}

#[derive(Debug)]
pub struct ReferenceData {
    pub range: FileRange,
    pub is_definition: bool,
}

#[derive(Debug)]
pub struct TokenStaticData {
    pub hover: Option<HoverResult>,
    pub definition: Option<FileRange>,
    pub references: Vec<ReferenceData>,
    pub moniker: Option<MonikerResult>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TokenId(usize);

impl TokenId {
    pub fn raw(self) -> usize {
        self.0
    }
}

#[derive(Default, Debug)]
pub struct TokenStore(Vec<TokenStaticData>);

impl TokenStore {
    pub fn insert(&mut self, data: TokenStaticData) -> TokenId {
        let id = TokenId(self.0.len());
        self.0.push(data);
        id
    }

    pub fn get_mut(&mut self, id: TokenId) -> Option<&mut TokenStaticData> {
        self.0.get_mut(id.0)
    }

    pub fn get(&self, id: TokenId) -> Option<&TokenStaticData> {
        self.0.get(id.0)
    }

    pub fn iter(self) -> impl Iterator<Item = (TokenId, TokenStaticData)> {
        self.0.into_iter().enumerate().map(|(i, x)| (TokenId(i), x))
    }
}

#[derive(Debug)]
pub struct StaticIndexedFile {
    pub file_id: FileId,
    pub folds: Vec<Fold>,
    pub inlay_hints: Vec<InlayHint>,
    pub tokens: Vec<(TextRange, TokenId)>,
}

fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
    let mut worklist: Vec<_> =
        Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect();
    let mut modules = Vec::new();

    while let Some(module) = worklist.pop() {
        modules.push(module);
        worklist.extend(module.children(db));
    }

    modules
}

impl StaticIndex<'_> {
    fn add_file(&mut self, file_id: FileId) {
        let current_crate = crate_for_file(self.db, file_id);
        let folds = self.analysis.folding_ranges(file_id).unwrap();
        let inlay_hints = self
            .analysis
            .inlay_hints(
                &InlayHintsConfig {
                    render_colons: true,
                    type_hints: true,
                    parameter_hints: true,
                    chaining_hints: true,
                    closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
                    lifetime_elision_hints: crate::LifetimeElisionHints::Never,
                    reborrow_hints: crate::ReborrowHints::Never,
                    hide_named_constructor_hints: false,
                    hide_closure_initialization_hints: false,
                    param_names_for_lifetime_elision_hints: false,
                    binding_mode_hints: false,
                    max_length: Some(25),
                    closing_brace_hints_min_lines: Some(25),
                },
                file_id,
                None,
            )
            .unwrap();
        // hovers
        let sema = hir::Semantics::new(self.db);
        let tokens_or_nodes = sema.parse(file_id).syntax().clone();
        let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|x| match x {
            syntax::NodeOrToken::Node(_) => None,
            syntax::NodeOrToken::Token(x) => Some(x),
        });
        let hover_config = HoverConfig {
            links_in_hover: true,
            documentation: Some(HoverDocFormat::Markdown),
            keywords: true,
        };
        let tokens = tokens.filter(|token| {
            matches!(
                token.kind(),
                IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
            )
        });
        let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] };
        for token in tokens {
            let range = token.text_range();
            let node = token.parent().unwrap();
            let def = match get_definition(&sema, token.clone()) {
                Some(x) => x,
                None => continue,
            };
            let id = if let Some(x) = self.def_map.get(&def) {
                *x
            } else {
                let x = self.tokens.insert(TokenStaticData {
                    hover: hover_for_definition(&sema, file_id, def, &node, &hover_config),
                    definition: def
                        .try_to_nav(self.db)
                        .map(|x| FileRange { file_id: x.file_id, range: x.focus_or_full_range() }),
                    references: vec![],
                    moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)),
                });
                self.def_map.insert(def, x);
                x
            };
            let token = self.tokens.get_mut(id).unwrap();
            token.references.push(ReferenceData {
                range: FileRange { range, file_id },
                is_definition: match def.try_to_nav(self.db) {
                    Some(x) => x.file_id == file_id && x.focus_or_full_range() == range,
                    None => false,
                },
            });
            result.tokens.push((range, id));
        }
        self.files.push(result);
    }

    pub fn compute(analysis: &Analysis) -> StaticIndex<'_> {
        let db = &*analysis.db;
        let work = all_modules(db).into_iter().filter(|module| {
            let file_id = module.definition_source(db).file_id.original_file(db);
            let source_root = db.file_source_root(file_id);
            let source_root = db.source_root(source_root);
            !source_root.is_library
        });
        let mut this = StaticIndex {
            files: vec![],
            tokens: Default::default(),
            analysis,
            db,
            def_map: Default::default(),
        };
        let mut visited_files = FxHashSet::default();
        for module in work {
            let file_id = module.definition_source(db).file_id.original_file(db);
            if visited_files.contains(&file_id) {
                continue;
            }
            this.add_file(file_id);
            // mark the file
            visited_files.insert(file_id);
        }
        this
    }
}

fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Definition> {
    for token in sema.descend_into_macros(token) {
        let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
        if let Some(&[x]) = def.as_deref() {
            return Some(x);
        } else {
            continue;
        };
    }
    None
}

#[cfg(test)]
mod tests {
    use crate::{fixture, StaticIndex};
    use ide_db::base_db::FileRange;
    use std::collections::HashSet;
    use syntax::TextSize;

    fn check_all_ranges(ra_fixture: &str) {
        let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
        let s = StaticIndex::compute(&analysis);
        let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect();
        for f in s.files {
            for (range, _) in f.tokens {
                let x = FileRange { file_id: f.file_id, range };
                if !range_set.contains(&x) {
                    panic!("additional range {:?}", x);
                }
                range_set.remove(&x);
            }
        }
        if !range_set.is_empty() {
            panic!("unfound ranges {:?}", range_set);
        }
    }

    fn check_definitions(ra_fixture: &str) {
        let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
        let s = StaticIndex::compute(&analysis);
        let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect();
        for (_, t) in s.tokens.iter() {
            if let Some(x) = t.definition {
                if x.range.start() == TextSize::from(0) {
                    // ignore definitions that are whole of file
                    continue;
                }
                if !range_set.contains(&x) {
                    panic!("additional definition {:?}", x);
                }
                range_set.remove(&x);
            }
        }
        if !range_set.is_empty() {
            panic!("unfound definitions {:?}", range_set);
        }
    }

    #[test]
    fn struct_and_enum() {
        check_all_ranges(
            r#"
struct Foo;
     //^^^
enum E { X(Foo) }
   //^   ^ ^^^
"#,
        );
        check_definitions(
            r#"
struct Foo;
     //^^^
enum E { X(Foo) }
   //^   ^
"#,
        );
    }

    #[test]
    fn multi_crate() {
        check_definitions(
            r#"
//- /main.rs crate:main deps:foo

use foo::func;

fn main() {
 //^^^^
    func();
}
//- /foo/lib.rs crate:foo

pub func() {

}
"#,
        );
    }

    #[test]
    fn derives() {
        check_all_ranges(
            r#"
//- minicore:derive
#[rustc_builtin_macro]
//^^^^^^^^^^^^^^^^^^^
pub macro Copy {}
        //^^^^
#[derive(Copy)]
//^^^^^^ ^^^^
struct Hello(i32);
     //^^^^^ ^^^
"#,
        );
    }
}
<commit_msg>ide: Remove unnecessary continue.<commit_after>//! This module provides `StaticIndex` which is used for powering
//! read-only code browsers and emitting LSIF

use std::collections::HashMap;

use hir::{db::HirDatabase, Crate, Module, Semantics};
use ide_db::{
    base_db::{FileId, FileRange, SourceDatabaseExt},
    defs::{Definition, IdentClass},
    FxHashSet, RootDatabase,
};
use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};

use crate::{
    hover::hover_for_definition,
    moniker::{crate_for_file, def_to_moniker, MonikerResult},
    Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig,
    TryToNav,
};

/// A static representation of fully analyzed source code.
///
/// The intended use-case is powering read-only code browsers and emitting LSIF
#[derive(Debug)]
pub struct StaticIndex<'a> {
    pub files: Vec<StaticIndexedFile>,
    pub tokens: TokenStore,
    analysis: &'a Analysis,
    db: &'a RootDatabase,
    def_map: HashMap<Definition, TokenId>,
}

#[derive(Debug)]
pub struct ReferenceData {
    pub range: FileRange,
    pub is_definition: bool,
}

#[derive(Debug)]
pub struct TokenStaticData {
    pub hover: Option<HoverResult>,
    pub definition: Option<FileRange>,
    pub references: Vec<ReferenceData>,
    pub moniker: Option<MonikerResult>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TokenId(usize);

impl TokenId {
    pub fn raw(self) -> usize {
        self.0
    }
}

#[derive(Default, Debug)]
pub struct TokenStore(Vec<TokenStaticData>);

impl TokenStore {
    pub fn insert(&mut self, data: TokenStaticData) -> TokenId {
        let id = TokenId(self.0.len());
        self.0.push(data);
        id
    }

    pub fn get_mut(&mut self, id: TokenId) -> Option<&mut TokenStaticData> {
        self.0.get_mut(id.0)
    }

    pub fn get(&self, id: TokenId) -> Option<&TokenStaticData> {
        self.0.get(id.0)
    }

    pub fn iter(self) -> impl Iterator<Item = (TokenId, TokenStaticData)> {
        self.0.into_iter().enumerate().map(|(i, x)| (TokenId(i), x))
    }
}

#[derive(Debug)]
pub struct StaticIndexedFile {
    pub file_id: FileId,
    pub folds: Vec<Fold>,
    pub inlay_hints: Vec<InlayHint>,
    pub tokens: Vec<(TextRange, TokenId)>,
}

fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
    let mut worklist: Vec<_> =
        Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect();
    let mut modules = Vec::new();

    while let Some(module) = worklist.pop() {
        modules.push(module);
        worklist.extend(module.children(db));
    }

    modules
}

impl StaticIndex<'_> {
    fn add_file(&mut self, file_id: FileId) {
        let current_crate = crate_for_file(self.db, file_id);
        let folds = self.analysis.folding_ranges(file_id).unwrap();
        let inlay_hints = self
            .analysis
            .inlay_hints(
                &InlayHintsConfig {
                    render_colons: true,
                    type_hints: true,
                    parameter_hints: true,
                    chaining_hints: true,
                    closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
                    lifetime_elision_hints: crate::LifetimeElisionHints::Never,
                    reborrow_hints: crate::ReborrowHints::Never,
                    hide_named_constructor_hints: false,
                    hide_closure_initialization_hints: false,
                    param_names_for_lifetime_elision_hints: false,
                    binding_mode_hints: false,
                    max_length: Some(25),
                    closing_brace_hints_min_lines: Some(25),
                },
                file_id,
                None,
            )
            .unwrap();
        // hovers
        let sema = hir::Semantics::new(self.db);
        let tokens_or_nodes = sema.parse(file_id).syntax().clone();
        let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|x| match x {
            syntax::NodeOrToken::Node(_) => None,
            syntax::NodeOrToken::Token(x) => Some(x),
        });
        let hover_config = HoverConfig {
            links_in_hover: true,
            documentation: Some(HoverDocFormat::Markdown),
            keywords: true,
        };
        let tokens = tokens.filter(|token| {
            matches!(
                token.kind(),
                IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
            )
        });
        let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] };
        for token in tokens {
            let range = token.text_range();
            let node = token.parent().unwrap();
            let def = match get_definition(&sema, token.clone()) {
                Some(x) => x,
                None => continue,
            };
            let id = if let Some(x) = self.def_map.get(&def) {
                *x
            } else {
                let x = self.tokens.insert(TokenStaticData {
                    hover: hover_for_definition(&sema, file_id, def, &node, &hover_config),
                    definition: def
                        .try_to_nav(self.db)
                        .map(|x| FileRange { file_id: x.file_id, range: x.focus_or_full_range() }),
                    references: vec![],
                    moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)),
                });
                self.def_map.insert(def, x);
                x
            };
            let token = self.tokens.get_mut(id).unwrap();
            token.references.push(ReferenceData {
                range: FileRange { range, file_id },
                is_definition: match def.try_to_nav(self.db) {
                    Some(x) => x.file_id == file_id && x.focus_or_full_range() == range,
                    None => false,
                },
            });
            result.tokens.push((range, id));
        }
        self.files.push(result);
    }

    pub fn compute(analysis: &Analysis) -> StaticIndex<'_> {
        let db = &*analysis.db;
        let work = all_modules(db).into_iter().filter(|module| {
            let file_id = module.definition_source(db).file_id.original_file(db);
            let source_root = db.file_source_root(file_id);
            let source_root = db.source_root(source_root);
            !source_root.is_library
        });
        let mut this = StaticIndex {
            files: vec![],
            tokens: Default::default(),
            analysis,
            db,
            def_map: Default::default(),
        };
        let mut visited_files = FxHashSet::default();
        for module in work {
            let file_id = module.definition_source(db).file_id.original_file(db);
            if visited_files.contains(&file_id) {
                continue;
            }
            this.add_file(file_id);
            // mark the file
            visited_files.insert(file_id);
        }
        this
    }
}

fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Definition> {
    for token in sema.descend_into_macros(token) {
        let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
        if let Some(&[x]) = def.as_deref() {
            return Some(x);
        }
    }
    None
}

#[cfg(test)]
mod tests {
    use crate::{fixture, StaticIndex};
    use ide_db::base_db::FileRange;
    use std::collections::HashSet;
    use syntax::TextSize;

    fn check_all_ranges(ra_fixture: &str) {
        let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
        let s = StaticIndex::compute(&analysis);
        let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect();
        for f in s.files {
            for (range, _) in f.tokens {
                let x = FileRange { file_id: f.file_id, range };
                if !range_set.contains(&x) {
                    panic!("additional range {:?}", x);
                }
                range_set.remove(&x);
            }
        }
        if !range_set.is_empty() {
            panic!("unfound ranges {:?}", range_set);
        }
    }

    fn check_definitions(ra_fixture: &str) {
        let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
        let s = StaticIndex::compute(&analysis);
        let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect();
        for (_, t) in s.tokens.iter() {
            if let Some(x) = t.definition {
                if x.range.start() == TextSize::from(0) {
                    // ignore definitions that are whole of file
                    continue;
                }
                if !range_set.contains(&x) {
                    panic!("additional definition {:?}", x);
                }
                range_set.remove(&x);
            }
        }
        if !range_set.is_empty() {
            panic!("unfound definitions {:?}", range_set);
        }
    }

    #[test]
    fn struct_and_enum() {
        check_all_ranges(
            r#"
struct Foo;
     //^^^
enum E { X(Foo) }
   //^   ^ ^^^
"#,
        );
        check_definitions(
            r#"
struct Foo;
     //^^^
enum E { X(Foo) }
   //^   ^
"#,
        );
    }

    #[test]
    fn multi_crate() {
        check_definitions(
            r#"
//- /main.rs crate:main deps:foo

use foo::func;

fn main() {
 //^^^^
    func();
}
//- /foo/lib.rs crate:foo

pub func() {

}
"#,
        );
    }

    #[test]
    fn derives() {
        check_all_ranges(
            r#"
//- minicore:derive
#[rustc_builtin_macro]
//^^^^^^^^^^^^^^^^^^^
pub macro Copy {}
        //^^^^
#[derive(Copy)]
//^^^^^^ ^^^^
struct Hello(i32);
     //^^^^^ ^^^
"#,
        );
    }
}
<|endoftext|>


<commit_before>//! This module contains a platform specific implementation of the window shell.

use std::{
    cell::{Cell, RefCell},
    char,
    collections::HashMap,
    rc::Rc,
    sync::Mutex,
};

#[cfg(not(target_os = "redox"))]
use minifb;

#[cfg(target_os = "redox")]
use minifb_fix as minifb;

use spin_sleep::LoopHelper;

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {}

fn key_event_helper(key: &mut KeyHelper, adapter: &mut A, window: &minifb::Window)
where
    A: WindowAdapter,
{
    if !key.0 && window.is_key_pressed(key.1, minifb::KeyRepeat::Yes) {
        adapter.key_event(KeyEvent {
            key: key.2,
            state: ButtonState::Down,
            text: String::new(),
        });

        key.0 = true;
    } else {
        key.0 = false;
    }
}

fn unicode_to_key_event(uni_char: u32) -> Option<KeyEvent> {
    let mut text = String::new();

    let key = if let Some(character) = char::from_u32(uni_char) {
        text = character.to_string();
        Key::from(character)
    } else {
        Key::Unknown
    };

    if key == Key::Up || key == Key::Down || key == Key::Left || key == Key::Right {
        return None;
    }

    Some(KeyEvent {
        key,
        state: ButtonState::Down,
        text,
    })
}

struct KeyInputCallBack {
    key_events: Rc<RefCell<Vec<KeyEvent>>>,
}

impl minifb::InputCallback for KeyInputCallBack {
    fn add_char(&mut self, uni_char: u32) {
        if let Some(key_event) = unicode_to_key_event(uni_char) {
            self.key_events.borrow_mut().push(key_event);
        }
    }
}

struct KeyHelper(bool, minifb::Key, Key);

/// Concrete implementation of the window shell.
pub struct WindowShell
where
    A: WindowAdapter,
{
    window: minifb::Window,
    render_context_2_d: RenderContext2D,
    adapter: A,
    mouse_pos: (f32, f32),
    button_down: (bool, bool, bool),
    window_size: (usize, usize),
    key_events: Rc<RefCell<Vec<KeyEvent>>>,
    // todo: temp solution
    key_backspace: KeyHelper,
    key_delete: KeyHelper,
    key_left: KeyHelper,
    key_right: KeyHelper,
    key_up: KeyHelper,
    key_down: KeyHelper,
    key_enter: KeyHelper,
    key_control: KeyHelper,
    key_control_right: KeyHelper,
    key_shift_l: KeyHelper,
    key_shift_r: KeyHelper,
    key_alt: KeyHelper,
    key_alt_r: KeyHelper,
    key_escape: KeyHelper,
    key_home: KeyHelper,
}

impl WindowShell
where
    A: WindowAdapter,
{
    /// Creates a new window shell with an adapter.
    pub fn new(
        window: minifb::Window,
        adapter: A,
        key_events: Rc<RefCell<Vec<KeyEvent>>>,
    ) -> WindowShell {
        let size = window.get_size();
        let render_context_2_d = RenderContext2D::new(size.0 as f64, size.1 as f64);

        WindowShell {
            window,
            // window_size: window_size,
            // mouse_buttons: (false, false, false),
            // mouse_position: Point::default(),
            render_context_2_d,
            adapter,
            mouse_pos: (0.0, 0.0),
            window_size: size,
            button_down: (false, false, false),
            key_events,
            key_backspace: KeyHelper(false, minifb::Key::Backspace, Key::Backspace),
            key_left: KeyHelper(false, minifb::Key::Left, Key::Left),
            key_right: KeyHelper(false, minifb::Key::Right, Key::Right),
            key_up: KeyHelper(false, minifb::Key::Up, Key::Up),
            key_down: KeyHelper(false, minifb::Key::Down, Key::Down),
            key_delete: KeyHelper(false, minifb::Key::Delete, Key::Delete),
            key_enter: KeyHelper(false, minifb::Key::Enter, Key::Enter),
            key_control: KeyHelper(false, minifb::Key::LeftCtrl, Key::Control),
            key_control_right: KeyHelper(false, minifb::Key::RightCtrl, Key::Control),
            key_shift_l: KeyHelper(false, minifb::Key::LeftShift, Key::ShiftL),
            key_shift_r: KeyHelper(false, minifb::Key::RightShift, Key::ShiftR),
            key_alt: KeyHelper(false, minifb::Key::LeftAlt, Key::Alt),
            key_alt_r: KeyHelper(false, minifb::Key::RightAlt, Key::Alt),
            key_escape: KeyHelper(false, minifb::Key::Escape, Key::Escape),
            key_home: KeyHelper(false, minifb::Key::Home, Key::Home),
        }
    }

    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render ctx 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    fn drain_events(&mut self) {
        // mouse move
        if let Some(pos) = self.window.get_mouse_pos(minifb::MouseMode::Discard) {
            if pos != self.mouse_pos {
                self.adapter.mouse(pos.0 as f64, pos.1 as f64);
                self.mouse_pos = pos;
            }
        }

        // mouse
        let left_button_down = self.window.get_mouse_down(minifb::MouseButton::Left);
        let middle_button_down = self.window.get_mouse_down(minifb::MouseButton::Middle);
        let right_button_down = self.window.get_mouse_down(minifb::MouseButton::Right);

        if left_button_down != self.button_down.0 {
            if left_button_down {
                self.push_mouse_event(true, MouseButton::Left);
            } else {
                self.push_mouse_event(false, MouseButton::Left);
            }
            self.button_down.0 = left_button_down;
        }

        if middle_button_down != self.button_down.1 {
            if middle_button_down {
                self.push_mouse_event(true, MouseButton::Middle);
            } else {
                self.push_mouse_event(false, MouseButton::Middle);
            }
            self.button_down.1 = middle_button_down;
        }

        if right_button_down != self.button_down.2 {
            if right_button_down {
                self.push_mouse_event(true, MouseButton::Right);
            } else {
                self.push_mouse_event(false, MouseButton::Right);
            }
            self.button_down.2 = right_button_down;
        }

        // scroll
        if let Some(delta) = self.window.get_scroll_wheel() {
            self.adapter.scroll(delta.0 as f64, delta.1 as f64);
        }

        // key
        while let Some(event) = self.key_events.borrow_mut().pop() {
            self.adapter.key_event(event);
        }

        key_event_helper(&mut self.key_backspace, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_delete, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_left, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_right, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_up, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_down, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_enter, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_control, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_control_right, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_shift_l, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_shift_r, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_alt, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_alt_r, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_escape, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_home, &mut self.adapter, &self.window);

        // resize
        if self.window_size != self.window.get_size() {
            self.window_size = self.window.get_size();
            self.render_context_2_d
                .resize(self.window_size.0 as f64, self.window_size.1 as f64);
            self.adapter
                .resize(self.window_size.0 as f64, self.window_size.1 as f64);
        }
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            x: self.mouse_pos.0 as f64,
            y: self.mouse_pos.1 as f64,
            button,
            state,
        });
    }

    pub fn flip(&mut self) -> bool {
        if let Some(data) = self.render_context_2_d.data() {
            self.window.update_with_buffer(data).unwrap();
            CONSOLE.time_end("render");
            return true;
        }

        false
    }
}

impl Drop for WindowShell
where
    A: WindowAdapter,
{
    fn drop(&mut self) {}
}

/// Implementation of the OrbClient based shell runner.
pub struct ShellRunner
where
    A: WindowAdapter,
{
    pub window_shell: Rc<RefCell<WindowShell>>,
    pub update: Rc<Cell<bool>>,
    pub running: Rc<Cell<bool>>,
    pub updater: Box<dyn Updater>,
}

impl ShellRunner
where
    A: WindowAdapter,
{
    pub fn run(&mut self) {
        let mut loop_helper = LoopHelper::builder()
            .report_interval_s(0.5)
            .build_with_target_rate(60.0);

        let mut _current_fps = None;

        loop {
            if !self.running.get() || !self.window_shell.borrow().window.is_open() {
                break;
            }

            let _delta = loop_helper.loop_start();

            if let Some(fps) = loop_helper.report_rate() {
                _current_fps = Some(fps);
                // println!("fps: {}", fps);
            }

            // CONSOLE.time("complete run");

            self.updater.update();

            if self.update.get() {
                self.update.set(false);
            }

            if !self.window_shell.borrow_mut().flip() {
                self.window_shell.borrow_mut().window.update();
            }

            self.window_shell.borrow_mut().drain_events();

            loop_helper.loop_sleep();
            // CONSOLE.time_end("complete run");
        }
    }
}

/// Constructs the window shell
pub struct WindowBuilder
where
    A: WindowAdapter,
{
    title: String,

    resizeable: bool,

    bounds: Rectangle,

    adapter: A,
}

impl WindowBuilder
where
    A: WindowAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        WindowBuilder {
            adapter,
            title: String::default(),
            resizeable: false,
            bounds: Rectangle::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rectangle>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(self) -> WindowShell {
        let window_options = minifb::WindowOptions {
            resize: self.resizeable,
            ..Default::default()
        };

        let mut window = minifb::Window::new(
            self.title.as_str(),
            self.bounds.width as usize,
            self.bounds.height as usize,
            window_options,
        )
        .unwrap_or_else(|e| {
            panic!("{}", e);
        });

        let key_events = Rc::new(RefCell::new(vec![]));

        window.set_input_callback(Box::new(KeyInputCallBack {
            key_events: key_events.clone(),
        }));

        window.set_position(self.bounds.x as isize, self.bounds.y as isize);

        WindowShell::new(window, self.adapter, key_events)
    }
}

use std::time::Instant;

lazy_static! {
    pub static ref CONSOLE: Console = Console {
        instants: Mutex::new(HashMap::new())
    };
}

pub struct Console {
    instants: Mutex<HashMap<String, Instant>>,
}

impl Console {
    pub fn time(&self, name: impl Into<String>) {
        self.instants
            .lock()
            .unwrap()
            .insert(name.into(), Instant::now());
    }

    pub fn time_end(&self, name: impl Into<String>) {
        if let Some((k, v)) = self.instants.lock().unwrap().remove_entry(&name.into()) {
            println!("{} {}ms - timer ended", k, v.elapsed().as_millis());
        }
    }

    pub fn log(&self, message: impl Into<String>) {
        println!("{}", message.into());
    }
}
<commit_msg>Fix extra char inserted on backspace<commit_after>//! This module contains a platform specific implementation of the window shell.

use std::{
    cell::{Cell, RefCell},
    char,
    collections::HashMap,
    rc::Rc,
    sync::Mutex,
};

#[cfg(not(target_os = "redox"))]
use minifb;

#[cfg(target_os = "redox")]
use minifb_fix as minifb;

use spin_sleep::LoopHelper;

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {}

fn key_event_helper(key: &mut KeyHelper, adapter: &mut A, window: &minifb::Window)
where
    A: WindowAdapter,
{
    if !key.0 && window.is_key_pressed(key.1, minifb::KeyRepeat::Yes) {
        adapter.key_event(KeyEvent {
            key: key.2,
            state: ButtonState::Down,
            text: String::new(),
        });

        key.0 = true;
    } else {
        key.0 = false;
    }
}

fn unicode_to_key_event(uni_char: u32) -> Option<KeyEvent> {
    let mut text = String::new();
    let mut key = Key::Unknown;

    if let Some(ch) = char::from_u32(uni_char) {
        if !ch.is_control() {
            text = ch.to_string();
            key = Key::from(ch);
        }
    }

    if key == Key::Up || key == Key::Down || key == Key::Left || key == Key::Right {
        return None;
    }

    Some(KeyEvent {
        key,
        state: ButtonState::Down,
        text,
    })
}

struct KeyInputCallBack {
    key_events: Rc<RefCell<Vec<KeyEvent>>>,
}

impl minifb::InputCallback for KeyInputCallBack {
    fn add_char(&mut self, uni_char: u32) {
        if let Some(key_event) = unicode_to_key_event(uni_char) {
            self.key_events.borrow_mut().push(key_event);
        }
    }
}

struct KeyHelper(bool, minifb::Key, Key);

/// Concrete implementation of the window shell.
pub struct WindowShell
where
    A: WindowAdapter,
{
    window: minifb::Window,
    render_context_2_d: RenderContext2D,
    adapter: A,
    mouse_pos: (f32, f32),
    button_down: (bool, bool, bool),
    window_size: (usize, usize),
    key_events: Rc<RefCell<Vec<KeyEvent>>>,
    // todo: temp solution
    key_backspace: KeyHelper,
    key_delete: KeyHelper,
    key_left: KeyHelper,
    key_right: KeyHelper,
    key_up: KeyHelper,
    key_down: KeyHelper,
    key_enter: KeyHelper,
    key_control: KeyHelper,
    key_control_right: KeyHelper,
    key_shift_l: KeyHelper,
    key_shift_r: KeyHelper,
    key_alt: KeyHelper,
    key_alt_r: KeyHelper,
    key_escape: KeyHelper,
    key_home: KeyHelper,
}

impl WindowShell
where
    A: WindowAdapter,
{
    /// Creates a new window shell with an adapter.
    pub fn new(
        window: minifb::Window,
        adapter: A,
        key_events: Rc<RefCell<Vec<KeyEvent>>>,
    ) -> WindowShell {
        let size = window.get_size();
        let render_context_2_d = RenderContext2D::new(size.0 as f64, size.1 as f64);

        WindowShell {
            window,
            // window_size: window_size,
            // mouse_buttons: (false, false, false),
            // mouse_position: Point::default(),
            render_context_2_d,
            adapter,
            mouse_pos: (0.0, 0.0),
            window_size: size,
            button_down: (false, false, false),
            key_events,
            key_backspace: KeyHelper(false, minifb::Key::Backspace, Key::Backspace),
            key_left: KeyHelper(false, minifb::Key::Left, Key::Left),
            key_right: KeyHelper(false, minifb::Key::Right, Key::Right),
            key_up: KeyHelper(false, minifb::Key::Up, Key::Up),
            key_down: KeyHelper(false, minifb::Key::Down, Key::Down),
            key_delete: KeyHelper(false, minifb::Key::Delete, Key::Delete),
            key_enter: KeyHelper(false, minifb::Key::Enter, Key::Enter),
            key_control: KeyHelper(false, minifb::Key::LeftCtrl, Key::Control),
            key_control_right: KeyHelper(false, minifb::Key::RightCtrl, Key::Control),
            key_shift_l: KeyHelper(false, minifb::Key::LeftShift, Key::ShiftL),
            key_shift_r: KeyHelper(false, minifb::Key::RightShift, Key::ShiftR),
            key_alt: KeyHelper(false, minifb::Key::LeftAlt, Key::Alt),
            key_alt_r: KeyHelper(false, minifb::Key::RightAlt, Key::Alt),
            key_escape: KeyHelper(false, minifb::Key::Escape, Key::Escape),
            key_home: KeyHelper(false, minifb::Key::Home, Key::Home),
        }
    }

    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render ctx 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    fn drain_events(&mut self) {
        // mouse move
        if let Some(pos) = self.window.get_mouse_pos(minifb::MouseMode::Discard) {
            if pos != self.mouse_pos {
                self.adapter.mouse(pos.0 as f64, pos.1 as f64);
                self.mouse_pos = pos;
            }
        }

        // mouse
        let left_button_down = self.window.get_mouse_down(minifb::MouseButton::Left);
        let middle_button_down = self.window.get_mouse_down(minifb::MouseButton::Middle);
        let right_button_down = self.window.get_mouse_down(minifb::MouseButton::Right);

        if left_button_down != self.button_down.0 {
            if left_button_down {
                self.push_mouse_event(true, MouseButton::Left);
            } else {
                self.push_mouse_event(false, MouseButton::Left);
            }
            self.button_down.0 = left_button_down;
        }

        if middle_button_down != self.button_down.1 {
            if middle_button_down {
                self.push_mouse_event(true, MouseButton::Middle);
            } else {
                self.push_mouse_event(false, MouseButton::Middle);
            }
            self.button_down.1 = middle_button_down;
        }

        if right_button_down != self.button_down.2 {
            if right_button_down {
                self.push_mouse_event(true, MouseButton::Right);
            } else {
                self.push_mouse_event(false, MouseButton::Right);
            }
            self.button_down.2 = right_button_down;
        }

        // scroll
        if let Some(delta) = self.window.get_scroll_wheel() {
            self.adapter.scroll(delta.0 as f64, delta.1 as f64);
        }

        // key
        while let Some(event) = self.key_events.borrow_mut().pop() {
            self.adapter.key_event(event);
        }

        key_event_helper(&mut self.key_backspace, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_delete, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_left, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_right, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_up, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_down, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_enter, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_control, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_control_right, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_shift_l, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_shift_r, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_alt, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_alt_r, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_escape, &mut self.adapter, &self.window);
        key_event_helper(&mut self.key_home, &mut self.adapter, &self.window);

        // resize
        if self.window_size != self.window.get_size() {
            self.window_size = self.window.get_size();
            self.render_context_2_d
                .resize(self.window_size.0 as f64, self.window_size.1 as f64);
            self.adapter
                .resize(self.window_size.0 as f64, self.window_size.1 as f64);
        }
    }

    fn push_mouse_event(&mut self, pressed: bool, button: MouseButton) {
        let state = if pressed {
            ButtonState::Down
        } else {
            ButtonState::Up
        };

        self.adapter.mouse_event(MouseEvent {
            x: self.mouse_pos.0 as f64,
            y: self.mouse_pos.1 as f64,
            button,
            state,
        });
    }

    pub fn flip(&mut self) -> bool {
        if let Some(data) = self.render_context_2_d.data() {
            self.window.update_with_buffer(data).unwrap();
            CONSOLE.time_end("render");
            return true;
        }

        false
    }
}

impl Drop for WindowShell
where
    A: WindowAdapter,
{
    fn drop(&mut self) {}
}

/// Implementation of the OrbClient based shell runner.
pub struct ShellRunner
where
    A: WindowAdapter,
{
    pub window_shell: Rc<RefCell<WindowShell>>,
    pub update: Rc<Cell<bool>>,
    pub running: Rc<Cell<bool>>,
    pub updater: Box<dyn Updater>,
}

impl ShellRunner
where
    A: WindowAdapter,
{
    pub fn run(&mut self) {
        let mut loop_helper = LoopHelper::builder()
            .report_interval_s(0.5)
            .build_with_target_rate(60.0);

        let mut _current_fps = None;

        loop {
            if !self.running.get() || !self.window_shell.borrow().window.is_open() {
                break;
            }

            let _delta = loop_helper.loop_start();

            if let Some(fps) = loop_helper.report_rate() {
                _current_fps = Some(fps);
                // println!("fps: {}", fps);
            }

            // CONSOLE.time("complete run");

            self.updater.update();

            if self.update.get() {
                self.update.set(false);
            }

            if !self.window_shell.borrow_mut().flip() {
                self.window_shell.borrow_mut().window.update();
            }

            self.window_shell.borrow_mut().drain_events();

            loop_helper.loop_sleep();
            // CONSOLE.time_end("complete run");
        }
    }
}

/// Constructs the window shell
pub struct WindowBuilder
where
    A: WindowAdapter,
{
    title: String,

    resizeable: bool,

    bounds: Rectangle,

    adapter: A,
}

impl WindowBuilder
where
    A: WindowAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        WindowBuilder {
            adapter,
            title: String::default(),
            resizeable: false,
            bounds: Rectangle::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rectangle>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(self) -> WindowShell {
        let window_options = minifb::WindowOptions {
            resize: self.resizeable,
            ..Default::default()
        };

        let mut window = minifb::Window::new(
            self.title.as_str(),
            self.bounds.width as usize,
            self.bounds.height as usize,
            window_options,
        )
        .unwrap_or_else(|e| {
            panic!("{}", e);
        });

        let key_events = Rc::new(RefCell::new(vec![]));

        window.set_input_callback(Box::new(KeyInputCallBack {
            key_events: key_events.clone(),
        }));

        window.set_position(self.bounds.x as isize, self.bounds.y as isize);

        WindowShell::new(window, self.adapter, key_events)
    }
}

use std::time::Instant;

lazy_static! {
    pub static ref CONSOLE: Console = Console {
        instants: Mutex::new(HashMap::new())
    };
}

pub struct Console {
    instants: Mutex<HashMap<String, Instant>>,
}

impl Console {
    pub fn time(&self, name: impl Into<String>) {
        self.instants
            .lock()
            .unwrap()
            .insert(name.into(), Instant::now());
    }

    pub fn time_end(&self, name: impl Into<String>) {
        if let Some((k, v)) = self.instants.lock().unwrap().remove_entry(&name.into()) {
            println!("{} {}ms - timer ended", k, v.elapsed().as_millis());
        }
    }

    pub fn log(&self, message: impl Into<String>) {
        println!("{}", message.into());
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate rand;

const RAND_BENCH_N: u64 = 1000;

use test::{black_box, Bencher};

use rand::prelude::*;
use rand::seq::*;

#[bench]
fn misc_gen_bool(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let mut accum = true;
        for _ in 0..::RAND_BENCH_N {
            accum ^= rng.gen_bool(0.18);
        }
        black_box(accum);
    })
}

#[bench]
fn misc_gen_bool_var(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let mut p = 0.18;
        let mut accum = true;
        for _ in 0..::RAND_BENCH_N {
            accum ^= rng.gen_bool(p);
            p += 0.0001;
        }
        black_box(accum);
    })
}

#[bench]
fn misc_shuffle_100(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
    let x : &mut [usize] = &mut [1; 100];
    b.iter(|| {
        rng.shuffle(x);
        black_box(&x);
    })
}

#[bench]
fn misc_sample_iter_10_of_100(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
    let x : &[usize] = &[1; 100];
    b.iter(|| {
        black_box(sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e));
    })
}

#[bench]
fn misc_sample_slice_10_of_100(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
    let x : &[usize] = &[1; 100];
    b.iter(|| {
        black_box(sample_slice(&mut rng, x, 10));
    })
}

#[bench]
fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
    let x : &[usize] = &[1; 100];
    b.iter(|| {
        black_box(sample_slice_ref(&mut rng, x, 10));
    })
}

macro_rules! sample_indices {
    ($name:ident, $amount:expr, $length:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
            b.iter(|| {
                black_box(sample_indices(&mut rng, $length, $amount));
            })
        }
    }
}

sample_indices!(misc_sample_indices_10_of_1k, 10, 1000);
sample_indices!(misc_sample_indices_50_of_1k, 50, 1000);
sample_indices!(misc_sample_indices_100_of_1k, 100, 1000);

#[bench]
fn gen_1k_iter_repeat(b: &mut Bencher) {
    use std::iter;
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let v: Vec<u64> = iter::repeat(()).map(|()| rng.gen()).take(128).collect();
        black_box(v);
    });
    b.bytes = 1024;
}

#[bench]
#[allow(deprecated)]
fn gen_1k_gen_iter(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let v: Vec<u64> = rng.gen_iter().take(128).collect();
        black_box(v);
    });
    b.bytes = 1024;
}

#[bench]
fn gen_1k_sample_iter(b: &mut Bencher) {
    use rand::distributions::{Distribution, Standard};
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let v: Vec<u64> = Standard.sample_iter(&mut rng).take(128).collect();
        black_box(v);
    });
    b.bytes = 1024;
}

#[bench]
fn gen_1k_fill(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    let mut buf = [0u64; 128];
    b.iter(|| {
        rng.fill(&mut buf[..]);
        black_box(buf);
    });
    b.bytes = 1024;
}
<commit_msg>Benchmark gen_bool vs. Bernoulli::sample<commit_after>#![feature(test)]

extern crate test;
extern crate rand;

const RAND_BENCH_N: u64 = 1000;

use test::{black_box, Bencher};

use rand::prelude::*;
use rand::seq::*;

#[bench]
fn misc_gen_bool(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let mut accum = true;
        for _ in 0..::RAND_BENCH_N {
            accum ^= rng.gen_bool(0.18);
        }
        black_box(accum);
    })
}

#[bench]
fn misc_gen_bool_var(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let mut p = 0.18;
        let mut accum = true;
        for _ in 0..::RAND_BENCH_N {
            accum ^= rng.gen_bool(p);
            p += 0.0001;
        }
        black_box(accum);
    })
}

#[bench]
fn misc_bernoulli(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    let d = rand::distributions::Bernoulli::new(0.18);
    b.iter(|| {
        let mut accum = true;
        for _ in 0..::RAND_BENCH_N {
            accum ^= rng.sample(d);
        }
        black_box(accum);
    })
}

#[bench]
fn misc_bernoulli_var(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let mut p = 0.18;
        let mut accum = true;
        for _ in 0..::RAND_BENCH_N {
            let d = rand::distributions::Bernoulli::new(p);
            accum ^= rng.sample(d);
            p += 0.0001;
        }
        black_box(accum);
    })
}

#[bench]
fn misc_shuffle_100(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
    let x : &mut [usize] = &mut [1; 100];
    b.iter(|| {
        rng.shuffle(x);
        black_box(&x);
    })
}

#[bench]
fn misc_sample_iter_10_of_100(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
    let x : &[usize] = &[1; 100];
    b.iter(|| {
        black_box(sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e));
    })
}

#[bench]
fn misc_sample_slice_10_of_100(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
    let x : &[usize] = &[1; 100];
    b.iter(|| {
        black_box(sample_slice(&mut rng, x, 10));
    })
}

#[bench]
fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
    let x : &[usize] = &[1; 100];
    b.iter(|| {
        black_box(sample_slice_ref(&mut rng, x, 10));
    })
}

macro_rules! sample_indices {
    ($name:ident, $amount:expr, $length:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
            b.iter(|| {
                black_box(sample_indices(&mut rng, $length, $amount));
            })
        }
    }
}

sample_indices!(misc_sample_indices_10_of_1k, 10, 1000);
sample_indices!(misc_sample_indices_50_of_1k, 50, 1000);
sample_indices!(misc_sample_indices_100_of_1k, 100, 1000);

#[bench]
fn gen_1k_iter_repeat(b: &mut Bencher) {
    use std::iter;
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let v: Vec<u64> = iter::repeat(()).map(|()| rng.gen()).take(128).collect();
        black_box(v);
    });
    b.bytes = 1024;
}

#[bench]
#[allow(deprecated)]
fn gen_1k_gen_iter(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let v: Vec<u64> = rng.gen_iter().take(128).collect();
        black_box(v);
    });
    b.bytes = 1024;
}

#[bench]
fn gen_1k_sample_iter(b: &mut Bencher) {
    use rand::distributions::{Distribution, Standard};
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    b.iter(|| {
        let v: Vec<u64> = Standard.sample_iter(&mut rng).take(128).collect();
        black_box(v);
    });
    b.bytes = 1024;
}

#[bench]
fn gen_1k_fill(b: &mut Bencher) {
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    let mut buf = [0u64; 128];
    b.iter(|| {
        rng.fill(&mut buf[..]);
        black_box(buf);
    });
    b.bytes = 1024;
}
<|endoftext|>