<commit_before>extern crate hyper;

use hubcaps::{self, Credentials};
use super::{Config, Pull};

/// Content associated with a pull request
#[derive(Debug, Default)]
pub struct Content {
    pub commits: Vec<String>,
    pub comments: Vec<String>,
}

/// interface for fetching pull request information
pub trait Github: Sync + Send {
    /// get a collection of content associated with a given pull
    fn content(&self, pull: Pull) -> Content;
}

pub struct DefaultGithub {
    client: hyper::Client,
    config: Config,
}

impl DefaultGithub {
    pub fn new(client: hyper::Client, config: Config) -> DefaultGithub {
        DefaultGithub {
            client: client,
            config: config,
        }
    }
}

impl Github for DefaultGithub {
    fn content(&self, pull: Pull) -> Content {
        let gh = hubcaps::Github::new(format!("{}/{}",
                                              env!("CARGO_PKG_NAME"),
                                              env!("CARGO_PKG_VERSION")),
                                      &self.client,
                                      Credentials::Token(self.config.github_token.clone()));
        let repo_uri = pull.repo_slug.split("/").collect::<Vec<_>>();
        // fetch all comments
        let comments = gh.repo(repo_uri[0], repo_uri[1])
            .pulls()
            .get(pull.number)
            .comments()
            .list(&Default::default())
            .unwrap_or(vec![]);
        // fetch all commits
        let commits = match gh.repo(repo_uri[0], repo_uri[1])
            .pulls()
            .get(pull.number)
            .commits()
            .iter() {
            Ok(iter) => iter.collect::<Vec<_>>(),
            _ => vec![],
        };
        info!("fetched {} comments and {} commits for pull {} in repo {}",
               comments.len(),
               commits.len(),
               pull.number,
               pull.repo_slug);
        Content {
            commits: commits.iter()
                .map(|commit| commit.commit.message.clone())
                .collect::<Vec<_>>(),
            comments: comments.iter()
                .map(|comment| comment.body.clone())
                .collect::<Vec<_>>(),
        }
    }
}
<commit_msg>if there is an error, report it<commit_after>extern crate hyper;

use hubcaps::{self, Credentials};
use super::{Config, Pull};

/// Content associated with a pull request
#[derive(Debug, Default)]
pub struct Content {
    pub commits: Vec<String>,
    pub comments: Vec<String>,
}

/// interface for fetching pull request information
pub trait Github: Sync + Send {
    /// get a collection of content associated with a given pull
    fn content(&self, pull: Pull) -> Content;
}

pub struct DefaultGithub {
    client: hyper::Client,
    config: Config,
}

impl DefaultGithub {
    pub fn new(client: hyper::Client, config: Config) -> DefaultGithub {
        DefaultGithub {
            client: client,
            config: config,
        }
    }
}

impl Github for DefaultGithub {
    fn content(&self, pull: Pull) -> Content {
        let gh = hubcaps::Github::new(format!("{}/{}",
                                              env!("CARGO_PKG_NAME"),
                                              env!("CARGO_PKG_VERSION")),
                                      &self.client,
                                      Credentials::Token(self.config.github_token.clone()));
        let repo_uri = pull.repo_slug.split("/").collect::<Vec<_>>();
        // fetch all comments
        let comments = gh.repo(repo_uri[0], repo_uri[1])
            .pulls()
            .get(pull.number)
            .comments()
            .list(&Default::default()).or_else(|e| {
                error!("error fetching comments for pull {}: {}", pull.number, e);
                Err(e)
            }).unwrap_or(Vec::new());
        // fetch all commits
        let commits = match gh.repo(repo_uri[0], repo_uri[1])
            .pulls()
            .get(pull.number)
            .commits()
            .iter() {
            Ok(iter) => iter.collect::<Vec<_>>(),
            _ => Vec::new(),
        };
        info!("fetched {} comments and {} commits for pull {} in repo {}",
               comments.len(),
               commits.len(),
               pull.number,
               pull.repo_slug);
        Content {
            commits: commits.iter()
                .map(|commit| commit.commit.message.clone())
                .collect::<Vec<_>>(),
            comments: comments.iter()
                .map(|comment| comment.body.clone())
                .collect::<Vec<_>>(),
        }
    }
}
<|endoftext|>


<commit_before>use regex_syntax::Parser;
use test::Bencher;

use regex::internal::Compiler;

#[bench]
fn compile_simple(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"^bc(d|e)*$").unwrap();
        Compiler::new().compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_simple_bytes(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"^bc(d|e)*$").unwrap();
        Compiler::new().bytes(true).compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_simple_full(b: &mut Bencher) {
    b.iter(|| regex!(r"^bc(d|e)*$"));
}

#[bench]
fn compile_small(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"\p{L}|\p{N}|\s|.|\d").unwrap();
        Compiler::new().compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_small_bytes(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"\p{L}|\p{N}|\s|.|\d").unwrap();
        Compiler::new().bytes(true).compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_small_full(b: &mut Bencher) {
    b.iter(|| regex!(r"\p{L}|\p{N}|\s|.|\d"));
}

#[bench]
fn compile_huge(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"\p{L}{100}").unwrap();
        Compiler::new().size_limit(1 << 30).compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_huge_bytes(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"\p{L}{100}").unwrap();
        Compiler::new().size_limit(1 << 30).bytes(true).compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_huge_full(b: &mut Bencher) {
    b.iter(|| regex!(r"\p{L}{100}"));
}
<commit_msg>bench: reduce huge regex a bit<commit_after>use regex_syntax::Parser;
use test::Bencher;

use regex::internal::Compiler;

#[bench]
fn compile_simple(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"^bc(d|e)*$").unwrap();
        Compiler::new().compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_simple_bytes(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"^bc(d|e)*$").unwrap();
        Compiler::new().bytes(true).compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_simple_full(b: &mut Bencher) {
    b.iter(|| regex!(r"^bc(d|e)*$"));
}

#[bench]
fn compile_small(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"\p{L}|\p{N}|\s|.|\d").unwrap();
        Compiler::new().compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_small_bytes(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"\p{L}|\p{N}|\s|.|\d").unwrap();
        Compiler::new().bytes(true).compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_small_full(b: &mut Bencher) {
    b.iter(|| regex!(r"\p{L}|\p{N}|\s|.|\d"));
}

#[bench]
fn compile_huge(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"\p{L}{50}").unwrap();
        Compiler::new().size_limit(1 << 30).compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_huge_bytes(b: &mut Bencher) {
    b.iter(|| {
        let re = Parser::new().parse(r"\p{L}{50}").unwrap();
        Compiler::new().size_limit(1 << 30).bytes(true).compile(&[re]).unwrap()
    });
}

#[bench]
fn compile_huge_full(b: &mut Bencher) {
    b.iter(|| regex!(r"\p{L}{50}"));
}
<|endoftext|>


<commit_before>extern crate frappe;
use frappe::Sink;

use std::rc::Rc;
use std::cell::RefCell;
use std::sync::mpsc;
use std::thread::{self, Thread};
use std::time::Duration;

#[derive(Clone)]
struct Updater
{
    jobs: Rc<RefCell<Vec<Box<Fn() -> bool>>>>,
    main_thread: Thread,
}

impl Updater
{
    fn new() -> Self
    {
        Updater{
            jobs: Default::default(),
            main_thread: thread::current(),
        }
    }

    fn register<F>(&self, f: F)
        where F: Fn() -> bool + 'static
    {
        self.jobs.borrow_mut().push(Box::new(f));
    }

    fn update(&self)
    {
        self.jobs.borrow_mut().retain(|f| !f());
    }

    fn wait(&self)
    {
        thread::park();
        self.update();
    }

    fn pending(&self) -> bool
    {
        !self.jobs.borrow().is_empty()
    }
}

fn main()
{
    let updater = Updater::new();
    let upd = updater.clone();

    let sink = Sink::new();

    let result = sink.stream()
        // we'll do this part on another thread
        .map_n(move |arg, sink_| {
            let n = *arg;
            let (tx, rx) = mpsc::channel();
            let main_th = upd.main_thread.clone();
            // sleep sort
            thread::spawn(move || {
                thread::sleep(Duration::from_millis(n));
                tx.send(n).unwrap();
                main_th.unpark();
            });
            // store the sink and use it later to return the value when it's ready
            upd.register(move || rx.try_recv().map(|v| sink_.send(v)).is_ok());
        })
        // rest of the chain continues on the main thread
        .fold(vec![], |mut vec, n| { vec.push(*n); vec });

    sink.feed(vec![5, 6, 10, 42, 1, 94, 22, 33, 7]);

    // the main loop dispatches results back to the stream
    while updater.pending()
    {
        updater.wait();
        println!("{:?}", result.sample());
    }
}
<commit_msg>updated async example<commit_after>extern crate frappe;
extern crate rand;
use frappe::Sink;
use rand::Rng;

use std::rc::Rc;
use std::cell::RefCell;
use std::sync::mpsc;
use std::thread::{self, Thread};
use std::time::Duration;

#[derive(Clone)]
struct Updater
{
    jobs: Rc<RefCell<Vec<Box<Fn() -> bool>>>>,
    main_thread: Thread,
}

impl Updater
{
    fn new() -> Self
    {
        Updater{
            jobs: Default::default(),
            main_thread: thread::current(),
        }
    }

    fn register<F>(&self, f: F)
        where F: Fn() -> bool + 'static
    {
        self.jobs.borrow_mut().push(Box::new(f));
    }

    fn get_main_thread(&self) -> Thread
    {
        self.main_thread.clone()
    }

    fn update(&self)
    {
        self.jobs.borrow_mut().retain(|f| !f());
    }

    fn wait(&self)
    {
        thread::park();
        self.update();
    }

    fn pending(&self) -> bool
    {
        !self.jobs.borrow().is_empty()
    }
}

