<commit_before>use cursive::traits::*;
use cursive::views;

use std::io::Read as _;
use std::io::Write as _;
use std::sync::{Arc, Mutex};

// This example builds a simple TCP server with some parameters and some output.
// It then builds a TUI to control the parameters and display the output.

fn main() {
    let mut siv = cursive::Cursive::default();

    // Build a shared model
    let model = Arc::new(Mutex::new(Model {
        offset: 0,
        logs: Vec::new(),
        cb_sink: siv.cb_sink().clone(),
    }));

    // Start the TCP server in a thread
    start_server(Arc::clone(&model));

    // Build the UI from the model
    siv.add_layer(
        views::Dialog::around(build_ui(Arc::clone(&model)))
            .button("Quit", |s| s.quit()),
    );

    siv.run();
}

struct Model {
    offset: u8,
    logs: Vec<(u8, u8)>,
    cb_sink: cursive::CbSink,
}

fn start_server(model: Arc<Mutex<Model>>) {
    std::thread::spawn(move || {
        if let Err(err) = serve(Arc::clone(&model)) {
            model
                .lock()
                .unwrap()
                .cb_sink
                .send(Box::new(move |s: &mut cursive::Cursive| {
                    s.add_layer(
                        views::Dialog::text(&format!("{:?}", err))
                            .title("Error in TCP server")
                            .button("Quit", |s| s.quit()),
                    );
                }))
                .unwrap();
        }
    });
}

fn serve(model: Arc<Mutex<Model>>) -> std::io::Result<()> {
    let listener = std::net::TcpListener::bind("localhost:1234")?;

    for stream in listener.incoming() {
        let stream = stream?;

        for byte in (&stream).bytes() {
            let byte = byte?;
            let mut model = model.lock().unwrap();
            let response = byte.wrapping_add(model.offset);
            model.logs.push((byte, response));
            (&stream).write_all(&[response])?;
            model
                .cb_sink
                .send(Box::new(cursive::Cursive::noop))
                .unwrap();
        }
    }

    Ok(())
}

fn readable_char(byte: u8) -> char {
    if byte.is_ascii_control() {
        '�'
    } else {
        byte as char
    }
}

fn build_log_viewer(model: Arc<Mutex<Model>>) -> impl cursive::view::View {
    views::Canvas::new(model)
        .with_draw(|model, printer| {
            let model = model.lock().unwrap();
            for (i, &(byte, answer)) in model.logs.iter().enumerate() {
                printer.print(
                    (0, i),
                    &format!(
                        "{:3} '{}' -> {:3} '{}'",
                        byte,
                        readable_char(byte),
                        answer,
                        readable_char(answer),
                    ),
                );
            }
        })
        .with_required_size(|model, _req| {
            let model = model.lock().unwrap();
            cursive::Vec2::new(10, model.logs.len())
        })
}

fn build_selector(model: Arc<Mutex<Model>>) -> impl cursive::view::View {
    views::LinearLayout::horizontal()
        .child(
            views::EditView::new()
                .content("0")
                .with_id("edit")
                .min_width(5),
        )
        .child(views::DummyView.fixed_width(1))
        .child(views::Button::new("Update", move |s| {
            if let Some(n) = s
                .call_on_id("edit", |edit: &mut views::EditView| {
                    edit.get_content()
                })
                .and_then(|content| content.parse().ok())
            {
                model.lock().unwrap().offset = n;
            } else {
                s.add_layer(views::Dialog::info(
                    "Could not parse offset as u8",
                ));
            }
        }))
        .child(views::DummyView.fixed_width(1))
        .child(views::Button::new("Test", |s| {
            if let Err(err) = test_server() {
                s.add_layer(
                    views::Dialog::info(&format!("{:?}", err))
                        .title("Error running test."),
                );
            }
        }))
}

fn test_server() -> std::io::Result<()> {
    let mut stream = std::net::TcpStream::connect("localhost:1234")?;
    for &byte in &[1, 2, 3, b'a', b'c', b'd'] {
        let mut buf = [0];
        stream.write_all(&[byte])?;
        stream.read_exact(&mut buf)?;
    }
    Ok(())
}

fn build_ui(model: Arc<Mutex<Model>>) -> impl cursive::view::View {
    views::LinearLayout::vertical()
        .child(build_selector(Arc::clone(&model)))
        .child(build_log_viewer(Arc::clone(&model)))
}
<commit_msg>Fix compilation on stable<commit_after>use cursive::traits::*;
use cursive::views;

use std::io::Read as _;
use std::io::Write as _;
use std::sync::{Arc, Mutex};

// This example builds a simple TCP server with some parameters and some output.
// It then builds a TUI to control the parameters and display the output.

fn main() {
    let mut siv = cursive::Cursive::default();

    // Build a shared model
    let model = Arc::new(Mutex::new(Model {
        offset: 0,
        logs: Vec::new(),
        cb_sink: siv.cb_sink().clone(),
    }));

    // Start the TCP server in a thread
    start_server(Arc::clone(&model));

    // Build the UI from the model
    siv.add_layer(
        views::Dialog::around(build_ui(Arc::clone(&model)))
            .button("Quit", |s| s.quit()),
    );

    siv.run();
}

struct Model {
    offset: u8,
    logs: Vec<(u8, u8)>,
    cb_sink: cursive::CbSink,
}

fn start_server(model: Arc<Mutex<Model>>) {
    std::thread::spawn(move || {
        if let Err(err) = serve(Arc::clone(&model)) {
            model
                .lock()
                .unwrap()
                .cb_sink
                .send(Box::new(move |s: &mut cursive::Cursive| {
                    s.add_layer(
                        views::Dialog::text(format!("{:?}", err))
                            .title("Error in TCP server")
                            .button("Quit", |s| s.quit()),
                    );
                }))
                .unwrap();
        }
    });
}

fn serve(model: Arc<Mutex<Model>>) -> std::io::Result<()> {
    let listener = std::net::TcpListener::bind("localhost:1234")?;

    for stream in listener.incoming() {
        let stream = stream?;

        for byte in (&stream).bytes() {
            let byte = byte?;
            let mut model = model.lock().unwrap();
            let response = byte.wrapping_add(model.offset);
            model.logs.push((byte, response));
            (&stream).write_all(&[response])?;
            model
                .cb_sink
                .send(Box::new(cursive::Cursive::noop))
                .unwrap();
        }
    }

    Ok(())
}

fn readable_char(byte: u8) -> char {
    if byte.is_ascii_control() {
        '�'
    } else {
        byte as char
    }
}

fn build_log_viewer(model: Arc<Mutex<Model>>) -> impl cursive::view::View {
    views::Canvas::new(model)
        .with_draw(|model, printer| {
            let model = model.lock().unwrap();
            for (i, &(byte, answer)) in model.logs.iter().enumerate() {
                printer.print(
                    (0, i),
                    &format!(
                        "{:3} '{}' -> {:3} '{}'",
                        byte,
                        readable_char(byte),
                        answer,
                        readable_char(answer),
                    ),
                );
            }
        })
        .with_required_size(|model, _req| {
            let model = model.lock().unwrap();
            cursive::Vec2::new(10, model.logs.len())
        })
}

fn build_selector(model: Arc<Mutex<Model>>) -> impl cursive::view::View {
    views::LinearLayout::horizontal()
        .child(
            views::EditView::new()
                .content("0")
                .with_id("edit")
                .min_width(5),
        )
        .child(views::DummyView.fixed_width(1))
        .child(views::Button::new("Update", move |s| {
            if let Some(n) = s
                .call_on_id("edit", |edit: &mut views::EditView| {
                    edit.get_content()
                })
                .and_then(|content| content.parse().ok())
            {
                model.lock().unwrap().offset = n;
            } else {
                s.add_layer(views::Dialog::info(
                    "Could not parse offset as u8",
                ));
            }
        }))
        .child(views::DummyView.fixed_width(1))
        .child(views::Button::new("Test", |s| {
            if let Err(err) = test_server() {
                s.add_layer(
                    views::Dialog::info(format!("{:?}", err))
                        .title("Error running test."),
                );
            }
        }))
}

fn test_server() -> std::io::Result<()> {
    let mut stream = std::net::TcpStream::connect("localhost:1234")?;
    for &byte in &[1, 2, 3, b'a', b'c', b'd'] {
        let mut buf = [0];
        stream.write_all(&[byte])?;
        stream.read_exact(&mut buf)?;
    }
    Ok(())
}

fn build_ui(model: Arc<Mutex<Model>>) -> impl cursive::view::View {
    views::LinearLayout::vertical()
        .child(build_selector(Arc::clone(&model)))
        .child(build_log_viewer(Arc::clone(&model)))
}
<|endoftext|>


<commit_before>// Copyright 2018 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.

//! Mining plugin manager, using the cuckoo-miner crate to provide
//! a mining worker implementation
//!

use chrono::prelude::Utc;
use chrono::Duration;
use std::io;
use std::net::{SocketAddr, ToSocketAddrs};
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::thread;
use std::time;

use api;

use p2p;
use pool::DandelionConfig;
use util::LOGGER;

// DNS Seeds with contact email associated
const DNS_SEEDS: &'static [&'static str] = &[
	"t3.seed.grin-tech.org",    // igno.peverell@protonmail.com
	"seed.grin.lesceller.com",  // q.lesceller@gmail.com
	"t3.grin-seed.prokapi.com", // info@prokapi.com
];

pub fn connect_and_monitor(
	p2p_server: Arc<p2p::Server>,
	capabilities: p2p::Capabilities,
	dandelion_config: DandelionConfig,
	seed_list: Box<Fn() -> Vec<SocketAddr> + Send>,
	preferred_peers: Option<Vec<SocketAddr>>,
	stop: Arc<AtomicBool>,
) {
	let _ = thread::Builder::new()
		.name("seed".to_string())
		.spawn(move || {
			let peers = p2p_server.peers.clone();

			// open a channel with a listener that connects every peer address sent below
			// max peer count
			let (tx, rx) = mpsc::channel();

			// check seeds first
			connect_to_seeds_and_preferred_peers(
				peers.clone(),
				tx.clone(),
				seed_list,
				preferred_peers.clone(),
			);

			let mut prev = Utc::now() - Duration::seconds(60);
			let mut start_attempt = 0;
			let start_wait_base: i64 = 2;
			loop {
				let current_time = Utc::now();

				// make several attempts to get peers as quick as possible with
				// exponential backoff
				if (peers.peer_count() < p2p_server.config.peer_min_preferred_count()
					&& current_time - prev > Duration::seconds(start_wait_base.pow(start_attempt)))
					|| current_time - prev > Duration::seconds(20)
				{
					// try to connect to any address sent to the channel
					listen_for_addrs(peers.clone(), p2p_server.clone(), capabilities, &rx);

					// monitor additional peers if we need to add more
					monitor_peers(
						peers.clone(),
						p2p_server.config.clone(),
						capabilities,
						tx.clone(),
						preferred_peers.clone(),
					);

					update_dandelion_relay(peers.clone(), dandelion_config.clone());

					prev = current_time;
					if start_attempt < 6 {
						start_attempt += 1;
					}
				}

				thread::sleep(time::Duration::from_secs(1));

				if stop.load(Ordering::Relaxed) {
					break;
				}
			}
		});
}

