<commit_before><commit_msg>json: Replace line_reader.rs symlink with a copy for now<commit_after>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use std::collections::VecDeque;

#[derive(Debug)]
pub struct LineReader<T: AsRef<[u8]>> {
    queue: VecDeque<T>,
    // Read position into the queue in bytes
    read_pos: usize,
    // Offset into queue where we have to look for a newline
    // All previous items don't contain a newline
    search_pos: usize,
    buf: Vec<u8>,
}

impl<T: AsRef<[u8]>> LineReader<T> {
    pub fn new() -> LineReader<T> {
        Self {
            queue: VecDeque::new(),
            read_pos: 0,
            search_pos: 0,
            buf: Vec::new(),
        }
    }

    pub fn push(&mut self, b: T) {
        self.queue.push_back(b);
    }

    /// Drops everything from the internal queue that was previously returned, i.e.
    /// if previously a line was returned we drop this whole line so that we can
    /// proceed with the next line
    fn drop_previous_line(&mut self) {
        // Drop everything we read the last time now
        while self.read_pos > 0
            && self.read_pos >= self.queue.front().map(|f| f.as_ref().len()).unwrap_or(0)
        {
            self.read_pos -= self.queue.front().map(|f| f.as_ref().len()).unwrap_or(0);
            self.queue.pop_front();
            if self.search_pos > 0 {
                self.search_pos -= 1;
            }
        }

        self.buf.clear();
    }

    #[allow(unused)]
    pub fn line_or_drain(&mut self) -> Option<&[u8]> {
        self.line_with_drain(true)
    }

    #[allow(unused)]
    pub fn line(&mut self) -> Option<&[u8]> {
        self.line_with_drain(false)
    }

    /// Searches the first '\n' in the currently queued buffers and returns the index in buffers
    /// inside the queue and the index in bytes from the beginning of the queue, or None.
    ///
    /// Also updates the search_pos so that we don't look again in the previous buffers on the next
    /// call
    fn find_newline(&mut self) -> Option<(usize, usize)> {
        let mut offset = 0;
        for (idx, buf) in self.queue.iter().enumerate() {
            let buf = buf.as_ref();

            // Fast skip-ahead
            if idx < self.search_pos {
                offset += buf.len();
                continue;
            }

            let pos = buf
                .iter()
                .enumerate()
                .skip(if idx == 0 { self.read_pos } else { 0 })
                .find(|(_, b)| **b == b'\n')
                .map(|(idx, _)| idx);

            if let Some(pos) = pos {
                // On the next call we have to search in this buffer again
                // as it might contain a second newline
                self.search_pos = idx;
                return Some((idx, offset + pos + 1));
            }

            // This buffer did not contain a newline so we don't have to look
            // in it again next time
            self.search_pos = idx + 1;
            offset += buf.len();
        }

        None
    }

    /// Copies length bytes from all buffers from the beginning until last_idx into our internal
    /// buffer, and skips the first offset bytes from the first buffer.
    fn copy_into_internal_buffer(&mut self, last_idx: usize, offset: usize, len: usize) {
        // Reserve space for the whole line beforehand
        if self.buf.capacity() < len {
            self.buf.reserve(len - self.buf.capacity());
        }

        // Then iterate over all buffers inside the queue until the one that contains
        // the newline character
        for (idx, buf) in self.queue.iter().enumerate().take(last_idx + 1) {
            let buf = buf.as_ref();

            // Calculate how much data we still have to copy
            let rem = len - self.buf.len();
            assert!(rem > 0);

            // For the first index we need to take into account the offset. The first
            // bytes might have to be skipped and as such we have fewer bytes available
            // than the whole length of the buffer
            let buf_len = if idx == 0 {
                assert!(offset < buf.len());
                buf.len() - offset
            } else {
                buf.len()
            };

            // Calculate how much we can copy from this buffer. At most the size of the buffer
            // itself, but never more than the amount we still have to copy overall
            let copy_len = if rem > buf_len { buf_len } else { rem };
            assert!(copy_len > 0);

            if idx == 0 {
                self.buf
                    .extend_from_slice(&buf[offset..(offset + copy_len)]);
            } else {
                self.buf.extend_from_slice(&buf[..copy_len]);
            }
        }

        assert_eq!(self.buf.len(), len);
    }

    pub fn line_with_drain(&mut self, drain: bool) -> Option<&[u8]> {
        // Drop all data from the previous line
        self.drop_previous_line();

        // read_pos must always be inside the first buffer of our queue here
        // or otherwise we went into an inconsistent state: the first buffer(s)
        // would've had to be dropped above then as they are not relevant anymore
        assert!(
            self.read_pos == 0
                || self.read_pos < self.queue.front().map(|f| f.as_ref().len()).unwrap_or(0)
        );

        // Find the next newline character from our previous position
        if let Some((idx, pos)) = self.find_newline() {
            // We now need to copy everything from the old read_pos to the new
            // pos, and on the next call we have to start from the new pos
            let old_read_pos = self.read_pos;
            self.read_pos = pos;

            assert!(self.read_pos > old_read_pos);
            assert!(idx < self.queue.len());

            // If the newline is found in the first buffer in our queue, we can directly return
            // the slice from it without doing any copying.
            //
            // On average this should be the most common case.
            if idx == 0 {
                let buf = self.queue.front().unwrap().as_ref();
                return Some(&buf[old_read_pos..self.read_pos]);
            } else {
                // Copy into our internal buffer as the current line spans multiple buffers
                let len = self.read_pos - old_read_pos;
                self.copy_into_internal_buffer(idx, old_read_pos, len);

                return Some(&self.buf[0..len]);
            }
        }

        // No newline found above and we're not draining, so let's wait until
        // more data is available that might contain a newline character
        if !drain {
            return None;
        }

        if self.queue.is_empty() {
            return None;
        }

        // When draining and we only have a single buffer in the queue we can
        // directly return a slice into it
        if self.queue.len() == 1 {
            let res = &self.queue.front().unwrap().as_ref()[self.read_pos..];
            self.read_pos += res.len();
            self.search_pos = 1;
            return Some(res);
        }

        // Otherwise we have to copy everything that is remaining into our
        // internal buffer and then return a slice from that
        let len = self.queue.iter().map(|v| v.as_ref().len()).sum();
        if self.buf.capacity() < len {
            self.buf.reserve(len - self.buf.capacity());
        }

        for (idx, ref v) in self.queue.iter().enumerate() {
            if idx == 0 {
                self.buf.extend_from_slice(&v.as_ref()[self.read_pos..]);
            } else {
                self.buf.extend_from_slice(v.as_ref());
            }
        }

        self.read_pos += self.buf.len();
        self.search_pos = self.queue.len();

        Some(self.buf.as_ref())
    }

    pub fn clear(&mut self) {
        self.queue.clear();
        self.read_pos = 0;
        self.search_pos = 0;
        self.buf.clear();
    }
}

#[cfg(test)]
mod tests {
    use super::LineReader;

    #[test]
    fn test_single_buffer() {
        let mut r = LineReader::new();
        r.push(Vec::from(b"abcd\nefgh\nijkl\n".as_ref()));

        assert_eq!(r.line(), Some(b"abcd\n".as_ref()));
        assert_eq!(r.line(), Some(b"efgh\n".as_ref()));
        assert_eq!(r.line(), Some(b"ijkl\n".as_ref()));
        assert_eq!(r.line(), None);
    }

    #[test]
    fn test_empty_line() {
        let mut r = LineReader::new();
        r.push(Vec::from(b"abcd\nefgh\n\nijkl\n".as_ref()));

        assert_eq!(r.line(), Some(b"abcd\n".as_ref()));
        assert_eq!(r.line(), Some(b"efgh\n".as_ref()));
        assert_eq!(r.line(), Some(b"\n".as_ref()));
        assert_eq!(r.line(), Some(b"ijkl\n".as_ref()));
        assert_eq!(r.line(), None);
    }