fn main()
{
    let updater = Updater::new();
    let upd = updater.clone();

    let sink = Sink::new();

    let result = sink.stream()
        // we'll do this part on another thread
        .map_n(move |arg, sink_| {
            let n = *arg;
            let (tx, rx) = mpsc::channel();
            let main_th = upd.get_main_thread();
            // our expensive computation (sleep sort)
            thread::spawn(move || {
                thread::sleep(Duration::from_millis(n));
                tx.send(n).unwrap();
                main_th.unpark();
            });
            // store the sink and use it later to return the value when it's ready
            upd.register(move || rx.try_recv().map(|v| sink_.send(v)).is_ok());
        })
        // rest of the chain continues on the main thread
        .fold(vec![], |mut vec, n| { vec.push(*n); vec });

    let mut rng = rand::thread_rng();
    sink.feed((0..10).map(|_| rng.gen_range(0, 100)));

    // the main loop dispatches results back to the stream
    while updater.pending()
    {
        updater.wait();
        println!("{:?}", result.sample());
    }
}
<|endoftext|>


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

use rand::{thread_rng, Rng};
use std::cmp::min;
use std::net::SocketAddr;
use std::ops::Deref;
use std::str::{self, FromStr};
use std::sync::Arc;
use std::thread;
use std::time;

use cpupool;
use futures::{self, future, Future, Stream};
use futures::sync::mpsc;
use hyper;
use tokio_core::reactor;
use tokio_timer::Timer;

use p2p;

const PEER_MAX_COUNT: u32 = 25;
const PEER_PREFERRED_COUNT: u32 = 8;
const GIST_SEEDS_URL: &'static str = "";

pub struct Seeder {
	peer_store: Arc<p2p::PeerStore>,
	p2p: Arc<p2p::Server>,

	capabilities: p2p::Capabilities,
}

impl Seeder {
	pub fn new(capabilities: p2p::Capabilities,
	           peer_store: Arc<p2p::PeerStore>,
	           p2p: Arc<p2p::Server>)
	           -> Seeder {
		Seeder {
			peer_store: peer_store,
			p2p: p2p,
			capabilities: capabilities,
		}
	}

	pub fn connect_and_monitor(&self,
	                           h: reactor::Handle,
	                           seed_list: Box<Future<Item = Vec<SocketAddr>, Error = String>>) {
		// open a channel with a listener that connects every peer address sent below
		// max peer count
		let (tx, rx) = futures::sync::mpsc::unbounded();
		h.spawn(self.listen_for_addrs(h.clone(), rx));

		// check seeds and start monitoring connections
		let seeder = self.connect_to_seeds(tx.clone(), seed_list)
			.join(self.monitor_peers(tx.clone()));

		h.spawn(seeder.map(|_| ()).map_err(|_| ()));
	}

	fn monitor_peers(&self,
	                 tx: mpsc::UnboundedSender<SocketAddr>)
	                 -> Box<Future<Item = (), Error = String>> {
		let peer_store = self.peer_store.clone();
		let p2p_server = self.p2p.clone();

		// now spawn a new future to regularly check if we need to acquire more peers
		// and if so, gets them from db
		let mon_loop = Timer::default()
			.interval(time::Duration::from_secs(10))
			.for_each(move |_| {

				// maintenance step first, clean up p2p server peers and mark bans
				// if needed
				let disconnected = p2p_server.clean_peers();
				for p in disconnected {
					if p.is_banned() {
						debug!("Marking peer {} as banned.", p.info.addr);
						peer_store.update_state(p.info.addr, p2p::State::Banned);
					}
				}

				// we don't have enough peers, getting more from db
				if p2p_server.peer_count() < PEER_PREFERRED_COUNT {
					let mut peers = peer_store.find_peers(p2p::State::Healthy,
					                                      p2p::UNKNOWN,
					                                      (2 * PEER_MAX_COUNT) as usize);
					debug!("Got {} more peers from db, trying to connect.", peers.len());
					thread_rng().shuffle(&mut peers[..]);
					let sz = min(PEER_PREFERRED_COUNT as usize, peers.len());
					for p in &peers[0..sz] {
						tx.send(p.addr).unwrap();
					}
				}
				Ok(())
			})
			.map_err(|e| e.to_string());
		Box::new(mon_loop)
	}

	// Check if we have any pre-existing peer in db. If so, start with those,
	// otherwise use the seeds provided.
	fn connect_to_seeds(&self,
	                    tx: mpsc::UnboundedSender<SocketAddr>,
	                    seed_list: Box<Future<Item = Vec<SocketAddr>, Error = String>>)
	                    -> Box<Future<Item = (), Error = String>> {
		let peer_store = self.peer_store.clone();

		// a thread pool is required so we don't block the event loop with a
		// db query
		let thread_pool = cpupool::CpuPool::new(1);
		let seeder = thread_pool.spawn_fn(move || {
				// check if we have some peers in db
				Ok(peer_store.find_peers(p2p::State::Healthy,
				                         p2p::FULL_HIST,
				                         (2 * PEER_MAX_COUNT) as usize))
			})
			.and_then(|mut peers| {
				// if so, get their addresses, otherwise use our seeds
				if peers.len() > 0 {
					thread_rng().shuffle(&mut peers[..]);
					Box::new(future::ok(peers.iter().map(|p| p.addr).collect::<Vec<_>>()))
				} else {
					seed_list
				}
			})
			.and_then(move |peer_addrs| {
				// connect to this first set of addresses
				let sz = min(PEER_PREFERRED_COUNT as usize, peer_addrs.len());
				for addr in &peer_addrs[0..sz] {
					debug!("Connecting to seed: {}.", addr);
					tx.send(*addr).unwrap();
				}
				Ok(())
			});
		Box::new(seeder)
	}

	/// Builds a future to continuously listen on a channel receiver for new
	/// addresses to and initiate a connection if the max peer count isn't
	/// exceeded. A request for more peers is also automatically sent after
	/// connection.
	fn listen_for_addrs(&self,
	                    h: reactor::Handle,
	                    rx: mpsc::UnboundedReceiver<SocketAddr>)
	                    -> Box<Future<Item = (), Error = ()>> {
		let capab = self.capabilities;
		let p2p_server = self.p2p.clone();

		let listener = rx.for_each(move |peer_addr| {
			debug!("New peer address to connect to: {}.", peer_addr);
			let inner_h = h.clone();
			if p2p_server.peer_count() < PEER_MAX_COUNT {
				connect_and_req(capab, p2p_server.clone(), inner_h, peer_addr)
			} else {
				Box::new(future::ok(()))
			}
		});
		Box::new(listener)
	}
}

/// Extract the list of seeds from a pre-defined gist. Easy method until we
/// have a set of DNS names we can rely on.
pub fn gist_seeds(h: reactor::Handle) -> Box<Future<Item = Vec<SocketAddr>, Error = String>> {
	let url = hyper::Uri::from_str(&GIST_SEEDS_URL).unwrap();
	let seeds = future::ok(()).and_then(move |_| {
		let client = hyper::Client::new(&h);

		// http get, filtering out non 200 results
		client.get(url)
			.map_err(|e| e.to_string())
			.and_then(|res| {
				if res.status() != hyper::Ok {
					return Err(format!("Gist request failed: {}", res.status()));
				}
				Ok(res)
			})
			.and_then(|res| {

				// collect all chunks and split around whitespace to get a list of SocketAddr
				res.body().collect().map_err(|e| e.to_string()).and_then(|chunks| {
					let res = chunks.iter().fold("".to_string(), |acc, ref chunk| {
						acc + str::from_utf8(&chunk[..]).unwrap()
					});
					let addrs =
						res.split_whitespace().map(|s| s.parse().unwrap()).collect::<Vec<_>>();
					Ok(addrs)
				})
			})
	});
	Box::new(seeds)
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>)
                        -> Box<Future<Item = Vec<SocketAddr>, Error = String>> {
	let seeds = future::ok(())
		.and_then(move |_| Ok(addrs_str.iter().map(|s| s.parse().unwrap()).collect::<Vec<_>>()));
	Box::new(seeds)
}

fn connect_and_req(capab: p2p::Capabilities,
                   p2p: Arc<p2p::Server>,
                   h: reactor::Handle,
                   addr: SocketAddr)
                   -> Box<Future<Item = (), Error = ()>> {
	let fut = p2p.connect_peer(addr, h)
		.and_then(move |p| {
			if let Some(p) = p {
				p.send_peer_request(capab);
			}
			Ok(())
		})
		.map_err(|e| {
			error!("Peer request error {:?}", e);
			()
		});
	Box::new(fut)
}
<commit_msg>Minor fixes and URL for web static file seeds<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rand::{thread_rng, Rng};
use std::cmp::min;
use std::net::SocketAddr;
use std::ops::Deref;
use std::str::{self, FromStr};
use std::sync::Arc;
use std::thread;
use std::time;

use cpupool;
use futures::{self, future, Future, Stream};
use futures::sync::mpsc;
use hyper;
use tokio_core::reactor;
use tokio_timer::Timer;

use p2p;

const PEER_MAX_COUNT: u32 = 25;
const PEER_PREFERRED_COUNT: u32 = 8;
const SEEDS_URL: &'static str = "http://www.mimwim.org/seeds.txt";

pub struct Seeder {
	peer_store: Arc<p2p::PeerStore>,
	p2p: Arc<p2p::Server>,

	capabilities: p2p::Capabilities,
}

impl Seeder {
	pub fn new(capabilities: p2p::Capabilities,
	           peer_store: Arc<p2p::PeerStore>,
	           p2p: Arc<p2p::Server>)
	           -> Seeder {
		Seeder {
			peer_store: peer_store,
			p2p: p2p,
			capabilities: capabilities,
		}
	}