fn monitor_peers(
	peers: Arc<p2p::Peers>,
	config: p2p::P2PConfig,
	capabilities: p2p::Capabilities,
	tx: mpsc::Sender<SocketAddr>,
	preferred_peers_list: Option<Vec<SocketAddr>>,
) {
	// regularly check if we need to acquire more peers  and if so, gets
	// them from db
	let total_count = peers.all_peers().len();
	let mut healthy_count = 0;
	let mut banned_count = 0;
	let mut defunct_count = 0;
	for x in peers.all_peers() {
		match x.flags {
			p2p::State::Banned => {
				let interval = Utc::now().timestamp() - x.last_banned;
				// Unban peer
				if interval >= config.ban_window() {
					peers.unban_peer(&x.addr);
					debug!(
						LOGGER,
						"monitor_peers: unbanned {} after {} seconds", x.addr, interval
					);
				} else {
					banned_count += 1;
				}
			}
			p2p::State::Healthy => healthy_count += 1,
			p2p::State::Defunct => defunct_count += 1,
		}
	}

	debug!(
		LOGGER,
		"monitor_peers: on {}:{}, {} connected ({} most_work). \
		 all {} = {} healthy + {} banned + {} defunct",
		config.host,
		config.port,
		peers.peer_count(),
		peers.most_work_peers().len(),
		total_count,
		healthy_count,
		banned_count,
		defunct_count,
	);

	// maintenance step first, clean up p2p server peers
	peers.clean_peers(config.peer_max_count() as usize);

	// not enough peers, getting more from db
	if peers.peer_count() >= config.peer_min_preferred_count() {
		return;
	}

	// loop over connected peers
	// ask them for their list of peers
	let mut connected_peers: Vec<SocketAddr> = vec![];
	for p in peers.connected_peers() {
		if let Ok(p) = p.try_read() {
			debug!(
				LOGGER,
				"monitor_peers: {}:{} ask {} for more peers", config.host, config.port, p.info.addr,
			);
			let _ = p.send_peer_request(capabilities);
			connected_peers.push(p.info.addr)
		} else {
			warn!(LOGGER, "monitor_peers: failed to get read lock on peer");
		}
	}

	// Attempt to connect to preferred peers if there is some
	match preferred_peers_list {
		Some(preferred_peers) => {
			for mut p in preferred_peers {
				if !connected_peers.is_empty() {
					if !connected_peers.contains(&p) {
						tx.send(p).unwrap();
					}
				} else {
					tx.send(p).unwrap();
				}
			}
		}
		None => debug!(LOGGER, "monitor_peers: no preferred peers"),
	}

	// find some peers from our db
	// and queue them up for a connection attempt
	let new_peers = peers.find_peers(
		p2p::State::Healthy,
		p2p::Capabilities::UNKNOWN,
		config.peer_max_count() as usize,
	);
	for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
		debug!(
			LOGGER,
			"monitor_peers: on {}:{}, queue to soon try {}", config.host, config.port, p.addr,
		);
		tx.send(p.addr).unwrap();
	}
}

fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionConfig) {
	// Dandelion Relay Updater
	let dandelion_relay = peers.get_dandelion_relay();
	if dandelion_relay.is_empty() {
		debug!(LOGGER, "monitor_peers: no dandelion relay updating");
		peers.update_dandelion_relay();
	} else {
		for last_added in dandelion_relay.keys() {
			let dandelion_interval = Utc::now().timestamp() - last_added;
			if dandelion_interval >= dandelion_config.relay_secs.unwrap() as i64 {
				debug!(LOGGER, "monitor_peers: updating expired dandelion relay");
				peers.update_dandelion_relay();
			}
		}
	}
}

// Check if we have any pre-existing peer in db. If so, start with those,
// otherwise use the seeds provided.
fn connect_to_seeds_and_preferred_peers(
	peers: Arc<p2p::Peers>,
	tx: mpsc::Sender<SocketAddr>,
	seed_list: Box<Fn() -> Vec<SocketAddr>>,
	peers_preferred_list: Option<Vec<SocketAddr>>,
) {
	// check if we have some peers in db
	let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::FULL_HIST, 100);

	// if so, get their addresses, otherwise use our seeds
	let mut peer_addrs = if peers.len() > 3 {
		peers.iter().map(|p| p.addr).collect::<Vec<_>>()
	} else {
		seed_list()
	};

	// If we have preferred peers add them to the connection
	match peers_preferred_list {
		Some(mut peers_preferred) => peer_addrs.append(&mut peers_preferred),
		None => debug!(LOGGER, "No preferred peers"),
	};

	if peer_addrs.len() == 0 {
		warn!(LOGGER, "No seeds were retrieved.");
	}

	// connect to this first set of addresses
	for addr in peer_addrs {
		tx.send(addr).unwrap();
	}
}

/// Regularly poll a channel receiver for new addresses 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(
	peers: Arc<p2p::Peers>,
	p2p: Arc<p2p::Server>,
	capab: p2p::Capabilities,
	rx: &mpsc::Receiver<SocketAddr>,
) {
	let pc = peers.peer_count();
	for addr in rx.try_iter() {
		if pc < p2p.config.peer_max_count() {
			let peers_c = peers.clone();
			let p2p_c = p2p.clone();
			let _ = thread::Builder::new()
				.name("peer_connect".to_string())
				.spawn(move || {
					let mut connect_retry_count = 0;
					loop {
						let connect_peer = p2p_c.connect(&addr);
						match connect_peer {
							Ok(p) => {
								trace!(
									LOGGER,
									"connect_and_req: on {}:{}. connect to {} ok. attempting send_peer_request",
									p2p_c.config.host,
									p2p_c.config.port,
									addr
								);
								if let Ok(p) = p.try_read() {
									let _ = p.send_peer_request(capab);
								}
								let _ = peers_c.update_state(addr, p2p::State::Healthy);
								break;
							}
							Err(e) => {
								debug!(
									LOGGER,
									"connect_and_req: on {}:{}. connect to {} is Defunct. {:?}",
									p2p_c.config.host,
									p2p_c.config.port,
									addr,
									e,
								);
								let _ = peers_c.update_state(addr, p2p::State::Defunct);

								// don't retry if connection refused or PeerWithSelf
								match e {
									p2p::Error::Connection(io_err) => {
										if io::ErrorKind::ConnectionRefused == io_err.kind() {
											break;
										}
									}
									p2p::Error::PeerWithSelf => break,
									_ => (),
								}
							}
						}

						// retry for 3 times
						thread::sleep(time::Duration::from_secs(1));
						connect_retry_count += 1;
						if connect_retry_count >= 3 {
							break;
						}
						debug!(
							LOGGER,
							"connect_and_req: on {}:{}. connect to {} retrying {}",
							p2p_c.config.host,
							p2p_c.config.port,
							addr,
							connect_retry_count,
						);
					}
				});
		}
	}
}

pub fn dns_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let mut addresses: Vec<SocketAddr> = vec![];
		for dns_seed in DNS_SEEDS {
			let temp_addresses = addresses.clone();
			debug!(LOGGER, "Retrieving seed nodes from dns {}", dns_seed);
			match (dns_seed.to_owned(), 0).to_socket_addrs() {
				Ok(addrs) => addresses.append(
					&mut (addrs
						.map(|mut addr| {
							addr.set_port(13414);
							addr
						})
						.filter(|addr| !temp_addresses.contains(addr))
						.collect()),
				),
				Err(e) => debug!(
					LOGGER,
					"Failed to resolve seed {:?} got error {:?}", dns_seed, e
				),
			}
		}
		debug!(LOGGER, "Retrieved seed addresses: {:?}", addresses);
		addresses
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>) -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(move || {
		addrs_str
			.iter()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>()
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn preferred_peers(addrs_str: Vec<String>) -> Option<Vec<SocketAddr>> {
	if addrs_str.is_empty() {
		None
	} else {
		Some(
			addrs_str
				.iter()
				.map(|s| s.parse().unwrap())
				.collect::<Vec<_>>(),
		)
	}
}
<commit_msg>Refactoring and cleanup on seed (#1513)<commit_after>// Copyright 2018 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.

//! Mining plugin manager, using the cuckoo-miner crate to provide
//! a mining worker implementation
//!

use chrono::prelude::Utc;
use chrono::{Duration, MIN_DATE};
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::{cmp, io, str, thread, time};

use p2p;
use pool::DandelionConfig;
use util::LOGGER;

// DNS Seeds with contact email associated
const DNS_SEEDS: &'static [&'static str] = &[
	"t3.seed.grin-tech.org",    // igno.peverell@protonmail.com
	"seed.grin.lesceller.com",  // q.lesceller@gmail.com
	"t3.grin-seed.prokapi.com", // info@prokapi.com
];

pub fn connect_and_monitor(
	p2p_server: Arc<p2p::Server>,
	capabilities: p2p::Capabilities,
	dandelion_config: DandelionConfig,
	seed_list: Box<Fn() -> Vec<SocketAddr> + Send>,
	preferred_peers: Option<Vec<SocketAddr>>,
	stop: Arc<AtomicBool>,
) {
	let _ = thread::Builder::new()
		.name("seed".to_string())
		.spawn(move || {
			let peers = p2p_server.peers.clone();

			// open a channel with a listener that connects every peer address sent below
			// max peer count
			let (tx, rx) = mpsc::channel();

			// check seeds first
			connect_to_seeds_and_preferred_peers(
				peers.clone(),
				tx.clone(),
				seed_list,
				preferred_peers.clone(),
			);

			let mut prev = MIN_DATE.and_hms(0, 0, 0);
			let mut start_attempt = 0;

			while !stop.load(Ordering::Relaxed) {
				// make several attempts to get peers as quick as possible
				// with exponential backoff
				if Utc::now() - prev > Duration::seconds(cmp::min(20, 1 << start_attempt)) {
					// try to connect to any address sent to the channel
					listen_for_addrs(peers.clone(), p2p_server.clone(), capabilities, &rx);

					// monitor additional peers if we need to add more
					monitor_peers(
						peers.clone(),
						p2p_server.config.clone(),
						capabilities,
						tx.clone(),
						preferred_peers.clone(),
					);

					update_dandelion_relay(peers.clone(), dandelion_config.clone());

					prev = Utc::now();
					start_attempt = cmp::min(6, start_attempt + 1);
				}

				thread::sleep(time::Duration::from_secs(1));
			}
		});
}

fn monitor_peers(
	peers: Arc<p2p::Peers>,
	config: p2p::P2PConfig,
	capabilities: p2p::Capabilities,
	tx: mpsc::Sender<SocketAddr>,
	preferred_peers_list: Option<Vec<SocketAddr>>,
) {
	// regularly check if we need to acquire more peers  and if so, gets
	// them from db
	let total_count = peers.all_peers().len();
	let mut healthy_count = 0;
	let mut banned_count = 0;
	let mut defunct_count = 0;
	for x in peers.all_peers() {
		match x.flags {
			p2p::State::Banned => {
				let interval = Utc::now().timestamp() - x.last_banned;
				// Unban peer
				if interval >= config.ban_window() {
					peers.unban_peer(&x.addr);
					debug!(
						LOGGER,
						"monitor_peers: unbanned {} after {} seconds", x.addr, interval
					);
				} else {
					banned_count += 1;
				}
			}
			p2p::State::Healthy => healthy_count += 1,
			p2p::State::Defunct => defunct_count += 1,
		}
	}

	debug!(
		LOGGER,
		"monitor_peers: on {}:{}, {} connected ({} most_work). \
		 all {} = {} healthy + {} banned + {} defunct",
		config.host,
		config.port,
		peers.peer_count(),
		peers.most_work_peers().len(),
		total_count,
		healthy_count,
		banned_count,
		defunct_count,
	);

	// maintenance step first, clean up p2p server peers
	peers.clean_peers(config.peer_max_count() as usize);

	// not enough peers, getting more from db
	if peers.peer_count() >= config.peer_min_preferred_count() {
		return;
	}

	// loop over connected peers
	// ask them for their list of peers
	let mut connected_peers: Vec<SocketAddr> = vec![];
	for p in peers.connected_peers() {
		if let Ok(p) = p.try_read() {
			debug!(
				LOGGER,
				"monitor_peers: {}:{} ask {} for more peers", config.host, config.port, p.info.addr,
			);
			let _ = p.send_peer_request(capabilities);
			connected_peers.push(p.info.addr)
		} else {
			warn!(LOGGER, "monitor_peers: failed to get read lock on peer");
		}
	}

	// Attempt to connect to preferred peers if there is some
	match preferred_peers_list {
		Some(preferred_peers) => {
			for mut p in preferred_peers {
				if !connected_peers.is_empty() {
					if !connected_peers.contains(&p) {
						tx.send(p).unwrap();
					}
				} else {
					tx.send(p).unwrap();
				}
			}
		}
		None => debug!(LOGGER, "monitor_peers: no preferred peers"),
	}

	// find some peers from our db
	// and queue them up for a connection attempt
	let new_peers = peers.find_peers(
		p2p::State::Healthy,
		p2p::Capabilities::UNKNOWN,
		config.peer_max_count() as usize,
	);
	for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
		debug!(
			LOGGER,
			"monitor_peers: on {}:{}, queue to soon try {}", config.host, config.port, p.addr,
		);
		tx.send(p.addr).unwrap();
	}
}

fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionConfig) {
	// Dandelion Relay Updater
	let dandelion_relay = peers.get_dandelion_relay();
	if dandelion_relay.is_empty() {
		debug!(LOGGER, "monitor_peers: no dandelion relay updating");
		peers.update_dandelion_relay();
	} else {
		for last_added in dandelion_relay.keys() {
			let dandelion_interval = Utc::now().timestamp() - last_added;
			if dandelion_interval >= dandelion_config.relay_secs.unwrap() as i64 {
				debug!(LOGGER, "monitor_peers: updating expired dandelion relay");
				peers.update_dandelion_relay();
			}
		}
	}
}