    #[test]
    fn test_multi_buffer_split() {
        let mut r = LineReader::new();
        r.push(Vec::from(b"abcd\nef".as_ref()));
        r.push(Vec::from(b"gh\nijkl\n".as_ref()));

        assert_eq!(r.line(), Some(b"abcd\n".as_ref()));
        assert_eq!(r.line(), Some(b"efgh\n".as_ref()));
        assert_eq!(r.line(), Some(b"ijkl\n".as_ref()));
        assert_eq!(r.line(), None);
    }

    #[test]
    fn test_multi_buffer_split_2() {
        let mut r = LineReader::new();
        r.push(Vec::from(b"abcd\ne".as_ref()));
        r.push(Vec::from(b"f".as_ref()));
        r.push(Vec::from(b"g".as_ref()));
        r.push(Vec::from(b"h\nijkl\n".as_ref()));

        assert_eq!(r.line(), Some(b"abcd\n".as_ref()));
        assert_eq!(r.line(), Some(b"efgh\n".as_ref()));
        assert_eq!(r.line(), Some(b"ijkl\n".as_ref()));
        assert_eq!(r.line(), None);
    }

    #[test]
    fn test_single_buffer_drain() {
        let mut r = LineReader::new();
        r.push(Vec::from(b"abcd\nefgh\nijkl".as_ref()));

        assert_eq!(r.line(), Some(b"abcd\n".as_ref()));
        assert_eq!(r.line(), Some(b"efgh\n".as_ref()));
        assert_eq!(r.line(), None);
        assert_eq!(r.line_or_drain(), Some(b"ijkl".as_ref()));
        assert_eq!(r.line_or_drain(), None);
    }

    #[test]
    fn test_single_buffer_drain_multi_line() {
        let mut r = LineReader::new();
        r.push(Vec::from(b"abcd\nefgh\n".as_ref()));
        r.push(Vec::from(b"ijkl".as_ref()));

        assert_eq!(r.line(), Some(b"abcd\n".as_ref()));
        assert_eq!(r.line(), Some(b"efgh\n".as_ref()));
        assert_eq!(r.line(), None);
        assert_eq!(r.line_or_drain(), Some(b"ijkl".as_ref()));
        assert_eq!(r.line_or_drain(), None);
    }

    #[test]
    fn test_single_buffer_drain_multi_line_2() {
        let mut r = LineReader::new();
        r.push(Vec::from(b"abcd\nefgh\ni".as_ref()));
        r.push(Vec::from(b"j".as_ref()));
        r.push(Vec::from(b"k".as_ref()));
        r.push(Vec::from(b"l".as_ref()));

        assert_eq!(r.line(), Some(b"abcd\n".as_ref()));
        assert_eq!(r.line(), Some(b"efgh\n".as_ref()));
        assert_eq!(r.line(), None);
        assert_eq!(r.line_or_drain(), Some(b"ijkl".as_ref()));
        assert_eq!(r.line_or_drain(), None);
    }
}
<|endoftext|>


<commit_before>extern crate unidiff;

use std::io::prelude::*;
use std::fs::File;

use unidiff::PatchSet;

#[test]
fn test_parse_sample0_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/sample0.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    assert_eq!(3, patch.len());
}

#[test]
fn test_parse_git_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/git.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    assert_eq!(3, patch.len());

    let added_files = patch.added_files();
    assert_eq!(1, added_files.len());
    assert_eq!("added_file", added_files[0].path());
    assert_eq!(4, added_files[0].added());
    assert_eq!(0, added_files[0].removed());

    let removed_files = patch.removed_files();
    assert_eq!(1, removed_files.len());
    assert_eq!("removed_file", removed_files[0].path());
    assert_eq!(0, removed_files[0].added());
    assert_eq!(3, removed_files[0].removed());

    let modified_files = patch.modified_files();
    assert_eq!(1, modified_files.len());
    assert_eq!("modified_file", modified_files[0].path());
    assert_eq!(3, modified_files[0].added());
    assert_eq!(1, modified_files[0].removed());
}

#[test]
fn test_parse_bzr_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/bzr.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    assert_eq!(3, patch.len());

    let added_files = patch.added_files();
    assert_eq!(1, added_files.len());
    assert_eq!("added_file", added_files[0].path());
    assert_eq!(4, added_files[0].added());
    assert_eq!(0, added_files[0].removed());

    let removed_files = patch.removed_files();
    assert_eq!(1, removed_files.len());
    assert_eq!("removed_file", removed_files[0].path());
    assert_eq!(0, removed_files[0].added());
    assert_eq!(3, removed_files[0].removed());

    let modified_files = patch.modified_files();
    assert_eq!(1, modified_files.len());
    assert_eq!("modified_file", modified_files[0].path());
    assert_eq!(3, modified_files[0].added());
    assert_eq!(1, modified_files[0].removed());
}

#[test]
fn test_parse_hg_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/hg.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    assert_eq!(3, patch.len());

    let added_files = patch.added_files();
    assert_eq!(1, added_files.len());
    assert_eq!("added_file", added_files[0].path());
    assert_eq!(4, added_files[0].added());
    assert_eq!(0, added_files[0].removed());

    let removed_files = patch.removed_files();
    assert_eq!(1, removed_files.len());
    assert_eq!("removed_file", removed_files[0].path());
    assert_eq!(0, removed_files[0].added());
    assert_eq!(3, removed_files[0].removed());

    let modified_files = patch.modified_files();
    assert_eq!(1, modified_files.len());
    assert_eq!("modified_file", modified_files[0].path());
    assert_eq!(3, modified_files[0].added());
    assert_eq!(1, modified_files[0].removed());
}

#[test]
fn test_parse_svn_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/svn.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    assert_eq!(3, patch.len());

    let added_files = patch.added_files();
    assert_eq!(1, added_files.len());
    assert_eq!("added_file", added_files[0].path());
    assert_eq!(4, added_files[0].added());
    assert_eq!(0, added_files[0].removed());

    let removed_files = patch.removed_files();
    assert_eq!(1, removed_files.len());
    assert_eq!("removed_file", removed_files[0].path());
    assert_eq!(0, removed_files[0].added());
    assert_eq!(3, removed_files[0].removed());

    let modified_files = patch.modified_files();
    assert_eq!(1, modified_files.len());
    assert_eq!("modified_file", modified_files[0].path());
    assert_eq!(3, modified_files[0].added());
    assert_eq!(1, modified_files[0].removed());
}
<commit_msg>Update test cases<commit_after>extern crate unidiff;

use std::io::prelude::*;
use std::fs::File;

use unidiff::PatchSet;

#[test]
fn test_parse_sample0_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/sample0.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    // three file in the patch
    assert_eq!(3, patch.len());
    // three hunks
    assert_eq!(3, patch[0].len());

    // first file is modified
    assert!(patch[0].is_modified_file());
    assert!(!patch[0].is_added_file());
    assert!(!patch[0].is_removed_file());

    // Hunk 1: five additions, no deletions, a section header
    assert_eq!(6, patch[0][0].added);
    assert_eq!(0, patch[0][0].removed);
    assert_eq!("Section Header", &patch[0][0].section_header);

    // Hunk 2: 2 additions, 8 deletions, no section header
    assert_eq!(2, patch[0][1].added);
    assert_eq!(8, patch[0][1].removed);
    assert_eq!("", &patch[0][1].section_header);

    // Hunk 3: four additions, no deletions, no section header
    assert_eq!(4, patch[0][2].added);
    assert_eq!(0, patch[0][2].removed);
    assert_eq!("", &patch[0][2].section_header);

    // Check file totals
    assert_eq!(12, patch[0].added());
    assert_eq!(8, patch[0].removed());

    // second file is added
    assert!(!patch[1].is_modified_file());
    assert!(patch[1].is_added_file());
    assert!(!patch[1].is_removed_file());

    // third file is removed
    assert!(!patch[2].is_modified_file());
    assert!(!patch[2].is_added_file());
    assert!(patch[2].is_removed_file());
}