	pub fn connect_and_monitor(&self,
	                           h: reactor::Handle,
	                           seed_list: Box<Future<Item = Vec<SocketAddr>, Error = String>>) {
		// open a channel with a listener that connects every peer address sent below
		// max peer count
		let (tx, rx) = futures::sync::mpsc::unbounded();
		h.spawn(self.listen_for_addrs(h.clone(), rx));

		// check seeds and start monitoring connections
		let seeder = self.connect_to_seeds(tx.clone(), seed_list)
			.join(self.monitor_peers(tx.clone()));

		h.spawn(seeder.map(|_| ()).map_err(|e| {
			error!("Seeding or peer monitoring error: {}", e);
			()
		}));
	}

	fn monitor_peers(&self,
	                 tx: mpsc::UnboundedSender<SocketAddr>)
	                 -> Box<Future<Item = (), Error = String>> {
		let peer_store = self.peer_store.clone();
		let p2p_server = self.p2p.clone();

		// now spawn a new future to regularly check if we need to acquire more peers
		// and if so, gets them from db
		let mon_loop = Timer::default()
			.interval(time::Duration::from_secs(10))
			.for_each(move |_| {

				// maintenance step first, clean up p2p server peers and mark bans
				// if needed
				let disconnected = p2p_server.clean_peers();
				for p in disconnected {
					if p.is_banned() {
						debug!("Marking peer {} as banned.", p.info.addr);
						peer_store.update_state(p.info.addr, p2p::State::Banned);
					}
				}

				// we don't have enough peers, getting more from db
				if p2p_server.peer_count() < PEER_PREFERRED_COUNT {
					let mut peers = peer_store.find_peers(p2p::State::Healthy,
					                                      p2p::UNKNOWN,
					                                      (2 * PEER_MAX_COUNT) as usize);
					debug!("Got {} more peers from db, trying to connect.", peers.len());
					thread_rng().shuffle(&mut peers[..]);
					let sz = min(PEER_PREFERRED_COUNT as usize, peers.len());
					for p in &peers[0..sz] {
						tx.send(p.addr).unwrap();
					}
				}
				Ok(())
			})
			.map_err(|e| e.to_string());
		Box::new(mon_loop)
	}

	// Check if we have any pre-existing peer in db. If so, start with those,
	// otherwise use the seeds provided.
	fn connect_to_seeds(&self,
	                    tx: mpsc::UnboundedSender<SocketAddr>,
	                    seed_list: Box<Future<Item = Vec<SocketAddr>, Error = String>>)
	                    -> Box<Future<Item = (), Error = String>> {
		let peer_store = self.peer_store.clone();

		// a thread pool is required so we don't block the event loop with a
		// db query
		let thread_pool = cpupool::CpuPool::new(1);
		let seeder = thread_pool.spawn_fn(move || {
				// check if we have some peers in db
				let peers = peer_store.find_peers(p2p::State::Healthy,
				                                  p2p::FULL_HIST,
				                                  (2 * PEER_MAX_COUNT) as usize);
				Ok(peers)
			})
			.and_then(|mut peers| {
				// if so, get their addresses, otherwise use our seeds
				if peers.len() > 0 {
					thread_rng().shuffle(&mut peers[..]);
					Box::new(future::ok(peers.iter().map(|p| p.addr).collect::<Vec<_>>()))
				} else {
					seed_list
				}
			})
			.and_then(move |peer_addrs| {
				// connect to this first set of addresses
				let sz = min(PEER_PREFERRED_COUNT as usize, peer_addrs.len());
				for addr in &peer_addrs[0..sz] {
					debug!("Connecting to seed: {}.", addr);
					tx.send(*addr).unwrap();
				}
				if peer_addrs.len() == 0 {
					warn!("No seeds were retrieved.");
				}
				Ok(())
			});
		Box::new(seeder)
	}

	/// Builds a future to continuously listen on a channel receiver for new
	/// addresses to and initiate a connection if the max peer count isn't
	/// exceeded. A request for more peers is also automatically sent after
	/// connection.
	fn listen_for_addrs(&self,
	                    h: reactor::Handle,
	                    rx: mpsc::UnboundedReceiver<SocketAddr>)
	                    -> Box<Future<Item = (), Error = ()>> {
		let capab = self.capabilities;
		let p2p_server = self.p2p.clone();

		let listener = rx.for_each(move |peer_addr| {
			debug!("New peer address to connect to: {}.", peer_addr);
			let inner_h = h.clone();
			if p2p_server.peer_count() < PEER_MAX_COUNT {
				connect_and_req(capab, p2p_server.clone(), inner_h, peer_addr)
			} else {
				Box::new(future::ok(()))
			}
		});
		Box::new(listener)
	}
}

/// Extract the list of seeds from a pre-defined text file available through
/// http. Easy method until we have a set of DNS names we can rely on.
pub fn web_seeds(h: reactor::Handle) -> Box<Future<Item = Vec<SocketAddr>, Error = String>> {
	let url = hyper::Uri::from_str(&SEEDS_URL).unwrap();
	let seeds = future::ok(()).and_then(move |_| {
		let client = hyper::Client::new(&h);

		// http get, filtering out non 200 results
		client.get(url)
			.map_err(|e| e.to_string())
			.and_then(|res| {
				if res.status() != hyper::Ok {
					return Err(format!("Gist request failed: {}", res.status()));
				}
				Ok(res)
			})
			.and_then(|res| {
				// collect all chunks and split around whitespace to get a list of SocketAddr
				res.body().collect().map_err(|e| e.to_string()).and_then(|chunks| {
					let res = chunks.iter().fold("".to_string(), |acc, ref chunk| {
						acc + str::from_utf8(&chunk[..]).unwrap()
					});
					let addrs =
						res.split_whitespace().map(|s| s.parse().unwrap()).collect::<Vec<_>>();
					Ok(addrs)
				})
			})
	});
	Box::new(seeds)
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>)
                        -> Box<Future<Item = Vec<SocketAddr>, Error = String>> {
	let seeds = future::ok(())
		.and_then(move |_| Ok(addrs_str.iter().map(|s| s.parse().unwrap()).collect::<Vec<_>>()));
	Box::new(seeds)
}

fn connect_and_req(capab: p2p::Capabilities,
                   p2p: Arc<p2p::Server>,
                   h: reactor::Handle,
                   addr: SocketAddr)
                   -> Box<Future<Item = (), Error = ()>> {
	let fut = p2p.connect_peer(addr, h)
		.and_then(move |p| {
			if let Some(p) = p {
				p.send_peer_request(capab);
			}
			Ok(())
		})
		.map_err(|e| {
			error!("Peer request error {:?}", e);
			()
		});
	Box::new(fut)
}
<|endoftext|>


<commit_before>use nom::{IResult, be_u16};

/// Header for resource record queries and responses
#[derive(Debug,Clone,Copy)]
pub struct Header {
    /// A 16 bit identifier assigned by the program.
    pub id: u16,
    /// Specifies whether this message is a query.
    pub qr: bool,
    opcode: u8,
    /// Whether the response is authoritative
    pub aa: bool,
    /// Whether the response is truncated
    pub tc: bool,
    /// Whether recursion is desired
    pub rd: bool,
    /// Whether recursion is available
    pub ra: bool,
    /// The response code
    pub rcode: u8,
    /// The number of entries in the question section.
    pub qdcount: u16,
    /// The number of entries in the resource records section.
    pub ancount: u16,
    /// The number of entries in the authority records section.
    pub nscount: u16,
    /// The number of entries in the additional records section.
    pub arcount: u16,
}

impl Header {
    /// Parses a byte stream into a `Header`
    pub fn parser(i: &[u8]) -> IResult<&[u8], Header> {
        header(i)
    }
}

//                                 1  1  1  1  1  1
//   0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                      ID                       |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                    QDCOUNT                    |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                    ANCOUNT                    |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                    NSCOUNT                    |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                    ARCOUNT                    |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

struct Flags {
    qr: bool,
    opcode: u8,
    aa: bool,
    tc: bool,
    rd: bool,
    ra: bool,
    rcode: u8,
}

named!(header_flags<&[u8], Flags>,
bits!(do_parse!(
     qr:     take_bits!( u8, 1 ) >>
     opcode: take_bits!( u8, 4 ) >>
     aa:     take_bits!( u8, 1 ) >>
     tc:     take_bits!( u8, 1 ) >>
     rd:     take_bits!( u8, 1 ) >>
     ra:     take_bits!( u8, 1 ) >>
     zero:   take_bits!( u8, 3 ) >>
     rcode:  take_bits!( u8, 4 ) >>
     (Flags {
          qr: (qr == 1),
          opcode: opcode,
          aa: (aa == 1),
          tc: (tc == 1),
          rd: (rd == 1),
          ra: (ra == 1),
          rcode: rcode
      })
)));

named!(header<&[u8], Header>,
do_parse!(
    id:          be_u16 >>
    flags: header_flags >>
    qdcount:     be_u16 >>
    ancount:     be_u16 >>
    nscount:     be_u16 >>
    arcount:     be_u16 >>
    (Header {
        id: id,
        qr: flags.qr,
        opcode: flags.opcode,
        aa: flags.aa,
        tc: flags.tc,
        rd: flags.rd,
        ra: flags.ra,
        rcode: flags.rcode,
        qdcount: qdcount,
        ancount: ancount,
        nscount: nscount,
        arcount: arcount
    })
));

#[cfg(test)]
mod tests {
    use nom::IResult;
    use super::Header;