// Check if we have any pre-existing peer in db. If so, start with those,
// otherwise use the seeds provided.
fn connect_to_seeds_and_preferred_peers(
	peers: Arc<p2p::Peers>,
	tx: mpsc::Sender<SocketAddr>,
	seed_list: Box<Fn() -> Vec<SocketAddr>>,
	peers_preferred_list: Option<Vec<SocketAddr>>,
) {
	// check if we have some peers in db
	let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::FULL_HIST, 100);

	// if so, get their addresses, otherwise use our seeds
	let mut peer_addrs = if peers.len() > 3 {
		peers.iter().map(|p| p.addr).collect::<Vec<_>>()
	} else {
		seed_list()
	};

	// If we have preferred peers add them to the connection
	match peers_preferred_list {
		Some(mut peers_preferred) => peer_addrs.append(&mut peers_preferred),
		None => debug!(LOGGER, "No preferred peers"),
	};

	if peer_addrs.len() == 0 {
		warn!(LOGGER, "No seeds were retrieved.");
	}

	// connect to this first set of addresses
	for addr in peer_addrs {
		tx.send(addr).unwrap();
	}
}

/// Regularly poll a channel receiver for new addresses 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(
	peers: Arc<p2p::Peers>,
	p2p: Arc<p2p::Server>,
	capab: p2p::Capabilities,
	rx: &mpsc::Receiver<SocketAddr>,
) {
	if peers.peer_count() >= p2p.config.peer_max_count() {
		// clean the rx messages to avoid accumulating
		for _ in rx.try_iter() {}
		return;
	}

	for addr in rx.try_iter() {
		let peers_c = peers.clone();
		let p2p_c = p2p.clone();
		let _ = thread::Builder::new()
			.name("peer_connect".to_string())
			.spawn(move || {
				// connect and retry on fail, but for 3 times at most
				for _ in 0..3 {
					match p2p_c.connect(&addr) {
						Ok(p) => {
							if let Ok(p) = p.try_read() {
								let _ = p.send_peer_request(capab);
							}
							let _ = peers_c.update_state(addr, p2p::State::Healthy);
							break;
						}
						Err(e) => {
							let _ = peers_c.update_state(addr, p2p::State::Defunct);

							// don't retry if connection refused or PeerWithSelf
							match e {
								p2p::Error::Connection(io_err) => {
									if io::ErrorKind::ConnectionRefused == io_err.kind() {
										break;
									}
								}
								p2p::Error::PeerWithSelf => break,
								_ => (), // allow to retry on any other error
							}
						}
					}

					thread::sleep(time::Duration::from_secs(1));
				}
			});
	}
}