#[test]
fn test_parse_git_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/git.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    assert_eq!(3, patch.len());

    let added_files = patch.added_files();
    assert_eq!(1, added_files.len());
    assert_eq!("added_file", added_files[0].path());
    assert_eq!(4, added_files[0].added());
    assert_eq!(0, added_files[0].removed());

    let removed_files = patch.removed_files();
    assert_eq!(1, removed_files.len());
    assert_eq!("removed_file", removed_files[0].path());
    assert_eq!(0, removed_files[0].added());
    assert_eq!(3, removed_files[0].removed());

    let modified_files = patch.modified_files();
    assert_eq!(1, modified_files.len());
    assert_eq!("modified_file", modified_files[0].path());
    assert_eq!(3, modified_files[0].added());
    assert_eq!(1, modified_files[0].removed());
}

#[test]
fn test_parse_bzr_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/bzr.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    assert_eq!(3, patch.len());

    let added_files = patch.added_files();
    assert_eq!(1, added_files.len());
    assert_eq!("added_file", added_files[0].path());
    assert_eq!(4, added_files[0].added());
    assert_eq!(0, added_files[0].removed());

    let removed_files = patch.removed_files();
    assert_eq!(1, removed_files.len());
    assert_eq!("removed_file", removed_files[0].path());
    assert_eq!(0, removed_files[0].added());
    assert_eq!(3, removed_files[0].removed());

    let modified_files = patch.modified_files();
    assert_eq!(1, modified_files.len());
    assert_eq!("modified_file", modified_files[0].path());
    assert_eq!(3, modified_files[0].added());
    assert_eq!(1, modified_files[0].removed());
}

#[test]
fn test_parse_hg_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/hg.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    assert_eq!(3, patch.len());

    let added_files = patch.added_files();
    assert_eq!(1, added_files.len());
    assert_eq!("added_file", added_files[0].path());
    assert_eq!(4, added_files[0].added());
    assert_eq!(0, added_files[0].removed());

    let removed_files = patch.removed_files();
    assert_eq!(1, removed_files.len());
    assert_eq!("removed_file", removed_files[0].path());
    assert_eq!(0, removed_files[0].added());
    assert_eq!(3, removed_files[0].removed());

    let modified_files = patch.modified_files();
    assert_eq!(1, modified_files.len());
    assert_eq!("modified_file", modified_files[0].path());
    assert_eq!(3, modified_files[0].added());
    assert_eq!(1, modified_files[0].removed());
}

#[test]
fn test_parse_svn_diff() {
    let mut buf = String::new();
    File::open("tests/fixtures/svn.diff").and_then(|mut r| r.read_to_string(&mut buf)).unwrap();

    let mut patch = PatchSet::new();
    patch.parse(&buf).unwrap();

    assert_eq!(3, patch.len());

    let added_files = patch.added_files();
    assert_eq!(1, added_files.len());
    assert_eq!("added_file", added_files[0].path());
    assert_eq!(4, added_files[0].added());
    assert_eq!(0, added_files[0].removed());

    let removed_files = patch.removed_files();
    assert_eq!(1, removed_files.len());
    assert_eq!("removed_file", removed_files[0].path());
    assert_eq!(0, removed_files[0].added());
    assert_eq!(3, removed_files[0].removed());

    let modified_files = patch.modified_files();
    assert_eq!(1, modified_files.len());
    assert_eq!("modified_file", modified_files[0].path());
    assert_eq!(3, modified_files[0].added());
    assert_eq!(1, modified_files[0].removed());
}
<|endoftext|>


<commit_before>#![feature(conservative_impl_trait)]

extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Remote, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;
use std::collections::HashMap;
use std::cell::RefCell;