    #[test]
    fn parse_query_1_header() {
        let data = include_bytes!("../assets/captures/dns_1_query.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        assert_eq!(header.id, 2);
        assert!(!header.qr);
        assert!(!header.aa);
        assert!(!header.tc);
        assert!(header.rd);
        assert!(!header.ra);
        assert_eq!(0, header.rcode);
        assert_eq!(1, header.qdcount);
        assert_eq!(0, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_response_1_header() {
        let data = include_bytes!("../assets/captures/dns_1_response.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        assert!(header.qr);
        assert_eq!(header.id, 2);
        assert!(!header.aa);
        assert!(!header.tc);
        assert!(header.rd);
        assert!(header.ra);
        assert_eq!(0, header.rcode);
        assert_eq!(1, header.qdcount);
        assert_eq!(1, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_query_2_header() {
        let data = include_bytes!("../assets/captures/dns_2_query.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        assert_eq!(header.id, 3);
        assert!(!header.qr);
        assert!(!header.aa);
        assert!(!header.tc);
        assert!(header.rd);
        assert!(!header.ra);
        assert_eq!(0, header.rcode);
        assert_eq!(1, header.qdcount);
        assert_eq!(0, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_response_2_header() {
        let data = include_bytes!("../assets/captures/dns_2_response.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        assert!(header.qr);
        assert_eq!(header.id, 3);
        assert!(!header.aa);
        assert!(!header.tc);
        assert!(header.rd);
        assert!(header.ra);
        assert_eq!(0, header.rcode);
        assert_eq!(1, header.qdcount);
        assert_eq!(1, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_query_3_header() {
        let data = include_bytes!("../assets/captures/dns_3_query.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        assert_eq!(header.id, 0xda64);
        assert!(!header.qr);
        assert!(!header.aa);
        assert!(!header.tc);
        assert!(header.rd);
        assert!(!header.ra);
        assert_eq!(0, header.rcode);
        assert_eq!(1, header.qdcount);
        assert_eq!(0, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_response_3_header() {
        let data = include_bytes!("../assets/captures/dns_3_response.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        assert!(header.qr);
        assert_eq!(header.id, 0xda64);
        assert!(!header.aa);
        assert!(!header.tc);
        assert!(header.rd);
        assert!(header.ra);
        assert_eq!(0, header.rcode);
        assert_eq!(1, header.qdcount);
        assert_eq!(2, header.ancount);
        assert_eq!(1, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_query_4_header() {
        let data = include_bytes!("../assets/captures/dns_4_query.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            IResult::Error(err) => {
                println!("{:?}", err);
                panic!("Result not parsed correctly (Error)");
            },
            IResult::Incomplete(needed) => {
                println!("{:?}", needed);
                panic!("Result not parsed correctly (Incomplete)");
            },
        };
        assert_eq!(header.id, 0x60ff);
        assert!(!header.qr);
        assert!(!header.aa);
        assert!(!header.tc);
        assert!(header.rd);
        assert!(!header.ra);
        assert_eq!(0, header.rcode);
        assert_eq!(1, header.qdcount);
        assert_eq!(0, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(1, header.arcount);
    }

    #[test]
    fn parse_response_4_header() {
        let data = include_bytes!("../assets/captures/dns_4_response.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        assert!(header.qr);
        assert_eq!(header.id, 0x60ff);
        assert!(!header.aa);
        assert!(!header.tc);
        assert!(header.rd);
        assert!(header.ra);
        assert_eq!(0, header.rcode);
        assert_eq!(1, header.qdcount);
        assert_eq!(13, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(1, header.arcount);
    }
}
<commit_msg>refactor: add test utilities<commit_after>use nom::{IResult, be_u16};

/// Header for resource record queries and responses
#[derive(Debug,Clone,Copy)]
pub struct Header {
    /// A 16 bit identifier assigned by the program.
    pub id: u16,
    /// Specifies whether this message is a query.
    pub qr: bool,
    /// The type of query
    pub opcode: u8,
    /// Whether the response is authoritative
    pub aa: bool,
    /// Whether the response is truncated
    pub tc: bool,
    /// Whether recursion is desired
    pub rd: bool,
    /// Whether recursion is available
    pub ra: bool,
    /// The response code
    pub rcode: u8,
    /// The number of entries in the question section.
    pub qdcount: u16,
    /// The number of entries in the resource records section.
    pub ancount: u16,
    /// The number of entries in the authority records section.
    pub nscount: u16,
    /// The number of entries in the additional records section.
    pub arcount: u16,
}

impl Header {
    /// Parses a byte stream into a `Header`
    pub fn parser(i: &[u8]) -> IResult<&[u8], Header> {
        header(i)
    }
}

//                                 1  1  1  1  1  1
//   0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                      ID                       |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                    QDCOUNT                    |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                    ANCOUNT                    |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                    NSCOUNT                    |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |                    ARCOUNT                    |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

struct Flags {
    qr: bool,
    opcode: u8,
    aa: bool,
    tc: bool,
    rd: bool,
    ra: bool,
    rcode: u8,
}

named!(header_flags<&[u8], Flags>,
bits!(do_parse!(
     qr:     take_bits!( u8, 1 ) >>
     opcode: take_bits!( u8, 4 ) >>
     aa:     take_bits!( u8, 1 ) >>
     tc:     take_bits!( u8, 1 ) >>
     rd:     take_bits!( u8, 1 ) >>
     ra:     take_bits!( u8, 1 ) >>
     zero:   take_bits!( u8, 3 ) >>
     rcode:  take_bits!( u8, 4 ) >>
     (Flags {
          qr: (qr == 1),
          opcode: opcode,
          aa: (aa == 1),
          tc: (tc == 1),
          rd: (rd == 1),
          ra: (ra == 1),
          rcode: rcode
      })
)));

named!(header<&[u8], Header>,
do_parse!(
    id:          be_u16 >>
    flags: header_flags >>
    qdcount:     be_u16 >>
    ancount:     be_u16 >>
    nscount:     be_u16 >>
    arcount:     be_u16 >>
    (Header {
        id: id,
        qr: flags.qr,
        opcode: flags.opcode,
        aa: flags.aa,
        tc: flags.tc,
        rd: flags.rd,
        ra: flags.ra,
        rcode: flags.rcode,
        qdcount: qdcount,
        ancount: ancount,
        nscount: nscount,
        arcount: arcount
    })
));

#[cfg(test)]
mod tests {
    use nom::IResult;
    use super::Header;

    fn check_query(header: Header, id: u16, truncated: bool, recursion_desired: bool) {
        assert_eq!(id, header.id);
        assert!(!header.qr);
        assert_eq!(0, header.opcode);
        assert_eq!(truncated, header.tc);
        assert_eq!(recursion_desired, header.rd);
    }

    fn check_response(header: Header,
                      id: u16,
                      authoritative: bool,
                      truncated: bool,
                      recursion_desired: bool,
                      recursion_available: bool,
                      rcode: u8) {
        assert_eq!(id, header.id);
        assert!(header.qr);
        assert_eq!(0, header.opcode);
        assert_eq!(authoritative, header.aa);
        assert_eq!(truncated, header.tc);
        assert_eq!(recursion_desired, header.rd);
        assert_eq!(recursion_available, header.ra);
        assert_eq!(rcode, header.rcode);
    }

    #[test]
    fn parse_query_1_header() {
        let data = include_bytes!("../assets/captures/dns_1_query.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        check_query(header, 2, false, true);
        assert_eq!(1, header.qdcount);
        assert_eq!(0, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_response_1_header() {
        let data = include_bytes!("../assets/captures/dns_1_response.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        check_response(header, 2, false, false, true, true, 0);
        assert_eq!(1, header.qdcount);
        assert_eq!(1, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_query_2_header() {
        let data = include_bytes!("../assets/captures/dns_2_query.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        check_query(header, 3, false, true);
        assert_eq!(1, header.qdcount);
        assert_eq!(0, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_response_2_header() {
        let data = include_bytes!("../assets/captures/dns_2_response.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        check_response(header, 3, false, false, true, true, 0);
        assert_eq!(1, header.qdcount);
        assert_eq!(1, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_query_3_header() {
        let data = include_bytes!("../assets/captures/dns_3_query.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        check_query(header, 0xda64, false, true);
        assert_eq!(1, header.qdcount);
        assert_eq!(0, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_response_3_header() {
        let data = include_bytes!("../assets/captures/dns_3_response.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        check_response(header, 0xda64, false, false, true, true, 0);
        assert_eq!(1, header.qdcount);
        assert_eq!(2, header.ancount);
        assert_eq!(1, header.nscount);
        assert_eq!(0, header.arcount);
    }

    #[test]
    fn parse_query_4_header() {
        let data = include_bytes!("../assets/captures/dns_4_query.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            IResult::Error(err) => {
                println!("{:?}", err);
                panic!("Result not parsed correctly (Error)");
            }
            IResult::Incomplete(needed) => {
                println!("{:?}", needed);
                panic!("Result not parsed correctly (Incomplete)");
            }
        };
        check_query(header, 0x60ff, false, true);
        assert_eq!(1, header.qdcount);
        assert_eq!(0, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(1, header.arcount);
    }

    #[test]
    fn parse_response_4_header() {
        let data = include_bytes!("../assets/captures/dns_4_response.bin");
        let header = match Header::parser(&data[0..12]) {
            IResult::Done(_, res) => res,
            _ => panic!("Result not parsed correctly"),
        };
        check_response(header, 0x60ff, false, false, true, true, 0);
        assert_eq!(1, header.qdcount);
        assert_eq!(13, header.ancount);
        assert_eq!(0, header.nscount);
        assert_eq!(1, header.arcount);
    }
}
<|endoftext|>


<commit_before>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::rc::Rc;
use std::path::Path;
use glium::{Surface, GlObject};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Texture(GliumTexture);

impl PartialEq<Texture> for Texture {
    fn eq(&self, other: &Texture) -> bool {
        self.0.get_id() == other.0.get_id()
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex: texcoord,
        }
    }
}

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    // compiling shaders and linking them together
    let program = program!(&display,
        150 => {
            vertex: "
                #version 150 core

                uniform mat4 matrix;

                in vec2 pos;
                in vec4 color;
                in vec2 tex;

                out vec4 vColor;
                out vec2 vTexcoord;

                void main() {
                    gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                    vColor = color;
                    vTexcoord = tex;
                }
            ",

            fragment: "
                #version 150 core
                uniform sampler2D tex;
                in vec4 vColor;
                in vec2 vTexcoord;
                out vec4 f_color;

                void main() {
                    f_color = vColor * texture(tex, vTexcoord);
                }
            "
        },
    )
                      .unwrap();

    let mut context: Context<Rc<Texture>, Vertex>;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png")).unwrap());
    context = builder.build(|img| {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(), dim);
        Rc::new(Texture(glium::texture::CompressedSrgbTexture2d::new(&display, raw).unwrap()))
    });

    let font = context.default_font();

    let mut test_input = String::new();

    // the main loop
    loop {
        context.begin_frame();

        let i = context.get_image(image);
        context.draw_image(&i, Point2D::new(100.0, 100.0), [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        // drawing a frame

        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&(*batch.texture).0)
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&display, &batch.vertices).unwrap()
            };

            // building the index buffer
            let index_buffer = glium::IndexBuffer::new(&display,
                                                       PrimitiveType::TrianglesList,
                                                       &batch.triangle_indices)
                                   .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer, &index_buffer, &program, &uniforms, &params).unwrap();
        }

        target.finish().unwrap();

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                glutin::Event::MouseMoved(x, y) => context.input_mouse_move(x, y),
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    match vk {
                        Tab => context.input_key_state(vitral::Keycode::Tab, is_down),
                        LShift | RShift => context.input_key_state(vitral::Keycode::Shift, is_down),
                        LControl | RControl => {
                            context.input_key_state(vitral::Keycode::Ctrl, is_down)
                        }
                        NumpadEnter | Return => {
                            context.input_key_state(vitral::Keycode::Enter, is_down)
                        }
                        Back => context.input_key_state(vitral::Keycode::Backspace, is_down),
                        Delete => context.input_key_state(vitral::Keycode::Del, is_down),
                        Numpad8 | Up => context.input_key_state(vitral::Keycode::Up, is_down),
                        Numpad2 | Down => context.input_key_state(vitral::Keycode::Down, is_down),
                        Numpad4 | Left => context.input_key_state(vitral::Keycode::Left, is_down),
                        Numpad6 | Right => context.input_key_state(vitral::Keycode::Right, is_down),
                        _ => {}
                    }
                }
                _ => (),
            }
        }
    }
}
<commit_msg>WIP wrap Glium backend in struct<commit_after>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::path::Path;
use glium::{DisplayBuild, Surface};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Backend {
    display: glium::Display,
    program: glium::Program,
    textures: Vec<GliumTexture>,
}

impl Backend {
    pub fn new(display: glium::Display, program: glium::Program) -> Backend {
        Backend {
            display: display,
            program: program,
            textures: Vec::new(),
        }
    }

    pub fn make_texture(&mut self, img: vitral::ImageBuffer) -> usize {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(),
                                                            dim);
        let tex = glium::texture::CompressedSrgbTexture2d::new(&self.display,
                                                               raw)
                      .unwrap();
        self.textures.push(tex);
        self.textures.len() - 1
    }

    pub fn update(&self, context: &mut Context<usize, Vertex>) -> bool {
        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&self.textures[batch.texture])
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&self.display, &batch.vertices)
                    .unwrap()
            };

            // building the index buffer
            let index_buffer =
                glium::IndexBuffer::new(&self.display,
                                        PrimitiveType::TrianglesList,
                                        &batch.triangle_indices)
                    .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer,
                        &index_buffer,
                        &self.program,
                        &uniforms,
                        &params)
                  .unwrap();
        }

        target.finish().unwrap();

        // polling and handling the events received by the window
        for event in self.display.poll_events() {
            match event {
                glutin::Event::Closed => return false,
                glutin::Event::MouseMoved(x, y) => {
                    context.input_mouse_move(x, y)
                }
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    match vk {
                        Tab => {
                            context.input_key_state(vitral::Keycode::Tab,
                                                    is_down)
                        }
                        LShift | RShift => {
                            context.input_key_state(vitral::Keycode::Shift,
                                                    is_down)
                        }
                        LControl | RControl => {
                            context.input_key_state(vitral::Keycode::Ctrl,
                                                    is_down)
                        }
                        NumpadEnter | Return => {
                            context.input_key_state(vitral::Keycode::Enter,
                                                    is_down)
                        }
                        Back => {
                            context.input_key_state(vitral::Keycode::Backspace,
                                                    is_down)
                        }
                        Delete => {
                            context.input_key_state(vitral::Keycode::Del,
                                                    is_down)
                        }
                        Numpad8 | Up => {
                            context.input_key_state(vitral::Keycode::Up,
                                                    is_down)
                        }
                        Numpad2 | Down => {
                            context.input_key_state(vitral::Keycode::Down,
                                                    is_down)
                        }
                        Numpad4 | Left => {
                            context.input_key_state(vitral::Keycode::Left,
                                                    is_down)
                        }
                        Numpad6 | Right => {
                            context.input_key_state(vitral::Keycode::Right,
                                                    is_down)
                        }
                        _ => {}
                    }
                }
                _ => (),
            }
        }

        true
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex: texcoord,
        }
    }
}

fn main() {
    // Construct Glium backend.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    // building the display, ie. the main object
    let program = program!(
        &display,
        150 => {
        vertex: "
            #version 150 core

            uniform mat4 matrix;

            in vec2 pos;
            in vec4 color;
            in vec2 tex;

            out vec4 vColor;
            out vec2 vTexcoord;

            void main() {
                gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                vColor = color;
                vTexcoord = tex;
            }
        ",

        fragment: "
            #version 150 core
            uniform sampler2D tex;
            in vec4 vColor;
            in vec2 vTexcoord;
            out vec4 f_color;

            void main() {
                f_color = vColor * texture(tex, vTexcoord);
            }
        "})
                      .unwrap();

    let mut backend = Backend::new(display, program);

    // Construct Vitral context.
    let mut context: Context<usize, Vertex>;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png"))
                                       .unwrap());
    context = builder.build(|img| backend.make_texture(img));

    let font = context.default_font();

    let mut test_input = String::new();

    // Run the program.
    loop {
        context.begin_frame();

        context.draw_image(image,
                           Point2D::new(100.0, 100.0),
                           [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        if !backend.update(&mut context) {
            return;
        }
    }
}
<|endoftext|>


<commit_before>
use std::usize;

use crate::graph::ID;
use crate::sim::{Io, TestPacket, RoutingAlgorithm};
use crate::utils::vec_filter;

/*
* Routing on top of an Spanning Tree.
*
* Tasks:
* - create a spanning tree
*/

#[derive(Clone, PartialEq)]
struct Path {
	id: u32,
	path: Vec<u32>,
}

impl Path {
	fn new() -> Self {
		Self {id: 0, path: Vec::new()}
	}

	fn with(id: u32) -> Self {
		Self {id: id, path: Vec::new()}
	}

	fn len(&self) -> usize {
		self.path.len()
	}

	fn last(&self) -> Option<u32> {
		if let Some(n) = self.path.last() {
			Some(*n)
		} else {
			None
		}
	}
}

#[derive(Clone)]
struct Packet {
	sender_id: u32,
	path: Path,
}

impl Packet {
	fn new() -> Self {
		Packet {
			sender_id: 0,
			path: Path::new(),
		}
	}
}

#[derive(Clone, PartialEq)]
struct Neighbor {
	id: u32,
	n: u8,
	last_updated: u32,
}

#[derive(Clone)]
struct Node {
	id: u32,
	path: Path,
	time: u32,

	// the entry with the smallest id is the root
	neighbors: Vec<Neighbor>
}

impl Node {
	fn new() -> Self {
		Self {
			id: 0,
			path: Path::new(),
			time: 0,
			neighbors: Vec::new(),
		}
	}

	fn init(&mut self, id: u32, time: u32) {
		self.id = id;
		self.path = Path::with(id);
		self.time = time;
		self.neighbors.clear();
	}

	fn is_better(p1: &Path, p2: &Path) -> bool {
		(p1.id < p2.id) || (p1.id == p2.id && p1.len() < p2.len())
	}

	fn tick(&mut self) -> Packet {
		self.time += 1;

		// timeout old entries
		let time = self.time;
		vec_filter(&mut self.neighbors, |ref e| (e.last_updated + 5) >= time);

		fn clone_append(path: &Path, id: u32) -> Path {
			let mut v = path.clone();
			v.path.push(id);
			v
		}

		Packet {
			sender_id: self.id,
			path: self.path.clone()
		}
	}

	fn update(&mut self, packet: &Packet) {
		fn update_neighbor(neighbors: &mut Vec<Neighbor>, packet: &Packet, time: u32) {
			for neighbor in neighbors.iter_mut() {
				if neighbor.id == packet.sender_id {
					neighbor.last_updated = time;
					return;
				}
			}

			let mut n = 0;
			for i in 0..200 {
				let mut taken = false;
				for neighbor in neighbors.iter() {
					if neighbor.n == i {
						taken = true;
					}
				}
				if !taken {
					n = i;
					break;
				}
			}

			neighbors.push(Neighbor{id: packet.sender_id, n: (n as u8), last_updated: time});
		}

		fn is_loop(path: &[u32], id: u32) -> bool {
			for pid in path {
				if *pid == id {
					return true;
				}
			}
			false
		}

		if Self::is_better(&packet.path, &self.path) {
			self.path = packet.path.clone();
			self.path.path.push(packet.sender_id);
		}

		update_neighbor(&mut self.neighbors, packet, self.time);
	}

	fn route(&self, dpath: &Path) -> Option<ID> {
		if let Some(destination) = dpath.last() {
			// destination is this node
			if destination == self.id {
				return None;
			}

			// desination is a direct neighbor
			for neighbor in &self.neighbors {
				if neighbor.id == destination {
					return Some(destination);
				}
			}

			// different tree!
			if dpath.id != self.path.id {
				return None;
			}

			if dpath.len() == self.path.len() {
				// no idea what to do...
				return None;
			} else if dpath.len() < self.path.len() {
				// move up the tree
				return self.path.last();
			} else {
				// move down the tree
				let neighbor_id = dpath.path[self.path.len()];

				for neighbor in &self.neighbors {
					if neighbor.id == neighbor_id {
						return Some(neighbor_id);
					}
				}

				// no idea what to do
				return None;
			}
		} else {
			None
		}
	}
}

pub struct SpanningTreeRouting {
	nodes: Vec<Node>,
	packets: Vec<Packet> // store packet that a node will send to it's neighbors separately, this will avoid cloning the nodes array on every step
}

impl SpanningTreeRouting {
	pub fn new() -> Self {
		Self {
			nodes: Vec::new(),
			packets: Vec::new()
		}
	}
}

impl RoutingAlgorithm for SpanningTreeRouting
{
	fn get_node(&self, id: ID, key: &str, out: &mut std::fmt::Write) -> Result<(), std::fmt::Error> {
		let node = &self.nodes[id as usize];
		match key {
			"name" => {
				write!(out, "{}", node.id)?;
			},
			"label" => {
				write!(out, "{},{}", node.neighbors.len(), node.path.len())?;
			},
			/*
			"color" => {
				write!(out, "#{:0x}", node.root.root_id)?;
			},*/
			_ => {}
		}
		Ok(())
	}

	fn get(&self, key: &str, out: &mut std::fmt::Write) -> Result<(), std::fmt::Error> {
		match key {
			"description" => {
				write!(out, "{}",
					concat!("Create a spanning tree. Every node is assigned a random (unique) identifier and shares with the neighbors the lowest known identifier, called root.",
						"The lowest identifier is propagated along with the path the identifier takes."))?;
			},
			"name" => {
				write!(out, "Spanning Tree Routing")?;
			},
			_ => {}
		}
		Ok(())
	}

	fn reset(&mut self, len: usize) {
		self.nodes = vec![Node::new(); len];
		self.packets = vec![Packet::new(); len];

		fn contains(nodes: &Vec<Node>, id: u32) -> bool {
			for i in 0..nodes.len() {
				if nodes[i].id == id {
					return true;
				}
			}
			false
		}

		fn unique_rnd_id(nodes: &Vec<Node>) -> u32 {
			loop {
				let id = rand::random::<u32>() % (nodes.len() as u32 * 2);
				if !contains(&nodes, id) {
					return id;
				}
			}
		}

		// Assign random numbers.
		// Avoid edges case for now when the ids are not unique
		for i in 0..len {
			let id = unique_rnd_id(&self.nodes);
			let time = rand::random::<u16>() as u32;
			self.nodes[i].init(id, time);
		}
	}

	fn step(&mut self, io: &mut Io) {
		// keep state
		for i in 0..self.nodes.len() {
			self.packets[i] = self.nodes[i].tick();
		}

		for (from, to) in io.link_iter() {
			let packet = &self.packets[from as usize];
			self.nodes[to as usize].update(&packet);
		}
	}

/*
pub fn new(transmitter: ID, receiver: ID, source: ID, destination: ID) -> Self {
		Self { transmitter, receiver, source, destination }
	}
*/

	fn route(&self, packet: &TestPacket) -> Option<ID> {
		let dpath = &self.nodes[packet.destination as usize].path;
		self.nodes[packet.receiver as usize].route(dpath)
	}

}
<commit_msg>improve spanning tree algorithm<commit_after>
use std::usize;

use crate::graph::ID;
use crate::sim::{Io, TestPacket, RoutingAlgorithm};
use crate::utils::vec_filter;

/*
* Routing on top of an Spanning Tree.
*/

#[derive(Clone, PartialEq, Debug)]
struct Path {
	id: u32, // todo: remove
	path: Vec<u32>,
}

impl Path {
	fn new() -> Self {
		Self {id: 0, path: Vec::new()}
	}

	fn with(id: u32) -> Self {
		Self {id: id, path: vec![id]}
	}

	fn len(&self) -> usize {
		self.path.len()
	}

	fn push(&mut self, id: u32) {
		self.path.push(id);
	}
}

#[derive(Clone)]
struct Packet {
	sender_id: u32,
	path: Path,
}

impl Packet {
	fn new() -> Self {
		Packet {
			sender_id: 0,
			path: Path::new(),
		}
	}
}

#[derive(Clone, PartialEq)]
struct Neighbor {
	id: u32,
	//n: u8,
	last_updated: u32,
}

#[derive(Clone)]
struct Node {
	id: u32,
	path: Path,
	time: u32,

	// the entry with the smallest id is the root
	neighbors: Vec<Neighbor>
}

fn has_duplicates(path: &Vec<u32>) -> bool {
	let len = path.len();
	for i in 0..len {
		for j in 0..len {
			if i != j && path[i] == path[j] {
				return true;
			}
		}
	}
	false
}

impl Node {
	fn new() -> Self {
		Self {
			id: 0,
			path: Path::new(),
			time: 0,
			neighbors: Vec::new(),
		}
	}

	fn init(&mut self, id: u32, time: u32) {
		self.id = id;
		self.path = Path::with(id);
		self.time = time;
		self.neighbors.clear();
	}

	fn is_better(p1: &Path, p2: &Path) -> bool {
		(p1.id < p2.id) || (p1.id == p2.id && p1.len() < p2.len())
	}

	fn tick(&mut self) -> Packet {
		self.time += 1;

		// timeout old entries
		let time = self.time;
		vec_filter(&mut self.neighbors, |ref e| (e.last_updated + 5) >= time);

		Packet {
			sender_id: self.id,
			path: self.path.clone()
		}
	}

	fn update(&mut self, packet: &Packet) {
		fn update_neighbor(neighbors: &mut Vec<Neighbor>, packet: &Packet, time: u32) {
			for neighbor in neighbors.iter_mut() {
				if neighbor.id == packet.sender_id {
					neighbor.last_updated = time;
					return;
				}
			}

			neighbors.push(Neighbor{id: packet.sender_id, last_updated: time});
		}

		fn is_loop(path: &[u32], id: u32) -> bool {
			for pid in path {
				if *pid == id {
					return true;
				}
			}
			false
		}

		if Self::is_better(&packet.path, &self.path) {
			self.path = packet.path.clone();
			self.path.path.push(self.id);
		}

		update_neighbor(&mut self.neighbors, packet, self.time);
	}

	fn route(&self, dpath: &Path, destination: ID) -> Option<ID> {
		println!("self.id: {}, path: {:?}, dpath: {:?}", self.id, self.path, dpath);

		fn get_common_len(p1: &Path, p2: &Path) -> usize {
			let len = usize::min(p1.len(), p2.len());
			for i in 0..len {
				if p1.path[i] != p2.path[i] {
					return i;
				}
			}
			len
		}

		// destination is this node
		if destination == self.id {
			println!("destination reached");
			return None;
		}

		// desination is a direct neighbor
		for neighbor in &self.neighbors {
			if neighbor.id == destination {
				println!("direct neighbor found");
				return Some(destination);
			}
		}

		// different tree!
		if dpath.id != self.path.id {
			println!("different root! {} {}", dpath.id, self.path.id);
			return None;
		}

		let common_len = get_common_len(&self.path, &dpath);

		if common_len == 0 {
			println!("common_len is zero");
			return None;
		} else if common_len < self.path.len() {
			// move up the tree
			let next = self.path.path[self.path.len() - 2];
			println!("up the tree: {}", next);
			return Some(next);
		} else {
			// move down the tree
			let neighbor_id = dpath.path[common_len];
			println!("down the tree: {}", neighbor_id);

			for neighbor in &self.neighbors {
				if neighbor.id == neighbor_id {
					println!("down the tree: {}", neighbor_id);
					return Some(neighbor_id);
				}
			}

			println!("no neighbor found");
			return None;
		}
	}
}

pub struct SpanningTreeRouting {
	nodes: Vec<Node>,
	packets: Vec<Packet> // store packet that a node will send to it's neighbors separately, this will avoid cloning the nodes array on every step
}

impl SpanningTreeRouting {
	pub fn new() -> Self {
		Self {
			nodes: Vec::new(),
			packets: Vec::new()
		}
	}
}

impl RoutingAlgorithm for SpanningTreeRouting {
	fn get_node(&self, id: ID, key: &str, out: &mut std::fmt::Write) -> Result<(), std::fmt::Error> {
		let node = &self.nodes[id as usize];
		match key {
			"name" => {
				write!(out, "{}", node.id)?;
			},
			"label" => {
				write!(out, "{},{}", node.neighbors.len(), node.path.len())?;
			},
			/*
			"color" => {
				write!(out, "#{:0x}", node.root.root_id)?;
			},*/
			_ => {}
		}
		Ok(())
	}

	fn get(&self, key: &str, out: &mut std::fmt::Write) -> Result<(), std::fmt::Error> {
		match key {
			"description" => {
				write!(out, "{}",
					concat!("Create a spanning tree. Every node is assigned a random (unique) identifier and shares with the neighbors the lowest known identifier, called root.",
						"The lowest identifier is propagated along with the path the identifier takes."))?;
			},
			"name" => {
				write!(out, "Spanning Tree Routing")?;
			},
			_ => {}
		}
		Ok(())
	}

	fn reset(&mut self, len: usize) {
		self.nodes = vec![Node::new(); len];
		self.packets = vec![Packet::new(); len];

		fn contains(nodes: &Vec<Node>, id: u32) -> bool {
			for i in 0..nodes.len() {
				if nodes[i].id == id {
					return true;
				}
			}
			false
		}

		fn unique_rnd_id(nodes: &Vec<Node>) -> u32 {
			loop {
				let id = rand::random::<u32>() % (nodes.len() as u32 * 2);
				if !contains(&nodes, id) {
					return id;
				}
			}
		}

		// Assign random numbers.
		// Avoid edges case for now when the ids are not unique
		for i in 0..len {
			//let id = unique_rnd_id(&self.nodes);
			let time = rand::random::<u16>() as u32;
			self.nodes[i].init(i as u32, time);
		}
	}

	fn step(&mut self, io: &mut Io) {
		// keep state
		for i in 0..self.nodes.len() {
			self.packets[i] = self.nodes[i].tick();
		}

		for (from, to) in io.link_iter() {
			let packet = &self.packets[from as usize];
			self.nodes[to as usize].update(&packet);
		}
	}

/*
pub fn new(transmitter: ID, receiver: ID, source: ID, destination: ID) -> Self {
		Self { transmitter, receiver, source, destination }
	}
*/

	fn route(&self, packet: &TestPacket) -> Option<ID> {
		let dpath = &self.nodes[packet.destination as usize].path;
		self.nodes[packet.receiver as usize].route(dpath, packet.destination)
	}

}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! A `mod` containing constructs useful in infix operator parsing with the precedence climbing
//! method.

use std::collections::HashMap;
use std::iter::Peekable;
use std::ops::BitOr;

use super::inputs::Input;
use super::iterators::{Pair, Pairs};
use super::RuleType;

/// An `enum` describing an `Operator`'s associativity.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Assoc {
    /// Left `Operator` associativity
    Left,
    /// Right `Operator` associativity
    Right
}

/// A `struct` defining an infix operator used in [PrecClimber](struct.PrecClimber.html).
#[derive(Debug)]
pub struct Operator<R: RuleType> {
    rule: R,
    assoc: Assoc,
    next: Option<Box<Operator<R>>>
}

impl<R: RuleType> Operator<R> {
    /// Creates a new `Operator` from a `Rule` and `Assoc`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, Operator};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus
    /// # }
    /// let additive = Operator::new(Rule::plus, Assoc::Left) |
    ///                Operator::new(Rule::minus, Assoc::Right);
    /// ```
    pub fn new(rule: R, assoc: Assoc) -> Operator<R> {
        Operator {
            rule,
            assoc,
            next: None
        }
    }
}

impl<R: RuleType> BitOr for Operator<R> {
    type Output = Self;

    fn bitor(mut self, rhs: Self) -> Self {
        self.next = Some(Box::new(rhs));
        self
    }
}

/// A `struct` useful in order to perform [precedence climbing][1] on infix expressions contained in
/// a [`Pairs`](../iterators/struct.Pairs.html). The token pairs contained in the `Pairs` should
/// start with a *primary* pair and then alternate between an *operator* and a *primary*.
///
/// [1]: https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method
#[derive(Debug)]
pub struct PrecClimber<R: RuleType> {
    ops: HashMap<R, (u32, Assoc)>
}

impl<R: RuleType> PrecClimber<R> {
    /// Creates a new `PrecClimber` from the `Operator`s contained in `ops`. Every entry in the
    /// `Vec` has precedence *index + 1*. In order to have operators with same precedence, they need
    /// to be chained with `|` between them.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, Operator, PrecClimber};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus,
    /// #     times,
    /// #     divide,
    /// #     power
    /// # }
    /// let climber = PrecClimber::new(vec![
    ///     Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Left),
    ///     Operator::new(Rule::times, Assoc::Left) | Operator::new(Rule::divide, Assoc::Left),
    ///     Operator::new(Rule::power, Assoc::Right)
    /// ]);
    /// ```
    pub fn new(ops: Vec<Operator<R>>) -> PrecClimber<R> {
        let ops = ops.into_iter().zip((1..)).fold(HashMap::new(), |mut map, (op, prec)| {
            let mut next = Some(op);

            while let Some(op) = next.take() {
                match op {
                    Operator { rule, assoc, next: op_next } => {
                        map.insert(rule, (prec, assoc));
                        next = op_next.map(|op| *op);
                    }
                }
            }

            map
        });

        PrecClimber {
            ops
        }
    }

    /// Performs the precedence climbing algorithm on the `pairs` in a similar manner to map-reduce.
    /// *Primary* pairs are mapped with `primary` and then reduced to one single result with
    /// `infix`.
    ///
    /// # Panics
    ///
    /// Panics will occur when `pairs` is empty or when the alternating *primary*, *operator*,
    /// *primary* order is not respected.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let primary = |pair| {
    ///     consume(pair, climber)
    /// };
    /// let infix = |lhs: i32, op: Pair<Rule, StringInput>, rhs: i32| {
    ///     match op.rule() {
    ///         Rule::plus => lhs + rhs,
    ///         Rule::minus => lhs - rhs,
    ///         Rule::times => lhs * rhs,
    ///         Rule::divide => lhs / rhs,
    ///         Rule::power => lhs.pow(rhs as u32),
    ///         _ => unreachable!()
    ///     }
    /// };
    ///
    /// let result = climber.climb(pairs, primary, infix);
    /// ```
    pub fn climb<I: Input, F, G, T>(
        &self,
        mut pairs: Pairs<R, I>,
        mut primary: F,
        mut infix: G
    ) -> T
    where
        F: FnMut(Pair<R, I>) -> T,
        G: FnMut(T, Pair<R, I>, T) -> T
    {
        let lhs = primary(pairs.next().expect("precedence climbing requires a non-empty Pairs"));
        self.climb_rec(lhs, 0, &mut pairs.peekable(), &mut primary, &mut infix)
    }

    fn climb_rec<I: Input, F, G, T>(
        &self,
        mut lhs: T,
        min_prec: u32,
        pairs: &mut Peekable<Pairs<R, I>>,
        primary: &mut F,
        infix: &mut G
    ) -> T
    where
        F: FnMut(Pair<R, I>) -> T,
        G: FnMut(T, Pair<R, I>, T) -> T
    {
        while pairs.peek().is_some() {
            let rule = pairs.peek().unwrap().rule();
            if let Some(&(prec, _)) = self.ops.get(&rule) {
                if prec >= min_prec {
                    let op = pairs.next().unwrap();
                    let mut rhs = primary(pairs.next().expect("infix operator must be followed by \
                                                               a primary expression"));

                    while pairs.peek().is_some() {
                        let rule = pairs.peek().unwrap().rule();
                        if let Some(&(new_prec, assoc)) = self.ops.get(&rule) {
                            if new_prec > prec || assoc == Assoc::Right && new_prec == prec {
                                rhs = self.climb_rec(rhs, new_prec, pairs, primary, infix);
                            }
                        }
                    }

                    lhs = infix(lhs, op, rhs);
                }
            }
        }

        lhs
    }
}
<commit_msg>Fixed while loops.<commit_after>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! A `mod` containing constructs useful in infix operator parsing with the precedence climbing
//! method.

use std::collections::HashMap;
use std::iter::Peekable;
use std::ops::BitOr;

use super::inputs::Input;
use super::iterators::Pair;
use super::RuleType;

/// An `enum` describing an `Operator`'s associativity.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Assoc {
    /// Left `Operator` associativity
    Left,
    /// Right `Operator` associativity
    Right
}

/// A `struct` defining an infix operator used in [PrecClimber](struct.PrecClimber.html).
#[derive(Debug)]
pub struct Operator<R: RuleType> {
    rule: R,
    assoc: Assoc,
    next: Option<Box<Operator<R>>>
}

impl<R: RuleType> Operator<R> {
    /// Creates a new `Operator` from a `Rule` and `Assoc`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, Operator};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus
    /// # }
    /// let additive = Operator::new(Rule::plus, Assoc::Left) |
    ///                Operator::new(Rule::minus, Assoc::Right);
    /// ```
    pub fn new(rule: R, assoc: Assoc) -> Operator<R> {
        Operator {
            rule,
            assoc,
            next: None
        }
    }
}

impl<R: RuleType> BitOr for Operator<R> {
    type Output = Self;

    fn bitor(mut self, rhs: Self) -> Self {
        self.next = Some(Box::new(rhs));
        self
    }
}

/// A `struct` useful in order to perform [precedence climbing][1] on infix expressions contained in
/// a [`Pairs`](../iterators/struct.Pairs.html). The token pairs contained in the `Pairs` should
/// start with a *primary* pair and then alternate between an *operator* and a *primary*.
///
/// [1]: https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method
#[derive(Debug)]
pub struct PrecClimber<R: RuleType> {
    ops: HashMap<R, (u32, Assoc)>
}

impl<R: RuleType> PrecClimber<R> {
    /// Creates a new `PrecClimber` from the `Operator`s contained in `ops`. Every entry in the
    /// `Vec` has precedence *index + 1*. In order to have operators with same precedence, they need
    /// to be chained with `|` between them.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, Operator, PrecClimber};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus,
    /// #     times,
    /// #     divide,
    /// #     power
    /// # }
    /// let climber = PrecClimber::new(vec![
    ///     Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Left),
    ///     Operator::new(Rule::times, Assoc::Left) | Operator::new(Rule::divide, Assoc::Left),
    ///     Operator::new(Rule::power, Assoc::Right)
    /// ]);
    /// ```
    pub fn new(ops: Vec<Operator<R>>) -> PrecClimber<R> {
        let ops = ops.into_iter().zip((1..)).fold(HashMap::new(), |mut map, (op, prec)| {
            let mut next = Some(op);

            while let Some(op) = next.take() {
                match op {
                    Operator { rule, assoc, next: op_next } => {
                        map.insert(rule, (prec, assoc));
                        next = op_next.map(|op| *op);
                    }
                }
            }

            map
        });

        PrecClimber {
            ops
        }
    }

    /// Performs the precedence climbing algorithm on the `pairs` in a similar manner to map-reduce.
    /// *Primary* pairs are mapped with `primary` and then reduced to one single result with
    /// `infix`.
    ///
    /// # Panics
    ///
    /// Panics will occur when `pairs` is empty or when the alternating *primary*, *operator*,
    /// *primary* order is not respected.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let primary = |pair| {
    ///     consume(pair, climber)
    /// };
    /// let infix = |lhs: i32, op: Pair<Rule, StringInput>, rhs: i32| {
    ///     match op.rule() {
    ///         Rule::plus => lhs + rhs,
    ///         Rule::minus => lhs - rhs,
    ///         Rule::times => lhs * rhs,
    ///         Rule::divide => lhs / rhs,
    ///         Rule::power => lhs.pow(rhs as u32),
    ///         _ => unreachable!()
    ///     }
    /// };
    ///
    /// let result = climber.climb(pairs, primary, infix);
    /// ```
    pub fn climb<I: Input, P, F, G, T>(
        &self,
        mut pairs: P,
        mut primary: F,
        mut infix: G
    ) -> T
    where
        P: Iterator<Item=Pair<R, I>>,
        F: FnMut(Pair<R, I>) -> T,
        G: FnMut(T, Pair<R, I>, T) -> T
    {
        let lhs = primary(pairs.next().expect("precedence climbing requires a non-empty Pairs"));
        self.climb_rec(lhs, 0, &mut pairs.peekable(), &mut primary, &mut infix)
    }

    fn climb_rec<I: Input, P, F, G, T>(
        &self,
        mut lhs: T,
        min_prec: u32,
        pairs: &mut Peekable<P>,
        primary: &mut F,
        infix: &mut G
    ) -> T
    where
        P: Iterator<Item=Pair<R, I>>,
        F: FnMut(Pair<R, I>) -> T,
        G: FnMut(T, Pair<R, I>, T) -> T
    {
        while pairs.peek().is_some() {
            let rule = pairs.peek().unwrap().rule();
            if let Some(&(prec, _)) = self.ops.get(&rule) {
                if prec >= min_prec {
                    let op = pairs.next().unwrap();
                    let mut rhs = primary(pairs.next().expect("infix operator must be followed by \
                                                               a primary expression"));

                    while pairs.peek().is_some() {
                        let rule = pairs.peek().unwrap().rule();
                        if let Some(&(new_prec, assoc)) = self.ops.get(&rule) {
                            if new_prec > prec || assoc == Assoc::Right && new_prec == prec {
                                rhs = self.climb_rec(rhs, new_prec, pairs, primary, infix);
                            } else {
                                break;
                            }
                        } else {
                            break;
                        }
                    }

                    lhs = infix(lhs, op, rhs);
                }
            } else {
                break;
            }
        }

        lhs
    }
}
<|endoftext|>


<commit_before>//! This example of boxcars extracts all the player names found in the "PlayerStats" property of the
//! header. This property may be absent in some replays or lack players that drop or join mid-game.
//! A more foolproof approach is to scour the network data for a specific property:
//! "Engine.PlayerReplicationInfo:PlayerName". This example shows both methods. The error handling
//! demonstrated is minimal, relying on stringly typed errors. In practice, prefer a richer error
//! type.
use boxcars::{HeaderProp, ParserBuilder};
use std::error;
use std::io::{self, Read};

/// Given an array of objects (represented as a slice of key-value pairs), find all the instances
/// of the "Name" key and extract the string value
fn names_in_header(
    stats: &[Vec<(String, HeaderProp)>],
) -> impl Iterator<Item = &String> {
    stats
        .iter()
        .flat_map(|v| v.iter())
        .filter(|(prop_name, _)| *prop_name == "Name")
        .filter_map(|(_, prop_val)| {
            if let HeaderProp::Str(name) = prop_val {
                Some(name)
            } else {
                None
            }
        })
}

/// Given network frames and the object id to "Engine.PlayerReplicationInfo:PlayerName", comb
/// through all the attributes looking for attributes that have our object id.
fn names_in_network(
    frames: &[boxcars::Frame],
    name_attribute_id: boxcars::ObjectId,
) -> Vec<&String> {
    let mut names = frames
        .iter()
        .flat_map(|x| x.updated_actors.iter())
        .filter(|attr| attr.object_id == name_attribute_id)
        .filter_map(|attr| {
            // PlayerName will be a string attribute
            if let boxcars::Attribute::String(s) = &attr.attribute {
                Some(s)
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    // This list will contain many duplicates so we dedup it before returning.
    names.sort();
    names.dedup();
    names
}

/// This function looks up the object id for "Engine.PlayerReplicationInfo:PlayerName". The object
/// id is the same as the index of that value in the `replay.objects` array.
fn player_name_object_id(
    replay: &boxcars::Replay,
) -> Result<boxcars::ObjectId, Box<dyn error::Error>> {
    let id = replay
        .objects
        .iter()
        .position(|val| val == "Engine.PlayerReplicationInfo:PlayerName")
        .map(|index| boxcars::ObjectId(index as i32))
        .ok_or("Expected Engine.PlayerReplicationInfo:PlayerName to be present in replay")?;
    Ok(id)
}

fn main() -> Result<(), Box<dyn error::Error>> {
    let mut data = Vec::new();
    io::stdin().read_to_end(&mut data)?;

    let replay = ParserBuilder::new(&data[..])
        .on_error_check_crc()
        .ignore_network_data_on_error()
        .parse()?;

    let stats_prop = replay
        .properties
        .iter()
        .find(|(prop, _)| *prop == "PlayerStats");

    if let Some((_, stats)) = stats_prop {
        println!("Names in the header data:");
        let stats = match stats {
            HeaderProp::Array(arr) => arr,
            _ => return Err("expected player stats to be an array")?,
        };

        let header_names = names_in_header(&stats);
        for name in header_names {
            println!("{}", name);
        }
    } else {
        println!("No player names found in the header");
    }

    if let Some(network) = replay.network_frames.as_ref() {
        println!("Names in the network data:");
        let name_attribute_id = player_name_object_id(&replay)?;
        let names = names_in_network(&network.frames, name_attribute_id);
        for name in names {
            println!("{}", name);
        }
    } else {
        println!("No player names found in the header as network data couldn't be decoded")
    }

    Ok(())
}
<commit_msg>Prefer &str to &String in example<commit_after>//! This example of boxcars extracts all the player names found in the "PlayerStats" property of the
//! header. This property may be absent in some replays or lack players that drop or join mid-game.
//! A more foolproof approach is to scour the network data for a specific property:
//! "Engine.PlayerReplicationInfo:PlayerName". This example shows both methods. The error handling
//! demonstrated is minimal, relying on stringly typed errors. In practice, prefer a richer error
//! type.
use boxcars::{HeaderProp, ParserBuilder};
use std::error;
use std::io::{self, Read};

/// Given an array of objects (represented as a slice of key-value pairs), find all the instances
/// of the "Name" key and extract the string value
fn names_in_header(
    stats: &[Vec<(String, HeaderProp)>],
) -> impl Iterator<Item = &str> {
    stats
        .iter()
        .flat_map(|v| v.iter())
        .filter(|(prop_name, _)| *prop_name == "Name")
        .filter_map(|(_, prop_val)| prop_val.as_string())
}

/// Given network frames and the object id to "Engine.PlayerReplicationInfo:PlayerName", comb
/// through all the attributes looking for attributes that have our object id.
fn names_in_network(
    frames: &[boxcars::Frame],
    name_attribute_id: boxcars::ObjectId,
) -> Vec<&str> {
    let mut names = frames
        .iter()
        .flat_map(|x| x.updated_actors.iter())
        .filter(|attr| attr.object_id == name_attribute_id)
        .filter_map(|attr| {
            // PlayerName will be a string attribute
            if let boxcars::Attribute::String(ref s) = attr.attribute {
                Some(s.as_str())
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    // This list will contain many duplicates so we dedup it before returning.
    names.sort();
    names.dedup();
    names
}

/// This function looks up the object id for "Engine.PlayerReplicationInfo:PlayerName". The object
/// id is the same as the index of that value in the `replay.objects` array.
fn player_name_object_id(
    replay: &boxcars::Replay,
) -> Result<boxcars::ObjectId, Box<dyn error::Error>> {
    let id = replay
        .objects
        .iter()
        .position(|val| val == "Engine.PlayerReplicationInfo:PlayerName")
        .map(|index| boxcars::ObjectId(index as i32))
        .ok_or("Expected Engine.PlayerReplicationInfo:PlayerName to be present in replay")?;
    Ok(id)
}

fn main() -> Result<(), Box<dyn error::Error>> {
    let mut data = Vec::new();
    io::stdin().read_to_end(&mut data)?;

    let replay = ParserBuilder::new(&data[..])
        .on_error_check_crc()
        .ignore_network_data_on_error()
        .parse()?;

    let stats_prop = replay
        .properties
        .iter()
        .find(|(prop, _)| *prop == "PlayerStats");

    if let Some((_, stats)) = stats_prop {
        println!("Names in the header data:");
        let stats = match stats {
            HeaderProp::Array(arr) => arr,
            _ => return Err("expected player stats to be an array")?,
        };

        let header_names = names_in_header(&stats);
        for name in header_names {
            println!("{}", name);
        }
    } else {
        println!("No player names found in the header");
    }

    if let Some(network) = replay.network_frames.as_ref() {
        println!("Names in the network data:");
        let name_attribute_id = player_name_object_id(&replay)?;
        let names = names_in_network(&network.frames, name_attribute_id);
        for name in names {
            println!("{}", name);
        }
    } else {
        println!("No player names found in the header as network data couldn't be decoded")
    }

    Ok(())
}
<|endoftext|>