pub fn dns_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(|| {
		let mut addresses: Vec<SocketAddr> = vec![];
		for dns_seed in DNS_SEEDS {
			let temp_addresses = addresses.clone();
			debug!(LOGGER, "Retrieving seed nodes from dns {}", dns_seed);
			match (dns_seed.to_owned(), 0).to_socket_addrs() {
				Ok(addrs) => addresses.append(
					&mut (addrs
						.map(|mut addr| {
							addr.set_port(13414);
							addr
						})
						.filter(|addr| !temp_addresses.contains(addr))
						.collect()),
				),
				Err(e) => debug!(
					LOGGER,
					"Failed to resolve seed {:?} got error {:?}", dns_seed, e
				),
			}
		}
		debug!(LOGGER, "Retrieved seed addresses: {:?}", addresses);
		addresses
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn predefined_seeds(addrs_str: Vec<String>) -> Box<Fn() -> Vec<SocketAddr> + Send> {
	Box::new(move || {
		addrs_str
			.iter()
			.map(|s| s.parse().unwrap())
			.collect::<Vec<_>>()
	})
}

/// Convenience function when the seed list is immediately known. Mostly used
/// for tests.
pub fn preferred_peers(addrs_str: Vec<String>) -> Option<Vec<SocketAddr>> {
	if addrs_str.is_empty() {
		None
	} else {
		Some(
			addrs_str
				.iter()
				.map(|s| s.parse().unwrap())
				.collect::<Vec<_>>(),
		)
	}
}
<|endoftext|>


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

// ignore

pub struct Inner<T> {
    field: T,
}

unsafe impl<T> Send for Inner<T>
where
    T: Copy + Send,
{
}

// @has no_redundancy/struct.Outer.html
// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl<T> Send for \
// Outer<T> where T: Copy + Send"
pub struct Outer<T> {
    inner_field: Inner<T>,
}
<commit_msg>Comment out entire test.<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/* This test is flakey. Commented it out until #49123 is fixed

pub struct Inner<T> {
    field: T,
}

unsafe impl<T> Send for Inner<T>
where
    T: Copy + Send,
{
}

// @has no_redundancy/struct.Outer.html
// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]/*/code' "impl<T> Send for \
// Outer<T> where T: Copy + Send"
pub struct Outer<T> {
    inner_field: Inner<T>,
}

*/
<|endoftext|>


<commit_before>#[macro_use]
extern crate ispc;
extern crate image;
extern crate rand;

use std::ptr;
use std::time::Instant;

use rand::Rng;

use camera::Camera;
use vol::Volume;
use vec3::{Vec3f, Vec3i};

mod raw;
mod vol;
mod vec3;
mod camera;

ispc_module!(ddvol);

pub type ISPCHandle = *mut ::std::os::raw::c_void;
/// Create a new null ISPCHandle
pub fn empty_handle() -> ISPCHandle {
    ptr::null::<*mut ::std::os::raw::c_void>() as ISPCHandle
}

fn main() {
    let width = 512;
    let height = 512;
    let camera = Camera::new(Vec3f::new(1.5, 0.5, 2.0), Vec3f::new(0.5, 0.5, 0.5),
                             Vec3f::new(0.0, 1.0, 0.0), 60.0, width as i32, height as i32);
    let volume = Volume::new(Vec3i::broadcast(2));
    let volume_data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
    volume.set_region(&volume_data[..], Vec3i::broadcast(0), Vec3i::broadcast(2));
    let mut framebuffer = vec![0.0; width * height * 3];
    let mut srgb_img_buf = vec![0u8; width * height * 3];
    let mut rng = rand::thread_rng();
    // We need a random seed for each scanline of the image
    let scanline_seeds: Vec<_> = rng.gen_iter::<i32>().take(height).collect();
    unsafe {
        let start = Instant::now();
        ddvol::render(camera.ispc_equiv(), volume.ispc_equiv(), scanline_seeds.as_ptr(),
                      width as i32, height as i32, framebuffer.as_mut_ptr());
        let elapsed = start.elapsed();
        println!("Rendering took {}s", elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9);
        ddvol::framebuffer_to_srgb(framebuffer.as_ptr(), srgb_img_buf.as_mut_ptr(), width as i32, height as i32);
    }
    match image::save_buffer("ddvol.png", &srgb_img_buf[..], width as u32, height as u32, image::RGB(8)) {
        Ok(_) => println!("Rendered image saved to ddvol.png"),
        Err(e) => panic!("Error saving image: {}", e),
    };
}

<commit_msg>Testing a simpler volume, maybe the marching or sampling is wrong?<commit_after>#[macro_use]
extern crate ispc;
extern crate image;
extern crate rand;

use std::ptr;
use std::time::Instant;

use rand::Rng;

use camera::Camera;
use vol::Volume;
use vec3::{Vec3f, Vec3i};

mod raw;
mod vol;
mod vec3;
mod camera;

ispc_module!(ddvol);

pub type ISPCHandle = *mut ::std::os::raw::c_void;
/// Create a new null ISPCHandle
pub fn empty_handle() -> ISPCHandle {
    ptr::null::<*mut ::std::os::raw::c_void>() as ISPCHandle
}

fn main() {
    let width = 512;
    let height = 512;
    let camera = Camera::new(Vec3f::new(2.0, 0.5, 2.0), Vec3f::new(0.5, 0.5, 0.5),
                             Vec3f::new(0.0, 1.0, 0.0), 60.0, width as i32, height as i32);
    let volume = Volume::new(Vec3i::new(2, 1, 1));
    let volume_data = [0.0, 1.0];//, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
    volume.set_region(&volume_data[..], Vec3i::broadcast(0), Vec3i::new(2, 1, 1));
    let mut framebuffer = vec![0.0; width * height * 3];
    let mut srgb_img_buf = vec![0u8; width * height * 3];
    let mut rng = rand::thread_rng();
    // We need a random seed for each scanline of the image
    let scanline_seeds: Vec<_> = rng.gen_iter::<i32>().take(height).collect();
    unsafe {
        let start = Instant::now();
        ddvol::render(camera.ispc_equiv(), volume.ispc_equiv(), scanline_seeds.as_ptr(),
                      width as i32, height as i32, framebuffer.as_mut_ptr());
        let elapsed = start.elapsed();
        println!("Rendering took {}s", elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9);
        ddvol::framebuffer_to_srgb(framebuffer.as_ptr(), srgb_img_buf.as_mut_ptr(), width as i32, height as i32);
    }
    match image::save_buffer("ddvol.png", &srgb_img_buf[..], width as u32, height as u32, image::RGB(8)) {
        Ok(_) => println!("Rendered image saved to ddvol.png"),
        Err(e) => panic!("Error saving image: {}", e),
    };
}

<|endoftext|>


<commit_before>use diesel;
use diesel::prelude::*;
use validator::Validate;
use rocket_contrib::{JSON, SerdeError};

use helpers::db::DB;
use validation::user::{UserSerializer, UserSettingsSerializer};
use responses::{APIResponse, ok, created, conflict, bad_request, forbidden, unauthorized};

use models::user::{User, ChangedUser};
use schema::users::dsl::*;

#[get("/info")]
pub fn info(current_user: User) -> APIResponse {
    ok().data(json!(current_user))
}

/// Endpoint for registering a new User.
///
/// Needs a unique nickname, unique email and password.
#[post("/register", data = "<user_data>", format = "application/json")]
pub fn register(user_data: Result<JSON<UserSerializer>, SerdeError>, db: DB) -> APIResponse {

    match user_data {
        // Return specific error if invalid JSON has been sent.
        Err(error) => return bad_request().message(format!("{}", error).as_str()),
        Ok(data) => {
            let validation = data.validate();
            match validation {
                Err(error) => {
                    let hashmap = error.inner();
                    if hashmap.contains_key("email") {
                        return bad_request().message("Invalid email provided");
                    }
                    if hashmap.contains_key("nickname") {
                        return bad_request().message("Nickname length has to be
                                                     between 1 and 120 characters.");
                    }
                }
                Ok(_) => (),
            }

            // Check for existing user email
            let results = users
                .filter(email.eq(data.email.clone()))
                .first::<User>(&*db);
            if results.is_ok() {
                return conflict().message("Nickname already taken.");
            }
            // Create new password hash
            let new_password_hash = User::make_password_hash(data.password.as_str());

            // Create new user to get uuid for pod
            let user = User::new_user(data.nickname.clone(),
                                      data.email.clone(),
                                      new_password_hash,
                                      &db);

            return created().message("User created.").data(json!(&user));
        }
    }
}

#[post("/settings", data = "<user_data>", format = "application/json")]
pub fn settings(current_user: User,
                user_data: Result<JSON<UserSettingsSerializer>, SerdeError>,
                db: DB)
                -> APIResponse {

    // Return specific error if invalid JSON has been sent.
    match user_data {
        Err(error) => return bad_request().message(format!("{}", error).as_str()),
        Ok(data) => {
            let mut new_password_hash: Option<Vec<u8>> = None;
            // Check if a new password is provided.
            // In case it is, we want the old password to verify the identity of the client.
            match data.new_password.as_ref() {
                Some(new_password) => {
                    match data.password.as_ref() {
                        Some(old_password) => {
                            if !current_user.verify_password(old_password.as_str()) {
                                return unauthorized().message("Incorrect password.");
                            }
                            new_password_hash = Some(User::make_password_hash(new_password
                                                                                .as_str()))
                        }
                        None => {
                            return forbidden().message("The current passwords needs to be \
                                    specified, if you want to change your password.")
                        }
                    }
                }
                None => (),
            };

            let changed_user = ChangedUser {
                nickname: data.nickname.clone(),
                email: data.email.clone(),
                password_hash: new_password_hash,
            };

            let user = diesel::update(users.filter(id.eq(current_user.id)))
                .set(&changed_user)
                .get_result::<User>(&*db)
                .expect("Failed to update user.");

            ok().message("User data changed.").data(json!(&user))
        }
    }
}
<commit_msg>Refactor user user<commit_after>use diesel;
use diesel::prelude::*;
use validator::Validate;
use rocket_contrib::{JSON, SerdeError};

use helpers::db::DB;
use validation::user::{UserSerializer, UserSettingsSerializer};
use responses::{APIResponse, ok, created, conflict, bad_request, forbidden, unauthorized};

use models::user::{User, ChangedUser};
use schema::users::dsl::*;

#[get("/info")]
pub fn info(current_user: User) -> APIResponse {
    ok().data(json!(current_user))
}

/// Endpoint for registering a new User.
///
/// Needs a unique nickname, unique email and password.
#[post("/register", data = "<user_data>", format = "application/json")]
pub fn register(user_data: Result<JSON<UserSerializer>, SerdeError>, db: DB) -> Result<APIResponse, APIResponse> {

    if let Err(error) = user_data {
        return Err(bad_request().message(format!("{}", error).as_str()));
    }
    let data = user_data.unwrap();
    data.validate().or(Err(bad_request().message("Invalid user data")))?;

    // Check for existing user email
    users
        .filter(email.eq(data.email.clone()))
        .first::<User>(&*db)
        .optional()
        .or(Err(conflict().message("Email already taken.")))?;

    // Check for existing user nickname
    users
        .filter(email.eq(data.email.clone()))
        .first::<User>(&*db)
        .optional()
        .or(Err(conflict().message("Nickname already taken.")))?;

    // Create new password hash
    let new_password_hash = User::make_password_hash(data.password.as_str());

    // Create new user to get uuid for pod
    let user = User::new_user(data.nickname.clone(),
                              data.email.clone(),
                              new_password_hash,
                              &db);

    Ok(created().message("User created.").data(json!(&user)))
}

#[post("/settings", data = "<user_data>", format = "application/json")]
pub fn settings(current_user: User,
                user_data: Result<JSON<UserSettingsSerializer>, SerdeError>,
                db: DB)
                -> Result<APIResponse, APIResponse> {

    if let Err(error) = user_data {
        return Err(bad_request().message(format!("{}", error).as_str()));
    }
    let data = user_data.unwrap();

    let mut new_password_hash: Option<Vec<u8>> = None;
    // Check if a new password is provided.
    // In case it is, we want the old password to verify the identity of the client.
    if let Some(ref new_password) = data.new_password {
        if let Some(ref old_password) = data.password {
            if !current_user.verify_password(old_password.as_str()) {
                return Err(unauthorized().message("Incorrect password."));
            }
            new_password_hash = Some(User::make_password_hash(new_password.as_str()));
        } else {
            return Err(forbidden().message("The current passwords needs to be \
                                            specified, if you want to change your password."));
        }
    }

    let changed_user = ChangedUser {
        nickname: data.nickname.clone(),
        email: data.email.clone(),
        password_hash: new_password_hash,
    };

    let user = diesel::update(users.filter(id.eq(current_user.id)))
        .set(&changed_user)
        .get_result::<User>(&*db)
        .expect("Failed to update user.");

    Ok(ok().message("User data changed.").data(json!(&user)))
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::io::BufReader;
use std::io::prelude::*;
use std::process::ChildStdin;
use std::process::Command;
use std::process::Stdio;
use std::sync::mpsc;
use std::thread;

use serde_json;
use serde_json::builder::*;
use serde_json::Value;

pub struct Core {
    stdin: ChildStdin,
    pub update_rx: mpsc::Receiver<Value>,
    rpc_rx: mpsc::Receiver<(u64,Value)>, // ! A simple piping works only for synchronous calls.
    rpc_index: u64,
    current_view: String,
    views: HashMap<String, String>,
}

impl Core {
    pub fn new(executable: &str, file: &str) -> Core {
        // spawn the core process
        let process = Command::new(executable)
                                .arg(file)
                                .stdout(Stdio::piped())
                                .stdin(Stdio::piped())
                                .stderr(Stdio::piped())
                                .env("RUST_BACKTRACE", "1")
                                .spawn()
                                .unwrap_or_else(|e| { panic!("failed to execute core: {}", e) });

        let (update_tx, update_rx) = mpsc::channel();
        let (rpc_tx, rpc_rx) = mpsc::channel();
        let stdout = process.stdout.unwrap();
        thread::spawn(move || {
            for line in BufReader::new(stdout).lines() {
                if let Ok(data) = serde_json::from_slice::<Value>(line.unwrap().as_bytes()) {
                    let req = data.as_object().unwrap();
                    info!("<<< {:?}", req);
                    if let (Some(id), Some(result)) = (req.get("id"), req.get("result")) {
                        rpc_tx.send((id.as_u64().unwrap(), result.clone())).unwrap();
                        info!(">>> {:?}", (id.as_u64().unwrap(), result.clone()));
                    } else if let (Some(method), Some(params)) = (req.get("method"), req.get("params")) {
                        let meth = method.as_str().unwrap();
                        if meth == "set_style" || meth == "scroll_to" || meth == "update" {
                            let request = ArrayBuilder::new().push(method.clone()).push(params.clone()).build();
                            update_tx.send(request).unwrap();
                        } else {
                            panic!("Unknown method {:?}.", method.as_str().unwrap());
                        }
                    } else {
                        panic!("Could not parse the core output: {:?}", req);
                    }
                }
            }
        });

        let stderr = process.stderr.unwrap();
        thread::spawn(move || {
            let buf_reader = BufReader::new(stderr);
            for line in buf_reader.lines() {
                if let Ok(line) = line {
                    error!("[core] {}", line);
                }
            }
        });

        let stdin = process.stdin.unwrap();

        let mut core = Core {
            stdin: stdin,
            update_rx: update_rx,
            rpc_rx: rpc_rx,
            rpc_index: 0,
            current_view: "".into(),
            views: HashMap::new(),
        };
        let view_id = core.new_view(Some(file.to_string())).as_str().unwrap().to_string();
        core.views.insert(view_id.clone(), file.to_string());
        core.current_view = view_id;
        core
    }

    /// Build and send a JSON RPC request, returning the associated request ID to pair it with
    /// the response
    fn request(&mut self, method: &str, params: Value) -> u64 {
        self.rpc_index += 1;
        let message = ObjectBuilder::new()
            .insert("id", self.rpc_index)
            .insert("method", method)
            .insert("params", params)
            .build();
        self.send(&message);
        self.rpc_index
    }

    /// Build and send a JSON RPC notification. No synchronous response is expected, so
    /// there is no ID.
    fn notify(&mut self, method: &str, params: Value) {
        let message = ObjectBuilder::new()
            .insert("method", method)
            .insert("params", params)
            .build();
        self.send(&message);
    }

    /// Serialize JSON object and send it to the server
    fn send(&mut self, message: &Value) {
        let mut str_msg = serde_json::ser::to_string(&message).unwrap();
        str_msg.push('\n');
        self.stdin.write(str_msg.as_bytes()).unwrap();
    }

    fn call_sync(&mut self, method: &str, params: Value) -> Value {
        let i = self.request(method, params);
        let (id,result) = self.rpc_rx.recv().unwrap();
        assert_eq!(i, id);
        result
    }

    fn call_edit(&mut self, method: &str, params: Option<Value>) {
        let obj = ObjectBuilder::new()
            .insert("method", method)
            .insert("view_id", &self.current_view)
            .insert("params", params.unwrap_or(ArrayBuilder::new().build()));
        let built_obj = obj.build();
        info!(">>> {:?}", built_obj);
        self.notify("edit", built_obj);
    }

    fn call_edit_sync(&mut self, method: &str, params: Option<Value>) -> Value{
        let obj = ObjectBuilder::new()
            .insert("method", method)
            .insert("view_id", &self.current_view)
            .insert("params", params.unwrap_or(ArrayBuilder::new().build()));
        self.call_sync("edit", obj.build())
    }

    pub fn new_view(&mut self, file_path: Option<String>) -> Value {
        let mut obj = ObjectBuilder::new();
        if file_path.is_some() {
            obj = obj.insert("file_path", file_path.unwrap());
        }
        self.call_sync("new_view", obj.build())
    }

    pub fn save(&mut self) {
        let save_params = ObjectBuilder::new()
            .insert("view_id", &self.current_view)
            .insert("file_path", self.views.get(&self.current_view).unwrap())
            .build();
        self.request("save", save_params);
    }

    pub fn open(&mut self, filename: &str) {
        self.call_edit("open", Some(ObjectBuilder::new().insert("filename", filename).build()));
    }

    pub fn left(&mut self) { self.call_edit("move_left", None); }
    pub fn left_sel(&mut self) { self.call_edit("move_left_and_modify_selection", None); }

    pub fn right(&mut self) { self.call_edit("move_right", None); }
    pub fn right_sel(&mut self) { self.call_edit("move_right_and_modify_selection", None); }

    pub fn up(&mut self) { self.call_edit("move_up", None); }
    pub fn up_sel(&mut self) { self.call_edit("move_up_and_modify_selection", None); }

    pub fn down(&mut self) { self.call_edit("move_down", None); }
    pub fn down_sel(&mut self) { self.call_edit("move_down_and_modify_selection", None); }

    pub fn del(&mut self) { self.call_edit("delete_backward", None); }

    pub fn page_up(&mut self) { self.call_edit("page_up", None); }
    pub fn page_up_sel(&mut self) { self.call_edit("page_up_and_modify_selection", None); }

    pub fn page_down(&mut self) { self.call_edit("page_down", None); }
    pub fn page_down_sel(&mut self) { self.call_edit("page_down_and_modify_selection", None); }

    pub fn insert_newline(&mut self) { self.call_edit("insert_newline", None); }

    pub fn f1(&mut self) { self.call_edit("debug_rewrap", None); }

    pub fn f2(&mut self) { self.call_edit("debug_test_fg_spans", None); }

    pub fn char(&mut self, ch: char) {
        self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", ch).build()));
    }

    pub fn scroll(&mut self, start: u64, end: u64) {
        self.call_edit("scroll", Some(ArrayBuilder::new().push(start).push(end).build()));
    }

    pub fn click(&mut self, line: u64, column: u64) {
        self.call_edit("click", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build()));
    }
    pub fn drag(&mut self, line: u64, column: u64) {
        self.call_edit("drag", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build()));
    }

    pub fn copy(&mut self) -> String {
        self.call_edit_sync("copy", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn cut(&mut self) -> String {
        self.call_edit_sync("cut", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn paste(&mut self, s: String) {
        self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", s).build()));
    }

    #[allow(dead_code)]
    pub fn test(&mut self) {
        self.render_lines(0, 10);
    }

    pub fn render_lines(&mut self, _start: u64, _end: u64) {
        unimplemented!()
        // self.rpc_index += 1;
        // println!("render_lines");
        // let value = ArrayBuilder::new()
        //     .push("rpc")
        //     .push_object(|builder| builder
        //         .insert("index", self.rpc_index)
        //         .insert_array("request", |builder| builder
        //             .push("render_lines")
        //             .push_object(|builder| builder
        //                 .insert("first_line", _start)
        //                 .insert("last_line", _end)
        //             )
        //         )
        //     ).unwrap();
        // self.write(value);
    }

    pub fn render_lines_sync(&mut self, _start: u64, _end: u64) -> Value {
        unimplemented!()
        // self.render_lines(_start, _end);
        // let value = self.rpc_rx.recv().unwrap();
        // let object = value.as_object().unwrap();
        // assert_eq!(self.rpc_index, object.get("index").unwrap().as_u64().unwrap());
        // object.get("result").unwrap().clone()
    }
}
<commit_msg>Changes Core to map view_id to actual View structs<commit_after>#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::io::BufReader;
use std::io::prelude::*;
use std::process::ChildStdin;
use std::process::Command;
use std::process::Stdio;
use std::sync::mpsc;
use std::thread;

use serde_json;
use serde_json::builder::*;
use serde_json::Value;

use view::View;

pub struct Core {
    stdin: ChildStdin,
    pub update_rx: mpsc::Receiver<Value>,
    rpc_rx: mpsc::Receiver<(u64,Value)>, // ! A simple piping works only for synchronous calls.
    rpc_index: u64,
    current_view: String,
    views: HashMap<String, View>,
}

impl Core {
    pub fn new(executable: &str, file: &str) -> Core {
        // spawn the core process
        let process = Command::new(executable)
                                .arg(file)
                                .stdout(Stdio::piped())
                                .stdin(Stdio::piped())
                                .stderr(Stdio::piped())
                                .env("RUST_BACKTRACE", "1")
                                .spawn()
                                .unwrap_or_else(|e| { panic!("failed to execute core: {}", e) });

        let (update_tx, update_rx) = mpsc::channel();
        let (rpc_tx, rpc_rx) = mpsc::channel();
        let stdout = process.stdout.unwrap();
        thread::spawn(move || {
            for line in BufReader::new(stdout).lines() {
                if let Ok(data) = serde_json::from_slice::<Value>(line.unwrap().as_bytes()) {
                    let req = data.as_object().unwrap();
                    info!("<<< {:?}", req);
                    if let (Some(id), Some(result)) = (req.get("id"), req.get("result")) {
                        rpc_tx.send((id.as_u64().unwrap(), result.clone())).unwrap();
                        info!(">>> {:?}", (id.as_u64().unwrap(), result.clone()));
                    } else if let (Some(method), Some(params)) = (req.get("method"), req.get("params")) {
                        let meth = method.as_str().unwrap();
                        if meth == "set_style" || meth == "scroll_to" || meth == "update" {
                            let request = ArrayBuilder::new().push(method.clone()).push(params.clone()).build();
                            update_tx.send(request).unwrap();
                        } else {
                            panic!("Unknown method {:?}.", method.as_str().unwrap());
                        }
                    } else {
                        panic!("Could not parse the core output: {:?}", req);
                    }
                }
            }
        });

        let stderr = process.stderr.unwrap();
        thread::spawn(move || {
            let buf_reader = BufReader::new(stderr);
            for line in buf_reader.lines() {
                if let Ok(line) = line {
                    error!("[core] {}", line);
                }
            }
        });

        let stdin = process.stdin.unwrap();

        let mut core = Core {
            stdin: stdin,
            update_rx: update_rx,
            rpc_rx: rpc_rx,
            rpc_index: 0,
            current_view: "".into(),
            views: HashMap::new(),
        };
        let view_id = core.new_view(Some(file.to_string())).as_str().unwrap().to_string();
        let view = View::new(file.to_string());
        core.views.insert(view_id.clone(), view);
        core.current_view = view_id;
        core
    }

    /// Build and send a JSON RPC request, returning the associated request ID to pair it with
    /// the response
    fn request(&mut self, method: &str, params: Value) -> u64 {
        self.rpc_index += 1;
        let message = ObjectBuilder::new()
            .insert("id", self.rpc_index)
            .insert("method", method)
            .insert("params", params)
            .build();
        self.send(&message);
        self.rpc_index
    }

    /// Build and send a JSON RPC notification. No synchronous response is expected, so
    /// there is no ID.
    fn notify(&mut self, method: &str, params: Value) {
        let message = ObjectBuilder::new()
            .insert("method", method)
            .insert("params", params)
            .build();
        self.send(&message);
    }

    /// Serialize JSON object and send it to the server
    fn send(&mut self, message: &Value) {
        let mut str_msg = serde_json::ser::to_string(&message).unwrap();
        str_msg.push('\n');
        self.stdin.write(str_msg.as_bytes()).unwrap();
    }

    fn call_sync(&mut self, method: &str, params: Value) -> Value {
        let i = self.request(method, params);
        let (id,result) = self.rpc_rx.recv().unwrap();
        assert_eq!(i, id);
        result
    }

    fn call_edit(&mut self, method: &str, params: Option<Value>) {
        let obj = ObjectBuilder::new()
            .insert("method", method)
            .insert("view_id", &self.current_view)
            .insert("params", params.unwrap_or(ArrayBuilder::new().build()));
        let built_obj = obj.build();
        info!(">>> {:?}", built_obj);
        self.notify("edit", built_obj);
    }

    fn call_edit_sync(&mut self, method: &str, params: Option<Value>) -> Value{
        let obj = ObjectBuilder::new()
            .insert("method", method)
            .insert("view_id", &self.current_view)
            .insert("params", params.unwrap_or(ArrayBuilder::new().build()));
        self.call_sync("edit", obj.build())
    }

    pub fn new_view(&mut self, file_path: Option<String>) -> Value {
        let mut obj = ObjectBuilder::new();
        if file_path.is_some() {
            obj = obj.insert("file_path", file_path.unwrap());
        }
        self.call_sync("new_view", obj.build())
    }

    pub fn save(&mut self) {
        let views = self.views.clone();
        let save_params = ObjectBuilder::new()
            .insert("view_id", &self.current_view.clone())
            .insert("file_path", views.get(&self.current_view).unwrap().filepath.clone())
            .build();
        self.request("save", save_params);
    }

    pub fn open(&mut self, filename: &str) {
        self.call_edit("open", Some(ObjectBuilder::new().insert("filename", filename).build()));
    }

    pub fn left(&mut self) { self.call_edit("move_left", None); }
    pub fn left_sel(&mut self) { self.call_edit("move_left_and_modify_selection", None); }

    pub fn right(&mut self) { self.call_edit("move_right", None); }
    pub fn right_sel(&mut self) { self.call_edit("move_right_and_modify_selection", None); }

    pub fn up(&mut self) { self.call_edit("move_up", None); }
    pub fn up_sel(&mut self) { self.call_edit("move_up_and_modify_selection", None); }

    pub fn down(&mut self) { self.call_edit("move_down", None); }
    pub fn down_sel(&mut self) { self.call_edit("move_down_and_modify_selection", None); }

    pub fn del(&mut self) { self.call_edit("delete_backward", None); }

    pub fn page_up(&mut self) { self.call_edit("page_up", None); }
    pub fn page_up_sel(&mut self) { self.call_edit("page_up_and_modify_selection", None); }

    pub fn page_down(&mut self) { self.call_edit("page_down", None); }
    pub fn page_down_sel(&mut self) { self.call_edit("page_down_and_modify_selection", None); }

    pub fn insert_newline(&mut self) { self.call_edit("insert_newline", None); }

    pub fn f1(&mut self) { self.call_edit("debug_rewrap", None); }

    pub fn f2(&mut self) { self.call_edit("debug_test_fg_spans", None); }

    pub fn char(&mut self, ch: char) {
        self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", ch).build()));
    }

    pub fn scroll(&mut self, start: u64, end: u64) {
        self.call_edit("scroll", Some(ArrayBuilder::new().push(start).push(end).build()));
    }

    pub fn click(&mut self, line: u64, column: u64) {
        self.call_edit("click", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build()));
    }
    pub fn drag(&mut self, line: u64, column: u64) {
        self.call_edit("drag", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build()));
    }

    pub fn copy(&mut self) -> String {
        self.call_edit_sync("copy", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn cut(&mut self) -> String {
        self.call_edit_sync("cut", None).as_str().map(|x|x.into()).unwrap()
    }
    pub fn paste(&mut self, s: String) {
        self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", s).build()));
    }

    #[allow(dead_code)]
    pub fn test(&mut self) {
        self.render_lines(0, 10);
    }

    pub fn render_lines(&mut self, _start: u64, _end: u64) {
        unimplemented!()
        // self.rpc_index += 1;
        // println!("render_lines");
        // let value = ArrayBuilder::new()
        //     .push("rpc")
        //     .push_object(|builder| builder
        //         .insert("index", self.rpc_index)
        //         .insert_array("request", |builder| builder
        //             .push("render_lines")
        //             .push_object(|builder| builder
        //                 .insert("first_line", _start)
        //                 .insert("last_line", _end)
        //             )
        //         )
        //     ).unwrap();
        // self.write(value);
    }

    pub fn render_lines_sync(&mut self, _start: u64, _end: u64) -> Value {
        unimplemented!()
        // self.render_lines(_start, _end);
        // let value = self.rpc_rx.recv().unwrap();
        // let object = value.as_object().unwrap();
        // assert_eq!(self.rpc_index, object.get("index").unwrap().as_u64().unwrap());
        // object.get("result").unwrap().clone()
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;

/// A TIS-100 port.
#[derive(Debug, PartialEq, Copy, Clone, Hash)]
pub enum Port {
    Up,
    Down,
    Left,
    Right,
}

/// An error which can be returned when parsing a port.
#[derive(Debug, PartialEq)]
pub struct ParsePortError;

impl FromStr for Port {
    type Err = ParsePortError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "UP" => Ok(Port::Up),
            "DOWN" => Ok(Port::Down),
            "LEFT" => Ok(Port::Left),
            "RIGHT" => Ok(Port::Right),
            _ => Err(ParsePortError)
        }
    }
}

/// A TIS-100 port or pseudo-port.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum PseudoPort {
    Any,
    Last,
}

/// An error which can be returned when parsing a psedo-port.
#[derive(Debug, PartialEq)]
pub struct ParsePseudoPortError;

impl FromStr for PseudoPort {
    type Err = ParsePseudoPortError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "ANY" => Ok(PseudoPort::Any),
            "LAST" => Ok(PseudoPort::Last),
            _ => Err(ParsePseudoPortError)
        }
    }
}

/// A TIS-100 port or pseudo-port.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum IoRegister {
    Port(Port),
    Pseudo(PseudoPort),
}

/// An error which can be returned when parsing an IO register.
#[derive(Debug, PartialEq)]
pub struct ParseIoRegisterError;

impl FromStr for IoRegister {
    type Err = ParseIoRegisterError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(port) = str::parse::<Port>(s) {
            Ok(IoRegister::Port(port))
        } else if let Ok(pseudo) = str::parse::<PseudoPort>(s) {
            Ok(IoRegister::Pseudo(pseudo))
        } else {
            Err(ParseIoRegisterError)
        }
    }
}

/// A TIS-100 register.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Register {
    Acc,
    Bak,
    Nil,
    Io(IoRegister),
}