type Id = u32;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(HashMap::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (receive_channel_out, receive_channel_in) = mpsc::unbounded();

    let conn_id = Rc::new(RefCell::new(Counter::new()));
    let connections_inner = connections.clone();
    // Handle new connection
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections_inner = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            let channel = receive_channel_out.clone();
            let handle_inner = handle.clone();
            let conn_id = conn_id.clone();
            let f = upgrade
                .accept()
                .and_then(move |(framed, _)| {
                    let id = conn_id
                        .borrow_mut()
                        .next()
                        .expect("maximum amount of ids reached");
                    let (sink, stream) = framed.split();
                    let f = channel.send((id, stream));
                    spawn_future(f, "Senk stream to connection pool", &handle_inner);
                    connections_inner.write().unwrap().insert(id, sink);
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle);
            Ok(())
        })
        .map_err(|_| ());

    // Handle receiving messages from a client
    let state_read = state.clone();
    let remote_inner = remote.clone();
    let receive_handler = pool.spawn_fn(|| {
        receive_channel_in.for_each(move |(id, stream)| {
            let state_read = state_read.clone();
            remote_inner.spawn(move |_| {
                stream.for_each(move |msg| {
                                    process_message(id, &msg, &mut state_read.write().unwrap());
                                    Ok(())
                                })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (send_channel_out, send_channel_in) = mpsc::unbounded();

    // Handle sending messages to a client
    let connections_inner = connections.clone();
    let remote_inner = remote.clone();
    let send_handler =
        pool.spawn_fn(move || {
            let connections = connections_inner.clone();
            let remote = remote_inner.clone();
            send_channel_in.for_each(move |(id, state): (Id, Arc<RwLock<State>>)| {
                    let connections = connections.clone();
                    let sink = connections.write()
                        .unwrap()
                        .remove(&id)
                        .expect("Tried to send to invalid client id");

                    let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                    println!("Sending message: {}", msg);
                    let f = sink.send(OwnedMessage::Text(msg)).and_then(move |sink| {
                        connections.write().unwrap().insert(id, sink);
                        Ok(())
                    });
                    remote.spawn(move |_| f.map_err(|_| ()));
                    Ok(())
                })
                .map_err(|_| ())
        });

    // Main 'logic' loop
    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(send_channel_out, move |send_channel_out| {
            thread::sleep(Duration::from_millis(100));

            let should_continue = update(connections.clone(),
                                         state.clone(),
                                         send_channel_out.clone(),
                                         &remote);
            match should_continue {
                Ok(true) => Ok(Loop::Continue(send_channel_out)),
                Ok(false) => Ok(Loop::Break(())),
                Err(()) => Err(()),
            }
        })
    });

    let handlers =
        game_loop.select2(connection_handler.select2(receive_handler.select(send_handler)));
    core.run(handlers).map_err(|_| println!("Error while running core loop")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn process_message(_: u32, msg: &OwnedMessage, _: &mut State) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

type SinkContent =
    websocket::client::async::Framed<tokio_core::net::TcpStream,
                                     websocket::async::MessageCodec<OwnedMessage>>;
type SplitSink = futures::stream::SplitSink<SinkContent>;
// Represents one tick in the main loop
fn update(connections: Arc<RwLock<HashMap<Id, SplitSink>>>,
          state: Arc<RwLock<State>>,
          channel: mpsc::UnboundedSender<(Id, Arc<RwLock<State>>)>,
          remote: &Remote)
          -> Result<bool, ()> {
    remote.spawn(move |handle| {
        for (id, _) in connections.read().unwrap().iter() {
            let f = channel.clone().send((*id, state.clone()));
            spawn_future(f, "Send message to write handler", handle);
        }
        Ok(())
    });
    Ok(true)
}

struct Counter {
    count: Id,
}
impl Counter {
    fn new() -> Self {
        Counter { count: 0 }
    }
}

impl Iterator for Counter {
    type Item = Id;

    fn next(&mut self) -> Option<Id> {
        if self.count != Id::max_value() {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}

<commit_msg>Update rustfmt to v9.0<commit_after>#![feature(conservative_impl_trait)]

extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Remote, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;
use std::collections::HashMap;
use std::cell::RefCell;

type Id = u32;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(HashMap::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (receive_channel_out, receive_channel_in) = mpsc::unbounded();

    let conn_id = Rc::new(RefCell::new(Counter::new()));
    let connections_inner = connections.clone();
    // Handle new connection
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections_inner = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            let channel = receive_channel_out.clone();
            let handle_inner = handle.clone();
            let conn_id = conn_id.clone();
            let f = upgrade
                .accept()
                .and_then(move |(framed, _)| {
                    let id = conn_id
                        .borrow_mut()
                        .next()
                        .expect("maximum amount of ids reached");
                    let (sink, stream) = framed.split();
                    let f = channel.send((id, stream));
                    spawn_future(f, "Senk stream to connection pool", &handle_inner);
                    connections_inner.write().unwrap().insert(id, sink);
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle);
            Ok(())
        })
        .map_err(|_| ());

    // Handle receiving messages from a client
    let state_read = state.clone();
    let remote_inner = remote.clone();
    let receive_handler = pool.spawn_fn(|| {
        receive_channel_in.for_each(move |(id, stream)| {
            let state_read = state_read.clone();
            remote_inner.spawn(move |_| {
                stream
                    .for_each(move |msg| {
                        process_message(id, &msg, &mut state_read.write().unwrap());
                        Ok(())
                    })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (send_channel_out, send_channel_in) = mpsc::unbounded();

    // Handle sending messages to a client
    let connections_inner = connections.clone();
    let remote_inner = remote.clone();
    let send_handler = pool.spawn_fn(move || {
        let connections = connections_inner.clone();
        let remote = remote_inner.clone();
        send_channel_in
            .for_each(move |(id, state): (Id, Arc<RwLock<State>>)| {
                let connections = connections.clone();
                let sink = connections.write().unwrap().remove(&id).expect(
                    "Tried to send to invalid client id",
                );

                let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                println!("Sending message: {}", msg);
                let f = sink.send(OwnedMessage::Text(msg)).and_then(move |sink| {
                    connections.write().unwrap().insert(id, sink);
                    Ok(())
                });
                remote.spawn(move |_| f.map_err(|_| ()));
                Ok(())
            })
            .map_err(|_| ())
    });

    // Main 'logic' loop
    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(send_channel_out, move |send_channel_out| {
            thread::sleep(Duration::from_millis(100));

            let should_continue = update(
                connections.clone(),
                state.clone(),
                send_channel_out.clone(),
                &remote,
            );
            match should_continue {
                Ok(true) => Ok(Loop::Continue(send_channel_out)),
                Ok(false) => Ok(Loop::Break(())),
                Err(()) => Err(()),
            }
        })
    });

    let handlers = game_loop.select2(connection_handler.select2(
        receive_handler.select(send_handler),
    ));
    core.run(handlers)
        .map_err(|_| println!("Error while running core loop"))
        .unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
where
    F: Future<Item = I, Error = E> + 'static,
    E: Debug,
{
    handle.spawn(
        f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
            .map(move |_| println!("{}: Finished.", desc)),
    );
}

fn process_message(_: u32, msg: &OwnedMessage, _: &mut State) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

type SinkContent = websocket::client::async::Framed<
    tokio_core::net::TcpStream,
    websocket::async::MessageCodec<OwnedMessage>,
>;
type SplitSink = futures::stream::SplitSink<SinkContent>;
// Represents one tick in the main loop
fn update(
    connections: Arc<RwLock<HashMap<Id, SplitSink>>>,
    state: Arc<RwLock<State>>,
    channel: mpsc::UnboundedSender<(Id, Arc<RwLock<State>>)>,
    remote: &Remote,
) -> Result<bool, ()> {
    remote.spawn(move |handle| {
        for (id, _) in connections.read().unwrap().iter() {
            let f = channel.clone().send((*id, state.clone()));
            spawn_future(f, "Send message to write handler", handle);
        }
        Ok(())
    });
    Ok(true)
}

struct Counter {
    count: Id,
}
impl Counter {
    fn new() -> Self {
        Counter { count: 0 }
    }
}

impl Iterator for Counter {
    type Item = Id;

    fn next(&mut self) -> Option<Id> {
        if self.count != Id::max_value() {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::ptr;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;

use buffer::TrackedBuffer;
use command_buffer::pool::AllocatedCommandBuffer;
use command_buffer::pool::CommandPool;
use command_buffer::CommandsList;
use command_buffer::CommandsListSink;
use command_buffer::CommandsListSinkCaller;
use command_buffer::DynamicState;
use command_buffer::RawCommandBufferPrototype;
use command_buffer::StatesManager;
use device::Device;
use framebuffer::RenderPass;
use framebuffer::Subpass;
use framebuffer::traits::Framebuffer;
use image::Layout;
use image::TrackedImage;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Determines the kind of command buffer that we want to create.
#[derive(Debug, Clone)]
pub enum Kind<'a, R, F: 'a> {
    /// A primary command buffer can execute all commands and can call secondary command buffers.
    Primary,

    /// A secondary command buffer can execute all dispatch and transfer operations, but not
    /// drawing operations.
    Secondary,

    /// A secondary command buffer within a render pass can only call draw operations that can
    /// be executed from within a specific subpass.
    SecondaryRenderPass {
        /// Which subpass this secondary command buffer can be called from.
        subpass: Subpass<R>,
        /// The framebuffer object that will be used when calling the command buffer.
        /// This parameter is optional and is an optimization hint for the implementation.
        framebuffer: Option<&'a F>,
    },
}

/// Flags to pass when creating a command buffer.
///
/// The safest option is `SimultaneousUse`, but it may be slower than the other two.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Flags {
    /// The command buffer can be used multiple times, but must not execute more than once
    /// simultaneously.
    None,

    /// The command buffer can be executed multiple times in parallel.
    SimultaneousUse,

    /// The command buffer can only be submitted once. Any further submit is forbidden.
    OneTimeSubmit,
}

pub struct UnsyncedCommandBuffer<L, P> where P: CommandPool {
    // The Vulkan command buffer.
    cmd: vk::CommandBuffer,

    // Device that owns the command buffer.
    device: Arc<Device>,

    // Pool that owns the command buffer.
    pool: P::Finished,

    // Flags that were used at creation.
    flags: Flags,

    // True if the command buffer has always been submitted once. Only relevant if `flags` is
    // `OneTimeSubmit`.
    already_submitted: AtomicBool,

    // True if we are a secondary command buffer.
    secondary_cb: bool,

    // The commands list. Holds resources of the resources list alive.
    commands_list: L,
}

impl<L, P> UnsyncedCommandBuffer<L, P> where L: CommandsList, P: CommandPool {
    /// Creates a new builder.
    pub unsafe fn new<R, F>(list: L, pool: P, kind: Kind<R, F>, flags: Flags)
                            -> Result<UnsyncedCommandBuffer<L, P>, OomError>
        where R: RenderPass, F: Framebuffer
    {
        let secondary = match kind {
            Kind::Primary => false,
            Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
        };

        let cmd = try!(pool.alloc(secondary, 1)).next().unwrap();

        match UnsyncedCommandBuffer::already_allocated(list, pool, cmd, kind, flags) {
            Ok(cmd) => Ok(cmd),
            Err(err) => {
                // FIXME: uncomment this and solve the fact that `pool` has been moved
                //unsafe { pool.free(secondary, Some(cmd.into()).into_iter()) };
                Err(err)
            },
        }
    }

    /// Creates a new command buffer builder from an already-allocated command buffer.
    ///
    /// # Safety
    ///
    /// - The allocated command buffer must belong to the pool and must not be used anywhere else
    ///   in the code for the duration of this command buffer.
    ///
    pub unsafe fn already_allocated<R, F>(list: L, pool: P, cmd: AllocatedCommandBuffer,
                                          kind: Kind<R, F>, flags: Flags)
                                          -> Result<UnsyncedCommandBuffer<L, P>, OomError>
        where R: RenderPass, F: Framebuffer
    {
        let device = pool.device().clone();
        let vk = device.pointers();
        let cmd = cmd.internal_object();

        let vk_flags = {
            let a = match flags {
                Flags::None => 0,
                Flags::SimultaneousUse => vk::COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
                Flags::OneTimeSubmit => vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
            };

            let b = match kind {
                Kind::Primary | Kind::Secondary => 0,
                Kind::SecondaryRenderPass { .. } => {
                    vk::COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
                },
            };

            a | b
        };

        let (rp, sp) = if let Kind::SecondaryRenderPass { ref subpass, .. } = kind {
            (subpass.render_pass().inner().internal_object(), subpass.index())
        } else {
            (0, 0)
        };

        let framebuffer = if let Kind::SecondaryRenderPass { ref subpass, framebuffer: Some(ref framebuffer) } = kind {
            // TODO: restore check
            //assert!(framebuffer.is_compatible_with(subpass.render_pass()));     // TODO: proper error
            framebuffer.internal_object()
        } else {
            0
        };

        let inheritance = vk::CommandBufferInheritanceInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
            pNext: ptr::null(),
            renderPass: rp,
            subpass: sp,
            framebuffer: framebuffer,
            occlusionQueryEnable: 0,            // TODO:
            queryFlags: 0,          // TODO:
            pipelineStatistics: 0,          // TODO:
        };

        let infos = vk::CommandBufferBeginInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
            pNext: ptr::null(),
            flags: vk_flags,
            pInheritanceInfo: &inheritance,
        };

        try!(check_errors(vk.BeginCommandBuffer(cmd, &infos)));

        {
            let mut builder = RawCommandBufferPrototype {
                device: device.clone(),
                command_buffer: Some(cmd),
                current_state: DynamicState::none(),
                bound_graphics_pipeline: 0,
                bound_compute_pipeline: 0,
                resources_states: StatesManager::new(),
                marker: PhantomData,
            };

            list.append(&mut Sink(&mut builder, &device));
        };

        Ok(UnsyncedCommandBuffer {
            device: device.clone(),
            pool: pool.finish(),
            cmd: cmd,
            flags: flags,
            secondary_cb: match kind {
                Kind::Primary => false,
                Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
            },
            already_submitted: AtomicBool::new(false),
            commands_list: list,
        })
    }
}

// Helper object for UnsyncedCommandBuffer. Implementation detail.
struct Sink<'a>(&'a mut RawCommandBufferPrototype<'a>, &'a Arc<Device>);
impl<'a> CommandsListSink<'a> for Sink<'a> {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.1
    }

    #[inline]
    fn add_command(&mut self, f: Box<CommandsListSinkCaller<'a> + 'a>) {
        f.call(self.0)
    }

    #[inline]
    fn add_buffer_transition(&mut self, buffer: &TrackedBuffer, offset: usize, size: usize,
                             write: bool)
    {
    }

    #[inline]
    fn add_image_transition(&mut self, image: &TrackedImage, first_layer: u32, num_layers: u32,
                            first_mipmap: u32, num_mipmaps: u32, layout: Layout)
    {
    }

    #[inline]
    fn add_image_transition_notification(&mut self, image: &TrackedImage, first_layer: u32,
                                         num_layers: u32, first_mipmap: u32, num_mipmaps: u32,
                                         layout: Layout)
    {
    }
}
<commit_msg>Fix missing vkEndCommandBuffer<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::ptr;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;

use buffer::TrackedBuffer;
use command_buffer::pool::AllocatedCommandBuffer;
use command_buffer::pool::CommandPool;
use command_buffer::CommandsList;
use command_buffer::CommandsListSink;
use command_buffer::CommandsListSinkCaller;
use command_buffer::DynamicState;
use command_buffer::RawCommandBufferPrototype;
use command_buffer::StatesManager;
use device::Device;
use framebuffer::RenderPass;
use framebuffer::Subpass;
use framebuffer::traits::Framebuffer;
use image::Layout;
use image::TrackedImage;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Determines the kind of command buffer that we want to create.
#[derive(Debug, Clone)]
pub enum Kind<'a, R, F: 'a> {
    /// A primary command buffer can execute all commands and can call secondary command buffers.
    Primary,

    /// A secondary command buffer can execute all dispatch and transfer operations, but not
    /// drawing operations.
    Secondary,

    /// A secondary command buffer within a render pass can only call draw operations that can
    /// be executed from within a specific subpass.
    SecondaryRenderPass {
        /// Which subpass this secondary command buffer can be called from.
        subpass: Subpass<R>,
        /// The framebuffer object that will be used when calling the command buffer.
        /// This parameter is optional and is an optimization hint for the implementation.
        framebuffer: Option<&'a F>,
    },
}

/// Flags to pass when creating a command buffer.
///
/// The safest option is `SimultaneousUse`, but it may be slower than the other two.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Flags {
    /// The command buffer can be used multiple times, but must not execute more than once
    /// simultaneously.
    None,

    /// The command buffer can be executed multiple times in parallel.
    SimultaneousUse,

    /// The command buffer can only be submitted once. Any further submit is forbidden.
    OneTimeSubmit,
}

pub struct UnsyncedCommandBuffer<L, P> where P: CommandPool {
    // The Vulkan command buffer.
    cmd: vk::CommandBuffer,

    // Device that owns the command buffer.
    device: Arc<Device>,

    // Pool that owns the command buffer.
    pool: P::Finished,

    // Flags that were used at creation.
    flags: Flags,

    // True if the command buffer has always been submitted once. Only relevant if `flags` is
    // `OneTimeSubmit`.
    already_submitted: AtomicBool,

    // True if we are a secondary command buffer.
    secondary_cb: bool,

    // The commands list. Holds resources of the resources list alive.
    commands_list: L,
}

impl<L, P> UnsyncedCommandBuffer<L, P> where L: CommandsList, P: CommandPool {
    /// Creates a new builder.
    pub unsafe fn new<R, F>(list: L, pool: P, kind: Kind<R, F>, flags: Flags)
                            -> Result<UnsyncedCommandBuffer<L, P>, OomError>
        where R: RenderPass, F: Framebuffer
    {
        let secondary = match kind {
            Kind::Primary => false,
            Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
        };

        let cmd = try!(pool.alloc(secondary, 1)).next().unwrap();

        match UnsyncedCommandBuffer::already_allocated(list, pool, cmd, kind, flags) {
            Ok(cmd) => Ok(cmd),
            Err(err) => {
                // FIXME: uncomment this and solve the fact that `pool` has been moved
                //unsafe { pool.free(secondary, Some(cmd.into()).into_iter()) };
                Err(err)
            },
        }
    }

    /// Creates a new command buffer builder from an already-allocated command buffer.
    ///
    /// # Safety
    ///
    /// - The allocated command buffer must belong to the pool and must not be used anywhere else
    ///   in the code for the duration of this command buffer.
    ///
    pub unsafe fn already_allocated<R, F>(list: L, pool: P, cmd: AllocatedCommandBuffer,
                                          kind: Kind<R, F>, flags: Flags)
                                          -> Result<UnsyncedCommandBuffer<L, P>, OomError>
        where R: RenderPass, F: Framebuffer
    {
        let device = pool.device().clone();
        let vk = device.pointers();
        let cmd = cmd.internal_object();

        let vk_flags = {
            let a = match flags {
                Flags::None => 0,
                Flags::SimultaneousUse => vk::COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
                Flags::OneTimeSubmit => vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
            };

            let b = match kind {
                Kind::Primary | Kind::Secondary => 0,
                Kind::SecondaryRenderPass { .. } => {
                    vk::COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
                },
            };

            a | b
        };

        let (rp, sp) = if let Kind::SecondaryRenderPass { ref subpass, .. } = kind {
            (subpass.render_pass().inner().internal_object(), subpass.index())
        } else {
            (0, 0)
        };

        let framebuffer = if let Kind::SecondaryRenderPass { ref subpass, framebuffer: Some(ref framebuffer) } = kind {
            // TODO: restore check
            //assert!(framebuffer.is_compatible_with(subpass.render_pass()));     // TODO: proper error
            framebuffer.internal_object()
        } else {
            0
        };

        let inheritance = vk::CommandBufferInheritanceInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
            pNext: ptr::null(),
            renderPass: rp,
            subpass: sp,
            framebuffer: framebuffer,
            occlusionQueryEnable: 0,            // TODO:
            queryFlags: 0,          // TODO:
            pipelineStatistics: 0,          // TODO:
        };

        let infos = vk::CommandBufferBeginInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
            pNext: ptr::null(),
            flags: vk_flags,
            pInheritanceInfo: &inheritance,
        };

        try!(check_errors(vk.BeginCommandBuffer(cmd, &infos)));

        {
            let mut builder = RawCommandBufferPrototype {
                device: device.clone(),
                command_buffer: Some(cmd),
                current_state: DynamicState::none(),
                bound_graphics_pipeline: 0,
                bound_compute_pipeline: 0,
                resources_states: StatesManager::new(),
                marker: PhantomData,
            };

            list.append(&mut Sink(&mut builder, &device));
        };

        try!(check_errors(vk.EndCommandBuffer(cmd)));

        Ok(UnsyncedCommandBuffer {
            device: device.clone(),
            pool: pool.finish(),
            cmd: cmd,
            flags: flags,
            secondary_cb: match kind {
                Kind::Primary => false,
                Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
            },
            already_submitted: AtomicBool::new(false),
            commands_list: list,
        })
    }
}

// Helper object for UnsyncedCommandBuffer. Implementation detail.
struct Sink<'a>(&'a mut RawCommandBufferPrototype<'a>, &'a Arc<Device>);
impl<'a> CommandsListSink<'a> for Sink<'a> {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.1
    }

    #[inline]
    fn add_command(&mut self, f: Box<CommandsListSinkCaller<'a> + 'a>) {
        f.call(self.0)
    }

    #[inline]
    fn add_buffer_transition(&mut self, buffer: &TrackedBuffer, offset: usize, size: usize,
                             write: bool)
    {
    }

    #[inline]
    fn add_image_transition(&mut self, image: &TrackedImage, first_layer: u32, num_layers: u32,
                            first_mipmap: u32, num_mipmaps: u32, layout: Layout)
    {
    }

    #[inline]
    fn add_image_transition_notification(&mut self, image: &TrackedImage, first_layer: u32,
                                         num_layers: u32, first_mipmap: u32, num_mipmaps: u32,
                                         layout: Layout)
    {
    }
}
<|endoftext|>


<commit_before>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use rand::{thread_rng, Rng};

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
    global_allocator
)]
#[cfg(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>] \
    [--flush-every=<ms>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
    --flush-every=<m>  Flush and sync the database every ms [default: 200].
";

#[derive(Clone, Copy)]
struct Args {
    threads: usize,
    burn_in: bool,
    duration: u64,
    key_len: usize,
    val_len: usize,
    get_prop: usize,
    set_prop: usize,
    del_prop: usize,
    cas_prop: usize,
    scan_prop: usize,
    merge_prop: usize,
    entries: usize,
    sequential: bool,
    total_ops: Option<usize>,
    flush_every: u64,
}

impl Default for Args {
    fn default() -> Args {
        Args {
            threads: 4,
            burn_in: false,
            duration: 10,
            key_len: 10,
            val_len: 100,
            get_prop: 94,
            set_prop: 2,
            del_prop: 1,
            cas_prop: 1,
            scan_prop: 1,
            merge_prop: 1,
            entries: 100000,
            sequential: false,
            total_ops: None,
            flush_every: 200,
        }
    }
}

fn parse<'a, I, T>(mut iter: I) -> T
where
    I: Iterator<Item = &'a str>,
    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Debug,
{
    iter.next().expect(USAGE).parse().expect(USAGE)
}

impl Args {
    fn parse() -> Args {
        let mut args = Args::default();
        for raw_arg in std::env::args().skip(1) {
            let mut splits = raw_arg[2..].split('=');
            match splits.next().unwrap() {
                "threads" => args.threads = parse(&mut splits),
                "burn-in" => args.burn_in = true,
                "duration" => args.duration = parse(&mut splits),
                "key-len" => args.key_len = parse(&mut splits),
                "val-len" => args.val_len = parse(&mut splits),
                "get-prop" => args.get_prop = parse(&mut splits),
                "set-prop" => args.set_prop = parse(&mut splits),
                "del-prop" => args.del_prop = parse(&mut splits),
                "cas-prop" => args.cas_prop = parse(&mut splits),
                "scan-prop" => args.scan_prop = parse(&mut splits),
                "merge-prop" => args.merge_prop = parse(&mut splits),
                "entries" => args.entries = parse(&mut splits),
                "sequential" => args.sequential = true,
                "total-ops" => args.total_ops = Some(parse(&mut splits)),
                "flush-every" => args.flush_every = parse(&mut splits),
                other => panic!("unknown option: {}, {}", other, USAGE),
            }
        }
        args
    }
}

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops, {}mb RSS", total - last, rss() / (1024 * 1024));

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(args: Args, tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let get_max = args.get_prop;
    let set_max = get_max + args.set_prop;
    let del_max = set_max + args.del_prop;
    let cas_max = del_max + args.cas_prop;
    let merge_max = cas_max + args.merge_prop;
    let scan_max = merge_max + args.scan_prop;

    let bytes = |len| -> sled::IVec {
        let i = if args.sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.entries;

        let i_bytes = i.to_be_bytes();

        i_bytes
            .iter()
            .skip_while(|v| **v == 0)
            .cycle()
            .take(len)
            .copied()
            .collect()
    };
    let mut rng = thread_rng();

    let value = sled::IVec::from(vec![0; args.val_len]);

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = bytes(args.key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                tree.insert(&key, value.clone()).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old =
                    if rng.gen::<bool>() { Some(value.clone()) } else { None };

                let new =
                    if rng.gen::<bool>() { Some(value.clone()) } else { None };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                tree.merge(&key, value.clone()).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn rss() -> usize {
    #[cfg(target_os = "linux")]
    {
        use std::io::prelude::*;
        use std::io::BufReader;

        let mut buf = String::new();
        let mut f =
            BufReader::new(std::fs::File::open("/proc/self/statm").unwrap());
        f.read_line(&mut buf).unwrap();
        let mut parts = buf.split_whitespace();
        let rss_pages = parts.nth(1).unwrap().parse::<usize>().unwrap();
        rss_pages * 4096
    }
    #[cfg(not(target_os = "linux"))]
    {
        0
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = Args::parse();

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(256 * 1024 * 1024)
        .flush_every_ms(Some(args.flush_every))
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.threads;

    for i in 0..=n_threads {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            let args = args.clone();
            thread::spawn(move || run(args, tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.total_ops {
        assert!(!args.burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.burn_in {
        thread::sleep(std::time::Duration::from_secs(args.duration));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if std::env::var("RUST_LOG").is_ok() {
        builder.parse(&std::env::var("RUST_LOG").unwrap());
    }

    let _r = builder.try_init();
}
<commit_msg>Have the value generator in stress2 actually create new random values<commit_after>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use rand::{thread_rng, Rng};

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
    global_allocator
)]
#[cfg(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>] \
    [--flush-every=<ms>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
    --flush-every=<m>  Flush and sync the database every ms [default: 200].
";

#[derive(Clone, Copy)]
struct Args {
    threads: usize,
    burn_in: bool,
    duration: u64,
    key_len: usize,
    val_len: usize,
    get_prop: usize,
    set_prop: usize,
    del_prop: usize,
    cas_prop: usize,
    scan_prop: usize,
    merge_prop: usize,
    entries: usize,
    sequential: bool,
    total_ops: Option<usize>,
    flush_every: u64,
}

impl Default for Args {
    fn default() -> Args {
        Args {
            threads: 4,
            burn_in: false,
            duration: 10,
            key_len: 10,
            val_len: 100,
            get_prop: 94,
            set_prop: 2,
            del_prop: 1,
            cas_prop: 1,
            scan_prop: 1,
            merge_prop: 1,
            entries: 100000,
            sequential: false,
            total_ops: None,
            flush_every: 200,
        }
    }
}

fn parse<'a, I, T>(mut iter: I) -> T
where
    I: Iterator<Item = &'a str>,
    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Debug,
{
    iter.next().expect(USAGE).parse().expect(USAGE)
}

impl Args {
    fn parse() -> Args {
        let mut args = Args::default();
        for raw_arg in std::env::args().skip(1) {
            let mut splits = raw_arg[2..].split('=');
            match splits.next().unwrap() {
                "threads" => args.threads = parse(&mut splits),
                "burn-in" => args.burn_in = true,
                "duration" => args.duration = parse(&mut splits),
                "key-len" => args.key_len = parse(&mut splits),
                "val-len" => args.val_len = parse(&mut splits),
                "get-prop" => args.get_prop = parse(&mut splits),
                "set-prop" => args.set_prop = parse(&mut splits),
                "del-prop" => args.del_prop = parse(&mut splits),
                "cas-prop" => args.cas_prop = parse(&mut splits),
                "scan-prop" => args.scan_prop = parse(&mut splits),
                "merge-prop" => args.merge_prop = parse(&mut splits),
                "entries" => args.entries = parse(&mut splits),
                "sequential" => args.sequential = true,
                "total-ops" => args.total_ops = Some(parse(&mut splits)),
                "flush-every" => args.flush_every = parse(&mut splits),
                other => panic!("unknown option: {}, {}", other, USAGE),
            }
        }
        args
    }
}

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops, {}mb RSS", total - last, rss() / (1024 * 1024));

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(args: Args, tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let get_max = args.get_prop;
    let set_max = get_max + args.set_prop;
    let del_max = set_max + args.del_prop;
    let cas_max = del_max + args.cas_prop;
    let merge_max = cas_max + args.merge_prop;
    let scan_max = merge_max + args.scan_prop;

    let keygen = |len| -> sled::IVec {
        let i = if args.sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.entries;

        let i_keygen = i.to_be_bytes();

        i_keygen
            .iter()
            .skip_while(|v| **v == 0)
            .cycle()
            .take(len)
            .copied()
            .collect()
    };

    let valgen = |len| -> sled::IVec {
        let i: usize = thread_rng().gen::<usize>() % len;

        let i_keygen = i.to_be_bytes();

        i_keygen
            .iter()
            .skip_while(|v| **v == 0)
            .cycle()
            .take(len)
            .copied()
            .collect()
    };

    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = keygen(args.key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                let value = valgen(args.val_len);
                tree.insert(&key, value).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old = if rng.gen::<bool>() {
                    let value = valgen(args.val_len);
                    Some(value)
                } else {
                    None
                };

                let new = if rng.gen::<bool>() {
                    let value = valgen(args.val_len);
                    Some(value)
                } else {
                    None
                };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                let value = valgen(args.val_len);
                tree.merge(&key, value).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn rss() -> usize {
    #[cfg(target_os = "linux")]
    {
        use std::io::prelude::*;
        use std::io::BufReader;

        let mut buf = String::new();
        let mut f =
            BufReader::new(std::fs::File::open("/proc/self/statm").unwrap());
        f.read_line(&mut buf).unwrap();
        let mut parts = buf.split_whitespace();
        let rss_pages = parts.nth(1).unwrap().parse::<usize>().unwrap();
        rss_pages * 4096
    }
    #[cfg(not(target_os = "linux"))]
    {
        0
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = Args::parse();

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(256 * 1024 * 1024)
        .flush_every_ms(Some(args.flush_every))
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.threads;

    for i in 0..=n_threads {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            let args = args.clone();
            thread::spawn(move || run(args, tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.total_ops {
        assert!(!args.burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.burn_in {
        thread::sleep(std::time::Duration::from_secs(args.duration));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if let Ok(env_var) = std::env::var("RUST_LOG") {
        builder.parse(env_var);
    }

    let _r = builder.try_init();
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![recursion_limit = "128"]

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

use proc_macro::TokenStream;
use syn::*;
use syn::fold::Folder;

#[proc_macro_attribute]
pub fn async(attribute: TokenStream, function: TokenStream) -> TokenStream {
    if attribute.to_string() != "" {
        panic!("the #[async] attribute currently takes no arguments");
    }

    let ast = syn::parse_item(&function.to_string())
                    .expect("failed to parse item");
    let Item { ident, vis, attrs, node } = ast;
    let all = match node {
        ItemKind::Fn(a, b, c, d, e, f) => (a, b, c, d, e, f),
        _ => panic!("#[async] can only be applied to functions"),
    };
    let (decl, unsafety, constness, abi, generics, block) = all;
    let where_clause = &generics.where_clause;
    let FnDecl { inputs, output, variadic } = { *decl };
    let ref inputs = inputs;
    let output = match output {
        FunctionRetTy::Default => Ty::Tup(Vec::new()),
        FunctionRetTy::Ty(t) => t,
    };
    let ref bindings = inputs.iter().enumerate().map(|(i, input)| {
        match *input {
            FnArg::Captured(_, ref ty) => {
                let pat = Pat::Ident(BindingMode::ByValue(Mutability::Immutable),
                                     Ident::from(format!("__arg_{}", i)),
                                     None);
                FnArg::Captured(pat, ty.clone())
            }
            ref other => other.clone()
        }
    }).collect::<Vec<_>>();
    let ref inputs_mapped = inputs.iter().map(|input| {
        match *input {
            FnArg::Captured(Pat::Ident(ref mutability,
                                       ref ident,
                                       ref pat),
                            ref ty) => {
                let ident = if ident == "self" {
                    Ident::from("__self")
                } else {
                    ident.clone()
                };
                FnArg::Captured(Pat::Ident(mutability.clone(), ident, pat.clone()),
                                ty.clone())
            }
            ref cap @ FnArg::Captured(..) => cap.clone(),
            FnArg::Ignored(_) => panic!("can't work with ignored fn args"),
            FnArg::SelfRef(..) => panic!("self reference async methods are unsound"),
            FnArg::SelfValue(mutability) => {
                let me = Path {
                    global: false,
                    segments: vec![PathSegment {
                        ident: Ident::from("Self"),
                        parameters: PathParameters::AngleBracketed(Default::default()),
                    }],
                };
                FnArg::Captured(Pat::Ident(BindingMode::ByValue(mutability),
                                           Ident::from("__self"),
                                           None),
                                Ty::Path(None, me))
            }
        }
    }).collect::<Vec<_>>();
    let binding_names = bindings.iter().map(|input| {
        match *input {
            FnArg::Captured(Pat::Ident(_, ref name, _), _) => name.clone(),
            _ => Ident::from("self"),
        }
    }).collect::<Vec<_>>();
    let block = ExpandAsyncFor.fold_block(*block);
    let block = RewriteSelfReferences.fold_block(block);
    assert!(!variadic, "variadic functions cannot be async");

    // Actual #[async] transformation
    let output = quote! {
        #(#attrs)*
        #vis #unsafety #abi #constness
        fn #ident #generics(#(#bindings),*)
            // Dunno why this is buggy, hits an ICE when compiling
            // `examples/main.rs`
            // -> impl ::futures::__rt::MyFuture<#output>

            // Dunno why this is buggy, hits an ICE when compiling
            // `examples/main.rs`
            // -> impl ::futures::__rt::Future<
            //         Item = <#output as ::futures::__rt::FutureType>::Item,
            //         Error = <#output as ::futures::__rt::FutureType>::Error,
            //    >

            -> Box<::futures::Future<
                    Item = <#output as ::futures::__rt::FutureType>::Item,
                    Error = <#output as ::futures::__rt::FutureType>::Error,
               >>
            #where_clause
        {
            // Box::new(::futures::__rt::gen(
            //     #maybe_self
            //     #generator_name(#(#binding_names),*)
            // ))
            Box::new(::futures::__rt::gen((|#(#inputs_mapped),*| {
                // Ensure that this closure is a generator, even if it doesn't
                // have any `yield` statements.
                #[allow(unreachable_code)]
                {
                    if false {
                        yield
                    }
                }

                #block
            })(#(#binding_names),*)))
        }

    //     #unsafety #constness fn #generator_name #generics(#(#inputs),*)
    //         -> impl ::futures::__rt::Generator<Yield = (), Return = #output>
    //         #where_clause
    //     {
    //         // Ensure that this closure is a generator, even if it doesn't
    //         // have any `yield` statements.
    //         #[allow(unreachable_code)]
    //         {
    //             if false {
    //                 yield
    //             }
    //         }
    //
    //         #block
    //     }
    };
    // println!("{}", output);
    output.parse().unwrap()
}

struct ExpandAsyncFor;

impl Folder for ExpandAsyncFor {
    fn fold_expr(&mut self, expr: Expr) -> Expr {
        if expr.attrs.len() != 1 {
            return expr
        }
        // TODO: more validation here
        if expr.attrs[0].path.segments[0].ident != "async" {
            return expr
        }
        let all = match expr.node {
            ExprKind::ForLoop(a, b, c, d) => (a, b, c, d),
            _ => panic!("only for expressions can have #[async]"),
        };
        let (pat, expr, block, ident) = all;

        // Basically just expand to a `poll` loop
        let tokens = quote! {{
            let mut __stream = #expr;
            #ident
            loop {
                let #pat = {
                    extern crate futures_await;
                    match futures_await::Stream::poll(&mut __stream)? {
                        futures_await::Async::Ready(e) => {
                            match e {
                                futures_await::__rt::Some(e) => e,
                                futures_await::__rt::None => break,
                            }
                        }
                        futures_await::Async::NotReady => {
                            yield;
                            continue
                        }
                    }
                };

                #block
            }
        }};
        parse_expr(tokens.as_str()).unwrap()
    }

    // Don't recurse into items
    fn fold_item(&mut self, item: Item) -> Item {
        item
    }
}

struct RewriteSelfReferences;

impl Folder for RewriteSelfReferences {
    fn fold_path(&mut self, mut path: Path) -> Path {
        if path.segments.len() == 1 && !path.global &&
            path.segments[0].ident == "self" {
            path.segments[0].ident = Ident::from("__self");
        }
        path
    }

    // Don't recurse into items
    fn fold_item(&mut self, item: Item) -> Item {
        item
    }
}
<commit_msg>Delete some commented code<commit_after>#![feature(proc_macro)]
#![recursion_limit = "128"]

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

use proc_macro::TokenStream;
use syn::*;
use syn::fold::Folder;

#[proc_macro_attribute]
pub fn async(attribute: TokenStream, function: TokenStream) -> TokenStream {
    if attribute.to_string() != "" {
        panic!("the #[async] attribute currently takes no arguments");
    }

    let ast = syn::parse_item(&function.to_string())
                    .expect("failed to parse item");
    let Item { ident, vis, attrs, node } = ast;
    let all = match node {
        ItemKind::Fn(a, b, c, d, e, f) => (a, b, c, d, e, f),
        _ => panic!("#[async] can only be applied to functions"),
    };
    let (decl, unsafety, constness, abi, generics, block) = all;
    let where_clause = &generics.where_clause;
    let FnDecl { inputs, output, variadic } = { *decl };
    let ref inputs = inputs;
    let output = match output {
        FunctionRetTy::Default => Ty::Tup(Vec::new()),
        FunctionRetTy::Ty(t) => t,
    };
    let ref bindings = inputs.iter().enumerate().map(|(i, input)| {
        match *input {
            FnArg::Captured(_, ref ty) => {
                let pat = Pat::Ident(BindingMode::ByValue(Mutability::Immutable),
                                     Ident::from(format!("__arg_{}", i)),
                                     None);
                FnArg::Captured(pat, ty.clone())
            }
            ref other => other.clone()
        }
    }).collect::<Vec<_>>();
    let ref inputs_mapped = inputs.iter().map(|input| {
        match *input {
            FnArg::Captured(Pat::Ident(ref mutability,
                                       ref ident,
                                       ref pat),
                            ref ty) => {
                let ident = if ident == "self" {
                    Ident::from("__self")
                } else {
                    ident.clone()
                };
                FnArg::Captured(Pat::Ident(mutability.clone(), ident, pat.clone()),
                                ty.clone())
            }
            ref cap @ FnArg::Captured(..) => cap.clone(),
            FnArg::Ignored(_) => panic!("can't work with ignored fn args"),
            FnArg::SelfRef(..) => panic!("self reference async methods are unsound"),
            FnArg::SelfValue(mutability) => {
                let me = Path {
                    global: false,
                    segments: vec![PathSegment {
                        ident: Ident::from("Self"),
                        parameters: PathParameters::AngleBracketed(Default::default()),
                    }],
                };
                FnArg::Captured(Pat::Ident(BindingMode::ByValue(mutability),
                                           Ident::from("__self"),
                                           None),
                                Ty::Path(None, me))
            }
        }
    }).collect::<Vec<_>>();
    let binding_names = bindings.iter().map(|input| {
        match *input {
            FnArg::Captured(Pat::Ident(_, ref name, _), _) => name.clone(),
            _ => Ident::from("self"),
        }
    }).collect::<Vec<_>>();
    let block = ExpandAsyncFor.fold_block(*block);
    let block = RewriteSelfReferences.fold_block(block);
    assert!(!variadic, "variadic functions cannot be async");

    // Actual #[async] transformation
    let output = quote! {
        #(#attrs)*
        #vis #unsafety #abi #constness
        fn #ident #generics(#(#bindings),*)
            // Dunno why this is buggy, hits an ICE when compiling
            // `examples/main.rs`
            // -> impl ::futures::__rt::MyFuture<#output>

            // Dunno why this is buggy, hits an ICE when compiling
            // `examples/main.rs`
            // -> impl ::futures::__rt::Future<
            //         Item = <#output as ::futures::__rt::FutureType>::Item,
            //         Error = <#output as ::futures::__rt::FutureType>::Error,
            //    >

            -> Box<::futures::Future<
                    Item = <#output as ::futures::__rt::FutureType>::Item,
                    Error = <#output as ::futures::__rt::FutureType>::Error,
               >>
            #where_clause
        {
            Box::new(::futures::__rt::gen((|#(#inputs_mapped),*| {
                // Ensure that this closure is a generator, even if it doesn't
                // have any `yield` statements.
                #[allow(unreachable_code)]
                {
                    if false {
                        yield
                    }
                }

                #block
            })(#(#binding_names),*)))
        }
    };
    // println!("{}", output);
    output.parse().unwrap()
}

struct ExpandAsyncFor;

impl Folder for ExpandAsyncFor {
    fn fold_expr(&mut self, expr: Expr) -> Expr {
        if expr.attrs.len() != 1 {
            return expr
        }
        // TODO: more validation here
        if expr.attrs[0].path.segments[0].ident != "async" {
            return expr
        }
        let all = match expr.node {
            ExprKind::ForLoop(a, b, c, d) => (a, b, c, d),
            _ => panic!("only for expressions can have #[async]"),
        };
        let (pat, expr, block, ident) = all;

        // Basically just expand to a `poll` loop
        let tokens = quote! {{
            let mut __stream = #expr;
            #ident
            loop {
                let #pat = {
                    extern crate futures_await;
                    match futures_await::Stream::poll(&mut __stream)? {
                        futures_await::Async::Ready(e) => {
                            match e {
                                futures_await::__rt::Some(e) => e,
                                futures_await::__rt::None => break,
                            }
                        }
                        futures_await::Async::NotReady => {
                            yield;
                            continue
                        }
                    }
                };

                #block
            }
        }};
        parse_expr(tokens.as_str()).unwrap()
    }

    // Don't recurse into items
    fn fold_item(&mut self, item: Item) -> Item {
        item
    }
}

struct RewriteSelfReferences;

impl Folder for RewriteSelfReferences {
    fn fold_path(&mut self, mut path: Path) -> Path {
        if path.segments.len() == 1 && !path.global &&
            path.segments[0].ident == "self" {
            path.segments[0].ident = Ident::from("__self");
        }
        path
    }

    // Don't recurse into items
    fn fold_item(&mut self, item: Item) -> Item {
        item
    }
}
<|endoftext|>