/// An error which can be returned when parsing a register.
#[derive(Debug, PartialEq)]
pub struct ParseRegisterError;

impl FromStr for Register {
    type Err = ParseRegisterError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "ACC" => Ok(Register::Acc),
            "BAK" => Ok(Register::Bak),
            "NIL" => Ok(Register::Nil),
            _ => {
                if let Ok(reg) = str::parse::<IoRegister>(s) {
                    Ok(Register::Io(reg))
                } else {
                    Err(ParseRegisterError)
                }
            }
        }
    }
}

/// The operand component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Operand {
    Val(isize),
    Reg(Register),
}

/// An error which can be returned when parsing an operand.
#[derive(Debug, PartialEq)]
pub struct ParseOperandError;

impl FromStr for Operand {
    type Err = ParseOperandError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(val) = str::parse::<isize>(s) {
            Ok(Operand::Val(val))
        } else if let Ok(register) = str::parse::<Register>(s) {
            Ok(Operand::Reg(register))
        } else {
            Err(ParseOperandError)
        }
    }
}

/// The opcode component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Opcode {
    Nop,
    Mov,
    Swp,
    Sav,
    Add,
    Sub,
    Neg,
    Jmp,
    Jez,
    Jnz,
    Jgz,
    Jlz,
    Jro,
}

/// An error which can be returned when parsing an opcode.
#[derive(Debug, PartialEq)]
pub struct ParseOpcodeError;

impl FromStr for Opcode {
    type Err = ParseOpcodeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "NOP" => Ok(Opcode::Nop),
            "MOV" => Ok(Opcode::Mov),
            "SWP" => Ok(Opcode::Swp),
            "SAV" => Ok(Opcode::Sav),
            "ADD" => Ok(Opcode::Add),
            "SUB" => Ok(Opcode::Sub),
            "NEG" => Ok(Opcode::Neg),
            "JMP" => Ok(Opcode::Jmp),
            "JEZ" => Ok(Opcode::Jez),
            "JNZ" => Ok(Opcode::Jnz),
            "JGZ" => Ok(Opcode::Jgz),
            "JLZ" => Ok(Opcode::Jlz),
            "JRO" => Ok(Opcode::Jro),
            _ => Err(ParseOpcodeError),
        }
    }
}

/// A valid TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Instruction {
    Nop,
    Mov(Operand, Register),
    Swp,
    Sav,
    Add(Operand),
    Sub(Operand),
    Neg,
    Jmp(usize),
    Jez(usize),
    Jnz(usize),
    Jgz(usize),
    Jlz(usize),
    Jro(Operand),
}

/// The list of instructions created by parsing the program source code. The
/// instructions can then be evaluated by a basic execution node.
pub type Program = Vec<Instruction>;

#[test]
fn test_parse_port() {
    assert_eq!(str::parse::<Port>("UP"), Ok(Port::Up));
    assert_eq!(str::parse::<Port>("up"), Ok(Port::Up));
    assert_eq!(str::parse::<Port>("DOWN"), Ok(Port::Down));
    assert_eq!(str::parse::<Port>("LEFT"), Ok(Port::Left));
    assert_eq!(str::parse::<Port>("RIGHT"), Ok(Port::Right));
    assert_eq!(str::parse::<Port>("bad"), Err(ParsePortError));
}

#[test]
fn test_parse_psedo_port() {
    assert_eq!(str::parse::<PseudoPort>("ANY"), Ok(PseudoPort::Any));
    assert_eq!(str::parse::<PseudoPort>("any"), Ok(PseudoPort::Any));
    assert_eq!(str::parse::<PseudoPort>("LAST"), Ok(PseudoPort::Last));
    assert_eq!(str::parse::<PseudoPort>("bad"), Err(ParsePseudoPortError));
}

#[test]
fn test_parse_io_register() {
    assert_eq!(str::parse::<IoRegister>("UP"), Ok(IoRegister::Port(Port::Up)));
    assert_eq!(str::parse::<IoRegister>("ANY"), Ok(IoRegister::Pseudo(PseudoPort::Any)));
    assert_eq!(str::parse::<IoRegister>("bad"), Err(ParsePortError));
}

#[test]
fn test_parse_register() {
    assert_eq!(str::parse::<Register>("ACC"), Ok(Register::Acc));
    assert_eq!(str::parse::<Register>("acc"), Ok(Register::Acc));
    assert_eq!(str::parse::<Register>("BAK"), Ok(Register::Bak));
    assert_eq!(str::parse::<Register>("NIl"), Ok(Register::Nil));
    assert_eq!(str::parse::<Register>("UP"), Ok(Register::Io(IoRegister::Port(Port::Up))));
    assert_eq!(str::parse::<Register>("bad"), Err(ParseRegisterError));
}

#[test]
fn test_parse_operand() {
    assert_eq!(str::parse::<Operand>("ACC"), Ok(Operand::Reg(Register::Acc)));
    assert_eq!(str::parse::<Operand>("1"), Ok(Operand::Val(1)));
    assert_eq!(str::parse::<Operand>("bad"), Err(ParseOperandError));
}

#[test]
fn test_parse_opcode() {
    assert_eq!(str::parse::<Opcode>("NOP"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("nop"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("MOV"), Ok(Opcode::Mov));
    assert_eq!(str::parse::<Opcode>("SWP"), Ok(Opcode::Swp));
    assert_eq!(str::parse::<Opcode>("SAV"), Ok(Opcode::Sav));
    assert_eq!(str::parse::<Opcode>("ADD"), Ok(Opcode::Add));
    assert_eq!(str::parse::<Opcode>("SUB"), Ok(Opcode::Sub));
    assert_eq!(str::parse::<Opcode>("NEG"), Ok(Opcode::Neg));
    assert_eq!(str::parse::<Opcode>("JMP"), Ok(Opcode::Jmp));
    assert_eq!(str::parse::<Opcode>("JEZ"), Ok(Opcode::Jez));
    assert_eq!(str::parse::<Opcode>("JNZ"), Ok(Opcode::Jnz));
    assert_eq!(str::parse::<Opcode>("JGZ"), Ok(Opcode::Jgz));
    assert_eq!(str::parse::<Opcode>("JLZ"), Ok(Opcode::Jlz));
    assert_eq!(str::parse::<Opcode>("JRO"), Ok(Opcode::Jro));
    assert_eq!(str::parse::<Opcode>("bad"), Err(ParseOpcodeError));
}
<commit_msg>Remove Register::Bak<commit_after>use std::str::FromStr;

/// A TIS-100 port.
#[derive(Debug, PartialEq, Copy, Clone, Hash)]
pub enum Port {
    Up,
    Down,
    Left,
    Right,
}

/// An error which can be returned when parsing a port.
#[derive(Debug, PartialEq)]
pub struct ParsePortError;

impl FromStr for Port {
    type Err = ParsePortError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "UP" => Ok(Port::Up),
            "DOWN" => Ok(Port::Down),
            "LEFT" => Ok(Port::Left),
            "RIGHT" => Ok(Port::Right),
            _ => Err(ParsePortError)
        }
    }
}

/// A TIS-100 port or pseudo-port.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum PseudoPort {
    Any,
    Last,
}

/// An error which can be returned when parsing a psedo-port.
#[derive(Debug, PartialEq)]
pub struct ParsePseudoPortError;

impl FromStr for PseudoPort {
    type Err = ParsePseudoPortError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "ANY" => Ok(PseudoPort::Any),
            "LAST" => Ok(PseudoPort::Last),
            _ => Err(ParsePseudoPortError)
        }
    }
}

/// A TIS-100 port or pseudo-port.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum IoRegister {
    Port(Port),
    Pseudo(PseudoPort),
}

/// An error which can be returned when parsing an IO register.
#[derive(Debug, PartialEq)]
pub struct ParseIoRegisterError;

impl FromStr for IoRegister {
    type Err = ParseIoRegisterError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(port) = str::parse::<Port>(s) {
            Ok(IoRegister::Port(port))
        } else if let Ok(pseudo) = str::parse::<PseudoPort>(s) {
            Ok(IoRegister::Pseudo(pseudo))
        } else {
            Err(ParseIoRegisterError)
        }
    }
}

/// A TIS-100 register.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Register {
    Acc,
    Nil,
    Io(IoRegister),
}

/// An error which can be returned when parsing a register.
#[derive(Debug, PartialEq)]
pub struct ParseRegisterError;

impl FromStr for Register {
    type Err = ParseRegisterError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "ACC" => Ok(Register::Acc),
            "NIL" => Ok(Register::Nil),
            _ => {
                if let Ok(reg) = str::parse::<IoRegister>(s) {
                    Ok(Register::Io(reg))
                } else {
                    Err(ParseRegisterError)
                }
            }
        }
    }
}

/// The operand component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Operand {
    Val(isize),
    Reg(Register),
}

/// An error which can be returned when parsing an operand.
#[derive(Debug, PartialEq)]
pub struct ParseOperandError;

impl FromStr for Operand {
    type Err = ParseOperandError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(val) = str::parse::<isize>(s) {
            Ok(Operand::Val(val))
        } else if let Ok(register) = str::parse::<Register>(s) {
            Ok(Operand::Reg(register))
        } else {
            Err(ParseOperandError)
        }
    }
}

/// The opcode component of a TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Opcode {
    Nop,
    Mov,
    Swp,
    Sav,
    Add,
    Sub,
    Neg,
    Jmp,
    Jez,
    Jnz,
    Jgz,
    Jlz,
    Jro,
}

/// An error which can be returned when parsing an opcode.
#[derive(Debug, PartialEq)]
pub struct ParseOpcodeError;

impl FromStr for Opcode {
    type Err = ParseOpcodeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "NOP" => Ok(Opcode::Nop),
            "MOV" => Ok(Opcode::Mov),
            "SWP" => Ok(Opcode::Swp),
            "SAV" => Ok(Opcode::Sav),
            "ADD" => Ok(Opcode::Add),
            "SUB" => Ok(Opcode::Sub),
            "NEG" => Ok(Opcode::Neg),
            "JMP" => Ok(Opcode::Jmp),
            "JEZ" => Ok(Opcode::Jez),
            "JNZ" => Ok(Opcode::Jnz),
            "JGZ" => Ok(Opcode::Jgz),
            "JLZ" => Ok(Opcode::Jlz),
            "JRO" => Ok(Opcode::Jro),
            _ => Err(ParseOpcodeError),
        }
    }
}

/// A valid TIS-100 instruction.
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Instruction {
    Nop,
    Mov(Operand, Register),
    Swp,
    Sav,
    Add(Operand),
    Sub(Operand),
    Neg,
    Jmp(usize),
    Jez(usize),
    Jnz(usize),
    Jgz(usize),
    Jlz(usize),
    Jro(Operand),
}

/// The list of instructions created by parsing the program source code. The
/// instructions can then be evaluated by a basic execution node.
pub type Program = Vec<Instruction>;

#[test]
fn test_parse_port() {
    assert_eq!(str::parse::<Port>("UP"), Ok(Port::Up));
    assert_eq!(str::parse::<Port>("up"), Ok(Port::Up));
    assert_eq!(str::parse::<Port>("DOWN"), Ok(Port::Down));
    assert_eq!(str::parse::<Port>("LEFT"), Ok(Port::Left));
    assert_eq!(str::parse::<Port>("RIGHT"), Ok(Port::Right));
    assert_eq!(str::parse::<Port>("bad"), Err(ParsePortError));
}

#[test]
fn test_parse_psedo_port() {
    assert_eq!(str::parse::<PseudoPort>("ANY"), Ok(PseudoPort::Any));
    assert_eq!(str::parse::<PseudoPort>("any"), Ok(PseudoPort::Any));
    assert_eq!(str::parse::<PseudoPort>("LAST"), Ok(PseudoPort::Last));
    assert_eq!(str::parse::<PseudoPort>("bad"), Err(ParsePseudoPortError));
}

#[test]
fn test_parse_io_register() {
    assert_eq!(str::parse::<IoRegister>("UP"), Ok(IoRegister::Port(Port::Up)));
    assert_eq!(str::parse::<IoRegister>("ANY"), Ok(IoRegister::Pseudo(PseudoPort::Any)));
    assert_eq!(str::parse::<IoRegister>("bad"), Err(ParsePortError));
}

#[test]
fn test_parse_register() {
    assert_eq!(str::parse::<Register>("ACC"), Ok(Register::Acc));
    assert_eq!(str::parse::<Register>("acc"), Ok(Register::Acc));
    assert_eq!(str::parse::<Register>("NIl"), Ok(Register::Nil));
    assert_eq!(str::parse::<Register>("UP"), Ok(Register::Io(IoRegister::Port(Port::Up))));
    assert_eq!(str::parse::<Register>("bad"), Err(ParseRegisterError));
}

#[test]
fn test_parse_operand() {
    assert_eq!(str::parse::<Operand>("ACC"), Ok(Operand::Reg(Register::Acc)));
    assert_eq!(str::parse::<Operand>("1"), Ok(Operand::Val(1)));
    assert_eq!(str::parse::<Operand>("bad"), Err(ParseOperandError));
}

#[test]
fn test_parse_opcode() {
    assert_eq!(str::parse::<Opcode>("NOP"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("nop"), Ok(Opcode::Nop));
    assert_eq!(str::parse::<Opcode>("MOV"), Ok(Opcode::Mov));
    assert_eq!(str::parse::<Opcode>("SWP"), Ok(Opcode::Swp));
    assert_eq!(str::parse::<Opcode>("SAV"), Ok(Opcode::Sav));
    assert_eq!(str::parse::<Opcode>("ADD"), Ok(Opcode::Add));
    assert_eq!(str::parse::<Opcode>("SUB"), Ok(Opcode::Sub));
    assert_eq!(str::parse::<Opcode>("NEG"), Ok(Opcode::Neg));
    assert_eq!(str::parse::<Opcode>("JMP"), Ok(Opcode::Jmp));
    assert_eq!(str::parse::<Opcode>("JEZ"), Ok(Opcode::Jez));
    assert_eq!(str::parse::<Opcode>("JNZ"), Ok(Opcode::Jnz));
    assert_eq!(str::parse::<Opcode>("JGZ"), Ok(Opcode::Jgz));
    assert_eq!(str::parse::<Opcode>("JLZ"), Ok(Opcode::Jlz));
    assert_eq!(str::parse::<Opcode>("JRO"), Ok(Opcode::Jro));
    assert_eq!(str::parse::<Opcode>("bad"), Err(ParseOpcodeError));
}
<|endoftext|>


<commit_before>//! Helper methods and structures for working with cubes.
//!
//! ```ignore
//!         3  ---------  2
//!           /       / |
//!          /  up   /  |
//!      6  -------- 7  | 1
//!        |        |  /
//! west   |  south | /  east
//!        |        |/
//!      5  -------- 4
//! ```
//!
//!
//! ```ignore
//!         7  ---------  6
//!           /       / |
//!          /  up   /  |
//!      2  -------- 3  | 5
//!        |        |  /
//! east   |  north | /  west
//!        |        |/
//!      1  -------- 0
//! ```

use std::num::FromPrimitive;
use std::str::FromStr;

use vecmath::Vector3;

pub use self::Face::{
    Down,
    Up,
    North,
    South,
    West,
    East,
};

// Cube faces (clockwise).
pub const QUADS: &'static [[usize; 4]; 6] = &[
    [1, 0, 5, 4], // down
    [7, 6, 3, 2], // up
    [0, 1, 2, 3], // north
    [4, 5, 6, 7], // south
    [5, 0, 3, 6], // west
    [1, 4, 7, 2]  // east
];

// Cube vertices.
pub const VERTICES: &'static [Vector3<f32>; 8] = &[
    // This is the north surface
    [0.0, 0.0, 0.0], // 0
    [1.0, 0.0, 0.0], // 1
    [1.0, 1.0, 0.0], // 2
    [0.0, 1.0, 0.0], // 3

    // This is the south surface
    [1.0, 0.0, 1.0], // 4
    [0.0, 0.0, 1.0], // 5
    [0.0, 1.0, 1.0], // 6
    [1.0, 1.0, 1.0]  // 7
];

/// A value representing face direction.
#[repr(usize)]
#[derive(Copy, PartialEq, Eq, FromPrimitive, Show)]
pub enum Face {
    /// Facing down.
    Down = 0,
    /// Facing up.
    Up = 1,
    /// Facing north.
    North = 2,
    /// Facing south.
    South = 3,
    /// Facing west.
    West = 4,
    /// Facing east.
    East = 5
}

impl Face {
    /// Computes vertices of the face.
    pub fn vertices(self, base: Vector3<f32>, scale: Vector3<f32>) -> [Vector3<f32>; 4] {
        use array::*;

        let [x, y, z] = base;
        let [sx, sy, sz] = scale;

        QUADS[self as usize].map(|i| VERTICES[i]).map(|[vx, vy, vz]| {
            [x + sx * vx, y + sy * vy, z + sz * vz]
        })
    }

    /// Gets the direction of face.
    pub fn direction(self) -> [i32; 3] {
        match self {
            Down => [0, -1, 0],
            Up => [0, 1, 0],
            North => [0, 0, -1],
            South => [0, 0, 1],
            West => [-1, 0, 0],
            East => [1, 0, 0]
        }
    }

    /// Gets the face in a specific direction.
    pub fn from_direction(d: [i32; 3]) -> Option<Face> {
        Some(match d {
            [0, -1, 0] => Down,
            [0, 1, 0] => Up,
            [0, 0, -1] => North,
            [0, 0, 1] => South,
            [-1, 0, 0] => West,
            [1, 0, 0] => East,
            _ => return None
        })
    }
}

impl FromStr for Face {
    pub fn from_str(s: &str) -> Option<Face> {
        Some(match s {
            "down" => Down,
            "up" => Up,
            "north" => North,
            "south" => South,
            "west" => West,
            "east" => East,
            _ => return None
        })
    }
}

/// Iterates through each face on a cube.
#[derive(Copy)]
pub struct FaceIterator {
    face: usize,
}

impl FaceIterator {
    /// Creates a new face iterator.
    pub fn new() -> FaceIterator {
        FaceIterator {
            face: 0
        }
    }
}

impl Iterator for FaceIterator {
    type Item = Face;

    fn next(&mut self) -> Option<Face> {
        match self.face {
            x if x < 6 => {
                self.face += 1;
                FromPrimitive::from_uint(x)
            },
            _ => None
        }
    }
}
<commit_msg>Revert "Change visibility of Face::from_str (wasn't public)."<commit_after>//! Helper methods and structures for working with cubes.
//!
//! ```ignore
//!         3  ---------  2
//!           /       / |
//!          /  up   /  |
//!      6  -------- 7  | 1
//!        |        |  /
//! west   |  south | /  east
//!        |        |/
//!      5  -------- 4
//! ```
//!
//!
//! ```ignore
//!         7  ---------  6
//!           /       / |
//!          /  up   /  |
//!      2  -------- 3  | 5
//!        |        |  /
//! east   |  north | /  west
//!        |        |/
//!      1  -------- 0
//! ```

use std::num::FromPrimitive;
use std::str::FromStr;

use vecmath::Vector3;

pub use self::Face::{
    Down,
    Up,
    North,
    South,
    West,
    East,
};

// Cube faces (clockwise).
pub const QUADS: &'static [[usize; 4]; 6] = &[
    [1, 0, 5, 4], // down
    [7, 6, 3, 2], // up
    [0, 1, 2, 3], // north
    [4, 5, 6, 7], // south
    [5, 0, 3, 6], // west
    [1, 4, 7, 2]  // east
];

// Cube vertices.
pub const VERTICES: &'static [Vector3<f32>; 8] = &[
    // This is the north surface
    [0.0, 0.0, 0.0], // 0
    [1.0, 0.0, 0.0], // 1
    [1.0, 1.0, 0.0], // 2
    [0.0, 1.0, 0.0], // 3

    // This is the south surface
    [1.0, 0.0, 1.0], // 4
    [0.0, 0.0, 1.0], // 5
    [0.0, 1.0, 1.0], // 6
    [1.0, 1.0, 1.0]  // 7
];

/// A value representing face direction.
#[repr(usize)]
#[derive(Copy, PartialEq, Eq, FromPrimitive, Show)]
pub enum Face {
    /// Facing down.
    Down = 0,
    /// Facing up.
    Up = 1,
    /// Facing north.
    North = 2,
    /// Facing south.
    South = 3,
    /// Facing west.
    West = 4,
    /// Facing east.
    East = 5
}

impl Face {
    /// Computes vertices of the face.
    pub fn vertices(self, base: Vector3<f32>, scale: Vector3<f32>) -> [Vector3<f32>; 4] {
        use array::*;

        let [x, y, z] = base;
        let [sx, sy, sz] = scale;

        QUADS[self as usize].map(|i| VERTICES[i]).map(|[vx, vy, vz]| {
            [x + sx * vx, y + sy * vy, z + sz * vz]
        })
    }

    /// Gets the direction of face.
    pub fn direction(self) -> [i32; 3] {
        match self {
            Down => [0, -1, 0],
            Up => [0, 1, 0],
            North => [0, 0, -1],
            South => [0, 0, 1],
            West => [-1, 0, 0],
            East => [1, 0, 0]
        }
    }

    /// Gets the face in a specific direction.
    pub fn from_direction(d: [i32; 3]) -> Option<Face> {
        Some(match d {
            [0, -1, 0] => Down,
            [0, 1, 0] => Up,
            [0, 0, -1] => North,
            [0, 0, 1] => South,
            [-1, 0, 0] => West,
            [1, 0, 0] => East,
            _ => return None
        })
    }
}

impl FromStr for Face {
    fn from_str(s: &str) -> Option<Face> {
        Some(match s {
            "down" => Down,
            "up" => Up,
            "north" => North,
            "south" => South,
            "west" => West,
            "east" => East,
            _ => return None
        })
    }
}

/// Iterates through each face on a cube.
#[derive(Copy)]
pub struct FaceIterator {
    face: usize,
}

impl FaceIterator {
    /// Creates a new face iterator.
    pub fn new() -> FaceIterator {
        FaceIterator {
            face: 0
        }
    }
}

impl Iterator for FaceIterator {
    type Item = Face;

    fn next(&mut self) -> Option<Face> {
        match self.face {
            x if x < 6 => {
                self.face += 1;
                FromPrimitive::from_uint(x)
            },
            _ => None
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::PathBuf;
use std::fs;

use syn;
use proc_macro2::{TokenStream, Span};
use sha1::Sha1;

use utils::{Target, dummy_idents};

#[derive(Clone, Serialize, Deserialize, Debug)]
struct Snippet {
    name: String,
    code: String,
    arg_count: usize
}

fn hash( string: &str ) -> String {
    let mut hasher = Sha1::new();
    hasher.update( string.as_bytes() );
    format!( "{}", hasher.digest() )
}

fn database_path() -> PathBuf {
    let target_path = env::var_os( "CARGO_WEB_TARGET_DIR" ).map( PathBuf::from ).unwrap();
    assert!( target_path.exists() );

    target_path.join( ".cargo-web" ).join( "snippets" )
}

fn output_snippet( snippet: &Snippet ) {
    let hash = hash( &snippet.name );
    let directory = database_path().join( &hash[ 0..2 ] );

    fs::create_dir_all( &directory ).expect( "failed to create a directory for the JS snippet database" );
    let path = directory.join( format!( "{}.json", hash ) );

    let blob: Vec< u8 > = serde_json::to_string( &snippet ).unwrap().into_bytes();
    if path.exists() {
        if let Ok( size ) = path.metadata().map( |metadata| metadata.len() ) {
            if size == blob.len() as u64 {
                return;
            }
        }
    }

    fs::write( path, blob ).expect( "failed to write a JS snippet" );
}

pub fn js_shim_extern_code( target: Target, code: &str, arg_count: usize ) -> (syn::Ident, TokenStream) {
    let snippet = Snippet {
        name: format!( "__cargo_web_snippet_{}", hash( code ) ),
        code: code.to_owned(),
        arg_count
    };

    let shim_name = syn::Ident::new( &snippet.name, Span::call_site() );
    let shim_args: Vec< _ > = dummy_idents( arg_count ).map( |name| quote! { #name: *const u8 } ).collect();
    let shim_args_passthrough: Vec< _ > = dummy_idents( arg_count ).map( |name| quote! { #name } ).collect();
    let output = match target {
        Target::Emscripten => {
            let code_bytes = syn::LitByteStr::new( format!( "{}\0", code ).as_str().as_bytes(), Span::call_site() );

            quote! {
                const SNIPPET: &'static [u8] = #code_bytes;

                fn #shim_name( #(#shim_args),* ) -> i32 {
                    extern "C" {
                        pub fn emscripten_asm_const_int( code: *const u8, ... ) -> i32;
                    }

                    unsafe {
                        emscripten_asm_const_int( SNIPPET as *const _ as *const u8, #(#shim_args_passthrough),* )
                    }
                }
            }
        },
        Target::NativeWebAssembly => {
            output_snippet( &snippet );
            quote! {
                extern "C" {
                    pub fn #shim_name( #(#shim_args),* ) -> i32;
                }
            }
        }
    };

    (shim_name, output)
}
<commit_msg>Replace some `unwrap`s with `expect`s in procedural macros<commit_after>use std::env;
use std::path::PathBuf;
use std::fs;

use syn;
use proc_macro2::{TokenStream, Span};
use sha1::Sha1;

use utils::{Target, dummy_idents};

#[derive(Clone, Serialize, Deserialize, Debug)]
struct Snippet {
    name: String,
    code: String,
    arg_count: usize
}

fn hash( string: &str ) -> String {
    let mut hasher = Sha1::new();
    hasher.update( string.as_bytes() );
    format!( "{}", hasher.digest() )
}

fn database_path() -> PathBuf {
    let target_path = env::var_os( "CARGO_WEB_TARGET_DIR" )
        .map( PathBuf::from )
        .expect( "you need to use `cargo-web` to compile your project for the `wasm32-unknown-unknown` target" );
    assert!( target_path.exists() );

    target_path.join( ".cargo-web" ).join( "snippets" )
}

fn output_snippet( snippet: &Snippet ) {
    let hash = hash( &snippet.name );
    let directory = database_path().join( &hash[ 0..2 ] );

    fs::create_dir_all( &directory ).expect( "failed to create a directory for the JS snippet database" );
    let path = directory.join( format!( "{}.json", hash ) );

    let blob: Vec< u8 > = serde_json::to_string( &snippet ).expect( "failed to convert the JS snipped to JSON" ).into_bytes();
    if path.exists() {
        if let Ok( size ) = path.metadata().map( |metadata| metadata.len() ) {
            if size == blob.len() as u64 {
                return;
            }
        }
    }

    fs::write( path, blob ).expect( "failed to write a JS snippet" );
}

pub fn js_shim_extern_code( target: Target, code: &str, arg_count: usize ) -> (syn::Ident, TokenStream) {
    let snippet = Snippet {
        name: format!( "__cargo_web_snippet_{}", hash( code ) ),
        code: code.to_owned(),
        arg_count
    };

    let shim_name = syn::Ident::new( &snippet.name, Span::call_site() );
    let shim_args: Vec< _ > = dummy_idents( arg_count ).map( |name| quote! { #name: *const u8 } ).collect();
    let shim_args_passthrough: Vec< _ > = dummy_idents( arg_count ).map( |name| quote! { #name } ).collect();
    let output = match target {
        Target::Emscripten => {
            let code_bytes = syn::LitByteStr::new( format!( "{}\0", code ).as_str().as_bytes(), Span::call_site() );

            quote! {
                const SNIPPET: &'static [u8] = #code_bytes;

                fn #shim_name( #(#shim_args),* ) -> i32 {
                    extern "C" {
                        pub fn emscripten_asm_const_int( code: *const u8, ... ) -> i32;
                    }

                    unsafe {
                        emscripten_asm_const_int( SNIPPET as *const _ as *const u8, #(#shim_args_passthrough),* )
                    }
                }
            }
        },
        Target::NativeWebAssembly => {
            output_snippet( &snippet );
            quote! {
                extern "C" {
                    pub fn #shim_name( #(#shim_args),* ) -> i32;
                }
            }
        }
    };

    (shim_name, output)
}
<|endoftext|>