<commit_before>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    pub cells: [Cell; 30_000],
    pub data_pointer: usize,
    out: Stdout
}

impl VM {
    pub fn new(out: Option<Stdout>) -> VM {
        let stdout = out.unwrap_or_else(|| io::stdout());
        VM { cells: [0; 30_000], data_pointer: 0, out: stdout }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => panic!(error),
            },
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer].checked_add(1).unwrap_or(0);
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer]
            .checked_sub(1)
            .unwrap_or(Cell::max_value());
    }

    pub fn right_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer -= 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {},
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_new() {
        let vm = VM::new();
        assert!(vm.cells[0] == 0);
        assert!(vm.cells[30_000 - 1] == 0);
        assert!(vm.cells[0] == 0);
    }

    #[test]
    fn test_increment() {
        let mut vm = VM::new();
        vm.increment();
        assert!(vm.cells[0] == 1);
    }

    #[test]
    fn test_decrement() {
        const STARTING_VALUE: u8 = 2;

        let mut vm = VM::new();
        vm.cells[0] = STARTING_VALUE;
        vm.decrement();
        assert!(vm.cells[0] == STARTING_VALUE - 1);
    }

    #[test]
    fn test_right_shift() {
        let mut vm = VM::new();
        vm.right_shift();
        assert!(vm.data_pointer == 1);
    }

    #[test]
    fn test_left_shift() {
        const STARTING_POSITION: usize = 2;

        let mut vm = VM::new();
        vm.data_pointer  = STARTING_POSITION;
        vm.left_shift();
        assert!(vm.data_pointer == 1);
    }
}
<commit_msg>Change VM.out(&self) to use instance of Stdout<commit_after>use std::io;
use std::io::{Write,Read,Stdout};
use command::Command;

type Cell = u8;

pub struct VM {
    pub cells: [Cell; 30_000],
    pub data_pointer: usize,
    out: Stdout
}

impl VM {
    pub fn new(out: Option<Stdout>) -> VM {
        let stdout = out.unwrap_or_else(|| io::stdout());
        VM { cells: [0; 30_000], data_pointer: 0, out: stdout }
    }

    pub fn output(&mut self) {
        self.out
            .write_fmt(format_args!("{}", self.cells[self.data_pointer] as char))
            .expect("Could not output current byte");
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => panic!(error),
            },
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer].checked_add(1).unwrap_or(0);
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer]
            .checked_sub(1)
            .unwrap_or(Cell::max_value());
    }

    pub fn right_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer -= 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {},
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_new() {
        let vm = VM::new();
        assert!(vm.cells[0] == 0);
        assert!(vm.cells[30_000 - 1] == 0);
        assert!(vm.cells[0] == 0);
    }

    #[test]
    fn test_increment() {
        let mut vm = VM::new();
        vm.increment();
        assert!(vm.cells[0] == 1);
    }

    #[test]
    fn test_decrement() {
        const STARTING_VALUE: u8 = 2;

        let mut vm = VM::new();
        vm.cells[0] = STARTING_VALUE;
        vm.decrement();
        assert!(vm.cells[0] == STARTING_VALUE - 1);
    }

    #[test]
    fn test_right_shift() {
        let mut vm = VM::new();
        vm.right_shift();
        assert!(vm.data_pointer == 1);
    }

    #[test]
    fn test_left_shift() {
        const STARTING_POSITION: usize = 2;

        let mut vm = VM::new();
        vm.data_pointer  = STARTING_POSITION;
        vm.left_shift();
        assert!(vm.data_pointer == 1);
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};

use chrono::{DateTime, Local};
use log::debug;
use serde::{Deserialize, Serialize};
use serde_yaml;

use crate::error::{Error, Result};
use crate::utils::markdown_to_html;

/// blog post headers
///
/// the blog post headers is parsed using yaml format.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PostHeaders {
    /// post created local time, `created: 1970-01-01T00:00:00+08:00`
    pub created: DateTime<Local>,
    /// post hidden flag, `hidden: true`, default `false`
    #[serde(default)]
    pub hidden: bool,
    /// post tags, `tags: [hello, world]`, default `[]`
    #[serde(default)]
    pub tags: Vec<String>,
    /// post description
    #[serde(default)]
    pub description: String,
}

/// blog post
///
/// every blog post is composed of `head` part and `body` part.
/// the two part is separated by the first blank line.
#[derive(Serialize)]
pub struct Post {
    /// blog root path
    root: PathBuf,
    /// post path from relative root directory
    pub path: PathBuf,
    /// the post title
    pub title: String,
    /// the post url
    pub url: PathBuf,
    /// post headers
    pub headers: PostHeaders,
    /// post html body
    pub content: String,
}

impl Post {
    pub fn new<P: AsRef<Path>>(root: P, path: P) -> Result<Post> {
        let root = root.as_ref();
        let path = path.as_ref();
        debug!("loading post: {}", path.display());

        let fp = root.join(&path);
        let mut fo = File::open(fp)?;
        let mut content = String::new();
        fo.read_to_string(&mut content)?;

        let v: Vec<&str> = content.splitn(2, "\n\n").collect();
        if v.len() != 2 {
            return Err(Error::PostOnlyOnePart(path.into()));
        }
        let head = v[0].trim();
        let body = v[1].trim();
        if head.is_empty() {
            return Err(Error::PostNoHead(path.into()));
        }
        if body.is_empty() {
            return Err(Error::PostNoBody(path.into()));
        }

        let title = path
            .file_stem()
            .and_then(|x| x.to_str())
            .expect(&format!("post filename format error: {}", path.display()));
        let url = Path::new("/").join(path).with_extension("html");
        let mut headers: PostHeaders = serde_yaml::from_str(head)?;
        if headers.description.is_empty() {
            let desc = body
                .split("\n\n")
                .take(1)
                .next()
                .unwrap_or("")
                .split_whitespace()
                .take(100)
                .collect::<Vec<_>>()
                .join(" ");
            headers.description.push_str(&desc);
            if !headers.description.is_empty() {
                headers.description.push_str("...");
            }
        }
        let content = markdown_to_html(body);

        Ok(Post {
            root: root.to_owned(),
            path: path.to_owned(),
            title: title.to_owned(),
            url,
            headers,
            content,
        })
    }

    /// the absolute path of blog post markdown file.
    pub fn src(&self) -> PathBuf {
        self.root.join(&self.path)
    }

    /// the absolute path of blog post html file.
    pub fn dest(&self) -> PathBuf {
        self.path.with_extension("html")
    }
}
<commit_msg>now it's possible to provide a title in headers<commit_after>use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};

use chrono::{DateTime, Local};
use log::debug;
use serde::{Deserialize, Serialize};
use serde_yaml;

use crate::error::{Error, Result};
use crate::utils::markdown_to_html;

/// blog post headers
///
/// the blog post headers is parsed using yaml format.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PostHeaders {
    /// post created local time, `created: 1970-01-01T00:00:00+08:00`
    pub created: DateTime<Local>,
    /// post hidden flag, `hidden: true`, default `false`
    #[serde(default)]
    pub hidden: bool,
    /// post tags, `tags: [hello, world]`, default `[]`
    #[serde(default)]
    pub tags: Vec<String>,
    /// post description
    #[serde(default)]
    pub description: String,
    #[serde(default)]
    pub title: String,
}

/// blog post
///
/// every blog post is composed of `head` part and `body` part.
/// the two part is separated by the first blank line.
#[derive(Serialize)]
pub struct Post {
    /// blog root path
    root: PathBuf,
    /// post path from relative root directory
    pub path: PathBuf,
    /// the post title
    pub title: String,
    /// the post url
    pub url: PathBuf,
    /// post headers
    pub headers: PostHeaders,
    /// post html body
    pub content: String,
}

impl Post {
    pub fn new<P: AsRef<Path>>(root: P, path: P) -> Result<Post> {
        let root = root.as_ref();
        let path = path.as_ref();
        debug!("loading post: {}", path.display());

        let fp = root.join(&path);
        let mut fo = File::open(fp)?;
        let mut content = String::new();
        fo.read_to_string(&mut content)?;

        let v: Vec<&str> = content.splitn(2, "\n\n").collect();
        if v.len() != 2 {
            return Err(Error::PostOnlyOnePart(path.into()));
        }
        let head = v[0].trim();
        let body = v[1].trim();
        if head.is_empty() {
            return Err(Error::PostNoHead(path.into()));
        }
        if body.is_empty() {
            return Err(Error::PostNoBody(path.into()));
        }

        let title = path
            .file_stem()
            .and_then(|x| x.to_str())
            .expect(&format!("post filename format error: {}", path.display()));
        let url = Path::new("/").join(path).with_extension("html");
        let mut headers: PostHeaders = serde_yaml::from_str(head)?;
        if headers.description.is_empty() {
            let desc = body
                .split("\n\n")
                .take(1)
                .next()
                .unwrap_or("")
                .split_whitespace()
                .take(100)
                .collect::<Vec<_>>()
                .join(" ");
            headers.description.push_str(&desc);
            if !headers.description.is_empty() {
                headers.description.push_str("...");
            }
        }
        let title = if headers.title.is_empty() {
            title.to_string()
        } else {
            headers.title.to_string()
        };
        let content = markdown_to_html(body);

        Ok(Post {
            root: root.to_owned(),
            path: path.to_owned(),
            title: title.to_owned(),
            url,
            headers,
            content,
        })
    }

    /// the absolute path of blog post markdown file.
    pub fn src(&self) -> PathBuf {
        self.root.join(&self.path)
    }

    /// the absolute path of blog post html file.
    pub fn dest(&self) -> PathBuf {
        self.path.with_extension("html")
    }
}
<|endoftext|>


<commit_before>use rustyline::error::ReadlineError;
use rustyline::Editor;

use environment::Environment;
use interpreter::*;
use error::*;
use parser;

pub fn run_repl() {
    println!("Balloon REPL");
    let mut rl = Editor::<()>::new();
    let mut env = Environment::new();
    env.start_scope();
    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                let orig_input = String::from(line.trim());
                let mut input = orig_input.clone();
                if !input.ends_with(";") {
                    input.push(';');
                }
                match parser::program(&input) {
                    Err(parse_error) => {
                        print_parse_error("repl".to_string(), orig_input, parse_error);
                    }
                    Ok(ast) => {
                        if let Err(e) = interpret_statements(&ast, &mut env) {
                            match e {
                                InterpreterError::ReferenceError(id) => {
                                    println!("reference error: `{}` was not declared", id);
                                }
                                InterpreterError::UndeclaredAssignment(id) => {
                                    println!("reference error: cannot assign to undeclared `{}` ", id);
                                }
                            }
                        }
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break;
            }
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
    env.end_scope();
}
<commit_msg>Re-add support for history *per session* in REPL<commit_after>use rustyline::error::ReadlineError;
use rustyline::Editor;

use environment::Environment;
use interpreter::*;
use error::*;
use parser;

pub fn run_repl() {
    println!("Balloon REPL");
    let mut rl = Editor::<()>::new();
    let mut env = Environment::new();
    env.start_scope();
    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                let orig_input = String::from(line.trim());
                let mut input = orig_input.clone();
                if !input.ends_with(";") {
                    input.push(';');
                }
                match parser::program(&input) {
                    Err(parse_error) => {
                        print_parse_error("repl".to_string(), orig_input, parse_error);
                    }
                    Ok(ast) => {
                        if let Err(e) = interpret_statements(&ast, &mut env) {
                            match e {
                                InterpreterError::ReferenceError(id) => {
                                    println!("reference error: `{}` was not declared", id);
                                }
                                InterpreterError::UndeclaredAssignment(id) => {
                                    println!("reference error: cannot assign to undeclared `{}` ", id);
                                }
                            }
                        }
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break;
            }
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
    env.end_scope();
}
<|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.

//! Synchronization of the local blockchain with the rest of the network. Used
//! either on a brand new node or when a node is late based on others' heads.
//! Always starts by downloading the header chain before asking either for full
//! blocks or a full UTXO set with related information.

/// How many block bodies to download in parallel
const MAX_BODY_DOWNLOADS: usize = 8;

use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};

use core::core::hash::{Hash, Hashed};
use chain;
use p2p;
use types::Error;
use util::LOGGER;

#[derive(Debug)]
struct BlockDownload {
	hash: Hash,
	start_time: Instant,
	retries: u8,
}

/// Manages syncing the local chain with other peers. Needs both a head chain
/// and a full block chain to operate. First tries to advance the header
/// chain as much as possible, then downloads the full blocks by batches.
pub struct Syncer {
	chain: Arc<chain::Chain>,
	p2p: Arc<p2p::Server>,

	sync: Mutex<bool>,
	last_header_req: Mutex<Instant>,
	blocks_to_download: Mutex<Vec<Hash>>,
	blocks_downloading: Mutex<Vec<BlockDownload>>,
}

impl Syncer {
	pub fn new(chain_ref: Arc<chain::Chain>, p2p: Arc<p2p::Server>) -> Syncer {
		Syncer {
			chain: chain_ref,
			p2p: p2p,
			sync: Mutex::new(true),
			last_header_req: Mutex::new(Instant::now() - Duration::from_secs(2)),
			blocks_to_download: Mutex::new(vec![]),
			blocks_downloading: Mutex::new(vec![]),
		}
	}

	pub fn syncing(&self) -> bool {
		*self.sync.lock().unwrap()
	}

	/// Checks the local chain state, comparing it with our peers and triggers
	/// syncing if required.
	pub fn run(&self) -> Result<(), Error> {
		info!(LOGGER, "Sync: starting sync");

		// Loop for 10s waiting for some peers to potentially sync from.
		let start = Instant::now();
		loop {
			let pc = self.p2p.peer_count();
			if pc > 3 {
				break;
			}
			if Instant::now() - start > Duration::from_secs(10) {
				break;
			}
			thread::sleep(Duration::from_millis(200));
		}

		// Now check we actually have at least one peer to sync from.
		// If not then end the sync cleanly.
		if self.p2p.peer_count() == 0 {
			info!(LOGGER, "Sync: no peers to sync with, done.");

			let mut sync = self.sync.lock().unwrap();
			*sync = false;

			return Ok(())
		}

		// check if we have missing full blocks for which we already have a header
		self.init_download()?;

		// main syncing loop, requests more headers and bodies periodically as long
		// as a peer with higher difficulty exists and we're not fully caught up
		info!(LOGGER, "Sync: Starting loop.");
		loop {
			let tip = self.chain.get_header_head()?;

			// TODO do something better (like trying to get more) if we lose peers
			let peer = self.p2p.most_work_peer().expect("No peers available for sync.");
			let peer = peer.read().unwrap();
			debug!(
				LOGGER,
				"Sync: peer {} vs us {}",
				peer.info.total_difficulty,
				tip.total_difficulty
			);

			let more_headers = peer.info.total_difficulty > tip.total_difficulty;
			let more_bodies = {
				let blocks_to_download = self.blocks_to_download.lock().unwrap();
				let blocks_downloading = self.blocks_downloading.lock().unwrap();
				debug!(
					LOGGER,
					"Sync: blocks to download {}, block downloading {}",
					blocks_to_download.len(),
					blocks_downloading.len(),
				);
				blocks_to_download.len() > 0 || blocks_downloading.len() > 0
			};

			{
				let last_header_req = self.last_header_req.lock().unwrap().clone();
				if more_headers || (Instant::now() - Duration::from_secs(30) > last_header_req) {
					self.request_headers()?;
				}
			}
			if more_bodies {
				self.request_bodies();
			}
			if !more_headers && !more_bodies {
				// TODO check we haven't been lied to on the total work
				let mut sync = self.sync.lock().unwrap();
				*sync = false;
				break;
			}

			thread::sleep(Duration::from_secs(2));
		}
		info!(LOGGER, "Sync: done.");
		Ok(())
	}

	/// Checks the gap between the header chain and the full block chain and
	/// initializes the blocks_to_download structure with the missing full
	/// blocks
	fn init_download(&self) -> Result<(), Error> {
		// compare the header's head to the full one to see what we're missing
		let header_head = self.chain.get_header_head()?;
		let full_head = self.chain.head()?;
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();

		// go back the chain and insert for download all blocks we only have the
		// head for
		let mut prev_h = header_head.last_block_h;
		while prev_h != full_head.last_block_h {
			let header = self.chain.get_block_header(&prev_h)?;
			if header.height < full_head.height {
				break;
			}
			blocks_to_download.push(header.hash());
			prev_h = header.previous;
		}

		debug!(
			LOGGER,
			"Sync: Added {} full block hashes to download.",
			blocks_to_download.len()
		);
		Ok(())
	}

	/// Asks for the blocks we haven't downloaded yet and place them in the
	/// downloading structure.
	fn request_bodies(&self) {
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();
		let mut blocks_downloading = self.blocks_downloading.lock().unwrap();

		// retry blocks not downloading
		let now = Instant::now();
		for download in blocks_downloading.deref_mut() {
			let elapsed = (now - download.start_time).as_secs();
			if download.retries >= 12 {
				panic!("Failed to download required block {}", download.hash);
			}
			if download.retries < (elapsed / 5) as u8 {
				debug!(
					LOGGER,
					"Sync: Retry {} on block {}",
					download.retries,
					download.hash
				);
				self.request_block(download.hash);
				download.retries += 1;
			}
		}

		// consume hashes from blocks to download, place them in downloading and
		// request them from the network
		let mut count = 0;
		while blocks_to_download.len() > 0 && blocks_downloading.len() < MAX_BODY_DOWNLOADS {
			let h = blocks_to_download.pop().unwrap();
			self.request_block(h);
			count += 1;
			blocks_downloading.push(BlockDownload {
				hash: h,
				start_time: Instant::now(),
				retries: 0,
			});
		}
		debug!(
			LOGGER,
			"Sync: Requested {} full blocks to download, total left: {}. Current list: {:?}.",
			count,
			blocks_to_download.len(),
			blocks_downloading.deref(),
		);
	}

	/// We added a block, clean up the downloading structure
	pub fn block_received(&self, bh: Hash) {
		// just clean up the downloading list
		let mut bds = self.blocks_downloading.lock().unwrap();
		bds.iter()
			.position(|ref h| h.hash == bh)
			.map(|n| bds.remove(n));
	}

	/// Request some block headers from a peer to advance us
	fn request_headers(&self) -> Result<(), Error> {
		{
			let mut last_header_req = self.last_header_req.lock().unwrap();
			*last_header_req = Instant::now();
		}

		let tip = self.chain.get_header_head()?;
		let peer = self.p2p.most_work_peer();
		let locator = self.get_locator(&tip)?;
		if let Some(p) = peer {
			let p = p.read().unwrap();
			debug!(
				LOGGER,
				"Sync: Asking peer {} for more block headers, locator: {:?}",
				p.info.addr,
				locator,
			);
			if let Err(e) = p.send_header_request(locator) {
				debug!(LOGGER, "Sync: peer error, will retry");
			}
		} else {
			warn!(LOGGER, "Sync: Could not get most worked peer to request headers.");
		}
		Ok(())
	}

	/// We added a header, add it to the full block download list
	pub fn headers_received(&self, bhs: Vec<Hash>) {
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();
		let hs_len = bhs.len();
		for h in bhs {
			// enlist for full block download
			blocks_to_download.insert(0, h);
		}
		// ask for more headers if we got as many as required
		if hs_len == (p2p::MAX_BLOCK_HEADERS as usize) {
			self.request_headers().unwrap();
		}
	}

	/// Builds a vector of block hashes that should help the remote peer sending
	/// us the right block headers.
	fn get_locator(&self, tip: &chain::Tip) -> Result<Vec<Hash>, Error> {
		// Prepare the heights we want as the latests height minus increasing powers
		// of 2 up to max.
		let mut heights = vec![tip.height];
		let mut tail = (1..p2p::MAX_LOCATORS)
			.map(|n| 2u64.pow(n))
			.filter_map(|n| if n > tip.height {
				None
			} else {
				Some(tip.height - n)
			})
			.collect::<Vec<_>>();
		heights.append(&mut tail);

		// Include the genesis block (height 0) here as a fallback to guarantee
		// both nodes share at least one common header hash in the locator
		heights.push(0);

		debug!(LOGGER, "Sync: Loc heights: {:?}", heights);

		// Iteratively travel the header chain back from our head and retain the
		// headers at the wanted heights.
		let mut header = self.chain.get_block_header(&tip.last_block_h)?;
		let mut locator = vec![];
		while heights.len() > 0 {
			if header.height == heights[0] {
				heights = heights[1..].to_vec();
				locator.push(header.hash());
			}
			if header.height > 0 {
				header = self.chain.get_block_header(&header.previous)?;
			}
		}
		Ok(locator)
	}

	/// Pick a random peer and ask for a block by hash
	fn request_block(&self, h: Hash) {
		let peer = self.p2p.random_peer().unwrap();
		let peer = peer.read().unwrap();
		if let Err(e) = peer.send_block_request(h) {
			debug!(LOGGER, "Sync: Error requesting block: {:?}", e);
		}
	}
}
<commit_msg>More explicit panic when syn can't get a peer<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.

//! Synchronization of the local blockchain with the rest of the network. Used
//! either on a brand new node or when a node is late based on others' heads.
//! Always starts by downloading the header chain before asking either for full
//! blocks or a full UTXO set with related information.

/// How many block bodies to download in parallel
const MAX_BODY_DOWNLOADS: usize = 8;

use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};

use core::core::hash::{Hash, Hashed};
use chain;
use p2p;
use types::Error;
use util::LOGGER;

#[derive(Debug)]
struct BlockDownload {
	hash: Hash,
	start_time: Instant,
	retries: u8,
}

/// Manages syncing the local chain with other peers. Needs both a head chain
/// and a full block chain to operate. First tries to advance the header
/// chain as much as possible, then downloads the full blocks by batches.
pub struct Syncer {
	chain: Arc<chain::Chain>,
	p2p: Arc<p2p::Server>,

	sync: Mutex<bool>,
	last_header_req: Mutex<Instant>,
	blocks_to_download: Mutex<Vec<Hash>>,
	blocks_downloading: Mutex<Vec<BlockDownload>>,
}

impl Syncer {
	pub fn new(chain_ref: Arc<chain::Chain>, p2p: Arc<p2p::Server>) -> Syncer {
		Syncer {
			chain: chain_ref,
			p2p: p2p,
			sync: Mutex::new(true),
			last_header_req: Mutex::new(Instant::now() - Duration::from_secs(2)),
			blocks_to_download: Mutex::new(vec![]),
			blocks_downloading: Mutex::new(vec![]),
		}
	}

	pub fn syncing(&self) -> bool {
		*self.sync.lock().unwrap()
	}

	/// Checks the local chain state, comparing it with our peers and triggers
	/// syncing if required.
	pub fn run(&self) -> Result<(), Error> {
		info!(LOGGER, "Sync: starting sync");

		// Loop for 10s waiting for some peers to potentially sync from.
		let start = Instant::now();
		loop {
			let pc = self.p2p.peer_count();
			if pc > 3 {
				break;
			}
			if Instant::now() - start > Duration::from_secs(10) {
				break;
			}
			thread::sleep(Duration::from_millis(200));
		}

		// Now check we actually have at least one peer to sync from.
		// If not then end the sync cleanly.
		if self.p2p.peer_count() == 0 {
			info!(LOGGER, "Sync: no peers to sync with, done.");

			let mut sync = self.sync.lock().unwrap();
			*sync = false;

			return Ok(())
		}

		// check if we have missing full blocks for which we already have a header
		self.init_download()?;

		// main syncing loop, requests more headers and bodies periodically as long
		// as a peer with higher difficulty exists and we're not fully caught up
		info!(LOGGER, "Sync: Starting loop.");
		loop {
			let tip = self.chain.get_header_head()?;

			// TODO do something better (like trying to get more) if we lose peers
			let peer = self.p2p.most_work_peer().expect("No peers available for sync.");
			let peer = peer.read().unwrap();
			debug!(
				LOGGER,
				"Sync: peer {} vs us {}",
				peer.info.total_difficulty,
				tip.total_difficulty
			);

			let more_headers = peer.info.total_difficulty > tip.total_difficulty;
			let more_bodies = {
				let blocks_to_download = self.blocks_to_download.lock().unwrap();
				let blocks_downloading = self.blocks_downloading.lock().unwrap();
				debug!(
					LOGGER,
					"Sync: blocks to download {}, block downloading {}",
					blocks_to_download.len(),
					blocks_downloading.len(),
				);
				blocks_to_download.len() > 0 || blocks_downloading.len() > 0
			};

			{
				let last_header_req = self.last_header_req.lock().unwrap().clone();
				if more_headers || (Instant::now() - Duration::from_secs(30) > last_header_req) {
					self.request_headers()?;
				}
			}
			if more_bodies {
				self.request_bodies();
			}
			if !more_headers && !more_bodies {
				// TODO check we haven't been lied to on the total work
				let mut sync = self.sync.lock().unwrap();
				*sync = false;
				break;
			}

			thread::sleep(Duration::from_secs(2));
		}
		info!(LOGGER, "Sync: done.");
		Ok(())
	}

	/// Checks the gap between the header chain and the full block chain and
	/// initializes the blocks_to_download structure with the missing full
	/// blocks
	fn init_download(&self) -> Result<(), Error> {
		// compare the header's head to the full one to see what we're missing
		let header_head = self.chain.get_header_head()?;
		let full_head = self.chain.head()?;
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();

		// go back the chain and insert for download all blocks we only have the
		// head for
		let mut prev_h = header_head.last_block_h;
		while prev_h != full_head.last_block_h {
			let header = self.chain.get_block_header(&prev_h)?;
			if header.height < full_head.height {
				break;
			}
			blocks_to_download.push(header.hash());
			prev_h = header.previous;
		}

		debug!(
			LOGGER,
			"Sync: Added {} full block hashes to download.",
			blocks_to_download.len()
		);
		Ok(())
	}

	/// Asks for the blocks we haven't downloaded yet and place them in the
	/// downloading structure.
	fn request_bodies(&self) {
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();
		let mut blocks_downloading = self.blocks_downloading.lock().unwrap();

		// retry blocks not downloading
		let now = Instant::now();
		for download in blocks_downloading.deref_mut() {
			let elapsed = (now - download.start_time).as_secs();
			if download.retries >= 12 {
				panic!("Failed to download required block {}", download.hash);
			}
			if download.retries < (elapsed / 5) as u8 {
				debug!(
					LOGGER,
					"Sync: Retry {} on block {}",
					download.retries,
					download.hash
				);
				self.request_block(download.hash);
				download.retries += 1;
			}
		}

		// consume hashes from blocks to download, place them in downloading and
		// request them from the network
		let mut count = 0;
		while blocks_to_download.len() > 0 && blocks_downloading.len() < MAX_BODY_DOWNLOADS {
			let h = blocks_to_download.pop().unwrap();
			self.request_block(h);
			count += 1;
			blocks_downloading.push(BlockDownload {
				hash: h,
				start_time: Instant::now(),
				retries: 0,
			});
		}
		debug!(
			LOGGER,
			"Sync: Requested {} full blocks to download, total left: {}. Current list: {:?}.",
			count,
			blocks_to_download.len(),
			blocks_downloading.deref(),
		);
	}

	/// We added a block, clean up the downloading structure
	pub fn block_received(&self, bh: Hash) {
		// just clean up the downloading list
		let mut bds = self.blocks_downloading.lock().unwrap();
		bds.iter()
			.position(|ref h| h.hash == bh)
			.map(|n| bds.remove(n));
	}

	/// Request some block headers from a peer to advance us
	fn request_headers(&self) -> Result<(), Error> {
		{
			let mut last_header_req = self.last_header_req.lock().unwrap();
			*last_header_req = Instant::now();
		}

		let tip = self.chain.get_header_head()?;
		let peer = self.p2p.most_work_peer();
		let locator = self.get_locator(&tip)?;
		if let Some(p) = peer {
			let p = p.read().unwrap();
			debug!(
				LOGGER,
				"Sync: Asking peer {} for more block headers, locator: {:?}",
				p.info.addr,
				locator,
			);
			if let Err(e) = p.send_header_request(locator) {
				debug!(LOGGER, "Sync: peer error, will retry");
			}
		} else {
			warn!(LOGGER, "Sync: Could not get most worked peer to request headers.");
		}
		Ok(())
	}

	/// We added a header, add it to the full block download list
	pub fn headers_received(&self, bhs: Vec<Hash>) {
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();
		let hs_len = bhs.len();
		for h in bhs {
			// enlist for full block download
			blocks_to_download.insert(0, h);
		}
		// ask for more headers if we got as many as required
		if hs_len == (p2p::MAX_BLOCK_HEADERS as usize) {
			self.request_headers().unwrap();
		}
	}

	/// Builds a vector of block hashes that should help the remote peer sending
	/// us the right block headers.
	fn get_locator(&self, tip: &chain::Tip) -> Result<Vec<Hash>, Error> {
		// Prepare the heights we want as the latests height minus increasing powers
		// of 2 up to max.
		let mut heights = vec![tip.height];
		let mut tail = (1..p2p::MAX_LOCATORS)
			.map(|n| 2u64.pow(n))
			.filter_map(|n| if n > tip.height {
				None
			} else {
				Some(tip.height - n)
			})
			.collect::<Vec<_>>();
		heights.append(&mut tail);

		// Include the genesis block (height 0) here as a fallback to guarantee
		// both nodes share at least one common header hash in the locator
		heights.push(0);

		debug!(LOGGER, "Sync: Loc heights: {:?}", heights);

		// Iteratively travel the header chain back from our head and retain the
		// headers at the wanted heights.
		let mut header = self.chain.get_block_header(&tip.last_block_h)?;
		let mut locator = vec![];
		while heights.len() > 0 {
			if header.height == heights[0] {
				heights = heights[1..].to_vec();
				locator.push(header.hash());
			}
			if header.height > 0 {
				header = self.chain.get_block_header(&header.previous)?;
			}
		}
		Ok(locator)
	}

	/// Pick a random peer and ask for a block by hash
	fn request_block(&self, h: Hash) {
		let peer = self.p2p.random_peer().expect("No connected peer.");
		let peer = peer.read().unwrap();
		if let Err(e) = peer.send_block_request(h) {
			debug!(LOGGER, "Sync: Error requesting block: {:?}", e);
		}
	}
}
<|endoftext|>


<commit_before>// (c) 2016 Productize SPRL <joost@productize.be>

use super::*;
use ::formatter;

#[allow(dead_code)]
fn check_parse_res(s: &str, o:&str) {
    let e = parser::parse_str(s).unwrap();
    let t = ser::to_string(&e).unwrap();
    assert_eq!(o, t)
}

#[allow(dead_code)]
fn check_parse(s: &str) {
    let e = parser::parse_str(s).unwrap();
    let t = ser::to_string(&e).unwrap();
    assert_eq!(s, t)
}

#[allow(dead_code)]
fn check_parse_kicad(s: &str) {
    let e = parser::parse_str(s).unwrap();
    let t = ser::to_rules_string(&e, kicad_test_rules()).unwrap();
    assert_eq!(s, t)
}

#[allow(dead_code)]
fn check_parse_rules(s: &str, rules:formatter::Rules) {
    let e = parser::parse_str(s).unwrap();
    let t = ser::to_rules_string(&e, rules).unwrap();
    assert_eq!(s, t)
}

#[allow(dead_code)]
fn parse_fail(s: &str) {
    parser::parse_str(s).unwrap();
}

#[allow(dead_code)]
pub fn kicad_test_rules() -> formatter::Rules {
    let mut rf = formatter::Rules::new();
    rf.insert("layer", 1);
    rf.insert("desc", 1);
    rf.insert("fp_text", 1);
    rf.insert("fp_poly", 1);
    rf.insert("fp_line", 1);
    rf.insert("pad", 1);
    rf.insert("general", 1);
    rf
}

#[test]
fn test_empty() { check_parse("") }

#[test]
fn test_empty_qstring() { check_parse("(hello \"\")") }

#[test]
fn test_minimal() { check_parse("()") }

#[test]
fn test_string() { check_parse("hello") }

#[test]
fn test_qstring_a() { check_parse_res("\"hello\"", "hello") }

#[test]
fn test_qstring_a2() { check_parse("\"hello world\"") }

#[test]
fn test_qstring_a3() { check_parse("\"hello(world)\"") }

#[test]
fn test_number() { check_parse("1.3") }

#[test]
fn test_float_vs_int() { check_parse("2.0") }

#[test]
fn test_double() { check_parse("(())") }

#[test]
fn test_br_string() { check_parse("(world)") }

#[test]
fn test_br_qstring() { check_parse_res("(\"world\")", "(world)") }

#[test]
fn test_br_int() { check_parse("(42)") }

#[test]
fn test_br_float() { check_parse("(12.7)") }

#[test]
fn test_br_qbrstring() { check_parse("(\"(()\")") }

#[test]
fn test_number_string() { check_parse("567A_WZ") }

#[test]
#[should_panic(expected="called `Result::unwrap()` on an `Err` value: Other(\"incomplete: Size(2)\")")]
fn test_invalid1() { parse_fail("(") }

#[test]
#[should_panic(expected="called `Result::unwrap()` on an `Err` value: Other(\"parse error: Alt |)|\")")]
fn test_invalid2() { parse_fail(")") }

#[test]
#[should_panic(expected="incomplete: Size")]
fn test_invalid3() { parse_fail("\"hello") }

#[test]
fn test_complex() { check_parse("(module \"SWITCH_3W_SIDE_MMP221-R\" (layer F.Cu) (descr \"\") (pad 1 thru_hole rect (size 1.2 1.2) (at -2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 2 thru_hole rect (size 1.2 1.2) (at 0.0 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 3 thru_hole rect (size 1.2 1.2) (at 2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 5 thru_hole rect (size 1.2 1.2) (at 0.0 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 6 thru_hole rect (size 1.2 1.2) (at -2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 4 thru_hole rect (size 1.2 1.2) (at 2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (fp_line (start -4.5 -1.75) (end 4.5 -1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 -1.75) (end 4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 1.75) (end -4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start -4.5 1.75) (end -4.5 -1.75) (layer F.SilkS) (width 0.127)))") }

#[test]
fn test_kicad_1() {
    check_parse_kicad("(module SILABS_EFM32_QFM24
  (layer F.Cu))")
}

#[test]
fn test_multiline() {
    let mut rules = formatter::Rules::new();
    rules.insert("foo",1);
    rules.insert("mars",1);
    check_parse_rules("\
(hello \"test it\"
  (foo bar)
  (mars venus))", rules)
}

#[test]
fn test_multiline_two_empty() {
    check_parse_res("\
(hello

world)", "(hello world)")
}

#[test]
fn test_fail_pcb() {
        check_parse_kicad("\
(kicad_pcb (version 4) (host pcbnew \"(2015-05-31 BZR 5692)-product\")
  (general))")
}
<commit_msg>fix unit tests<commit_after>// (c) 2016 Productize SPRL <joost@productize.be>

use super::*;
use ::formatter;

#[allow(dead_code)]
fn check_parse_res(s: &str, o:&str) {
    let e = parser::parse_str(s).unwrap();
    let t = ser::to_string(&e).unwrap();
    assert_eq!(o, t)
}

#[allow(dead_code)]
fn check_parse(s: &str) {
    let e = parser::parse_str(s).unwrap();
    let t = ser::to_string(&e).unwrap();
    assert_eq!(s, t)
}

#[allow(dead_code)]
fn check_parse_kicad(s: &str) {
    let e = parser::parse_str(s).unwrap();
    let t = ser::to_string_with_rules(&e, kicad_test_rules()).unwrap();
    assert_eq!(s, t)
}

#[allow(dead_code)]
fn check_parse_rules(s: &str, rules:formatter::Rules) {
    let e = parser::parse_str(s).unwrap();
    let t = ser::to_string_with_rules(&e, rules).unwrap();
    assert_eq!(s, t)
}

#[allow(dead_code)]
fn parse_fail(s: &str) {
    parser::parse_str(s).unwrap();
}

#[allow(dead_code)]
pub fn kicad_test_rules() -> formatter::Rules {
    let mut rf = formatter::Rules::new();
    rf.insert("layer", 1);
    rf.insert("desc", 1);
    rf.insert("fp_text", 1);
    rf.insert("fp_poly", 1);
    rf.insert("fp_line", 1);
    rf.insert("pad", 1);
    rf.insert("general", 1);
    rf
}

#[test]
fn test_empty() { check_parse("") }

#[test]
fn test_empty_qstring() { check_parse("(hello \"\")") }

#[test]
fn test_minimal() { check_parse("()") }

#[test]
fn test_string() { check_parse("hello") }

#[test]
fn test_qstring_a() { check_parse_res("\"hello\"", "hello") }

#[test]
fn test_qstring_a2() { check_parse("\"hello world\"") }

#[test]
fn test_qstring_a3() { check_parse("\"hello(world)\"") }

#[test]
fn test_number() { check_parse("1.3") }

#[test]
fn test_float_vs_int() { check_parse("2.0") }

#[test]
fn test_double() { check_parse("(())") }

#[test]
fn test_br_string() { check_parse("(world)") }

#[test]
fn test_br_qstring() { check_parse_res("(\"world\")", "(world)") }

#[test]
fn test_br_int() { check_parse("(42)") }

#[test]
fn test_br_float() { check_parse("(12.7)") }

#[test]
fn test_br_qbrstring() { check_parse("(\"(()\")") }

#[test]
fn test_number_string() { check_parse("567A_WZ") }

#[test]
#[should_panic(expected="called `Result::unwrap()` on an `Err` value: Other(\"incomplete: Size(2)\")")]
fn test_invalid1() { parse_fail("(") }

#[test]
#[should_panic(expected="called `Result::unwrap()` on an `Err` value: Other(\"parse error: Alt |)|\")")]
fn test_invalid2() { parse_fail(")") }

#[test]
#[should_panic(expected="incomplete: Size")]
fn test_invalid3() { parse_fail("\"hello") }

#[test]
fn test_complex() { check_parse("(module \"SWITCH_3W_SIDE_MMP221-R\" (layer F.Cu) (descr \"\") (pad 1 thru_hole rect (size 1.2 1.2) (at -2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 2 thru_hole rect (size 1.2 1.2) (at 0.0 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 3 thru_hole rect (size 1.2 1.2) (at 2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 5 thru_hole rect (size 1.2 1.2) (at 0.0 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 6 thru_hole rect (size 1.2 1.2) (at -2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 4 thru_hole rect (size 1.2 1.2) (at 2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (fp_line (start -4.5 -1.75) (end 4.5 -1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 -1.75) (end 4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 1.75) (end -4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start -4.5 1.75) (end -4.5 -1.75) (layer F.SilkS) (width 0.127)))") }

#[test]
fn test_kicad_1() {
    check_parse_kicad("(module SILABS_EFM32_QFM24
  (layer F.Cu))")
}

#[test]
fn test_multiline() {
    let mut rules = formatter::Rules::new();
    rules.insert("foo",1);
    rules.insert("mars",1);
    check_parse_rules("\
(hello \"test it\"
  (foo bar)
  (mars venus))", rules)
}

#[test]
fn test_multiline_two_empty() {
    check_parse_res("\
(hello

world)", "(hello world)")
}

#[test]
fn test_fail_pcb() {
        check_parse_kicad("\
(kicad_pcb (version 4) (host pcbnew \"(2015-05-31 BZR 5692)-product\")
  (general))")
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use ffi;
use types::{gchar,gsize};
use types::{gpointer};

use libc;
use libc::c_char;
use std::c_str::{CString,ToCStr};
use std::kinds::marker;
use std::mem::transmute;
use std::ptr::copy_nonoverlapping_memory;
use std::slice;
use std::str;
use std::string;

pub struct UTF8Chars<'a> {
    data: *const gchar,
    lifetime: marker::ContravariantLifetime<'a>
}

impl<'a> UTF8Chars<'a> {
    pub unsafe fn wrap(ptr: *const gchar) -> UTF8Chars<'a> {
        UTF8Chars { data: ptr, lifetime: marker::ContravariantLifetime }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf(self.data as *const u8)
        }
    }
}

#[inline]
unsafe fn utf8_cont_bits(p: *const gchar) -> u32 {
    let byte = *(p as *const u8);
    debug_assert!((byte & 0xC0) == 0x80);
    (byte & 0x3F) as u32
}

impl<'a> Iterator<char> for UTF8Chars<'a> {
    fn next(&mut self) -> Option<char> {
        let p = self.data;
        let first_byte = unsafe { *(p as *const u8) };
        if first_byte == 0 {
            return None;
        }
        unsafe {
            let mut wc: u32;
            if first_byte < 0xC0 {
                debug_assert!(first_byte < 0x80);
                wc = first_byte as u32;
                self.data = p.offset(1);
            } else {
                let c1 = utf8_cont_bits(p.offset(1));
                if first_byte < 0xE0 {
                    wc = ((first_byte & 0x1F) as u32 << 6) | c1;
                    debug_assert!(wc >= 0x80);
                    self.data = p.offset(2);
                } else {
                    let c2 = utf8_cont_bits(p.offset(2));
                    if first_byte < 0xF0 {
                        wc = ((first_byte & 0x0F) as u32 << 12)
                             | (c1 << 6) | c2;
                        debug_assert!(wc >= 0x0800);
                        debug_assert!((wc & 0xF800) != 0xD800);
                        self.data = p.offset(3);
                    } else {
                        debug_assert!(first_byte <= 0xF4);
                        let c3 = utf8_cont_bits(p.offset(3));
                        wc = ((first_byte & 0x07) as u32 << 18)
                             | (c1 << 12) | (c2 << 6) | c3;
                        debug_assert!(wc >= 0x010000 && wc <= 0x10FFFF);
                        self.data = p.offset(4);
                    }
                }
            }
            Some(transmute(wc))
        }
    }
}

unsafe fn dup_to_c_str(source: *const c_char, len: uint) -> CString {
    let copy = libc::malloc(len as libc::size_t + 1) as *mut c_char;
    copy_nonoverlapping_memory(copy, source, len + 1);
    CString::new(copy as *const c_char, true)
}

impl<'a> ToCStr for UTF8Chars<'a> {

    #[inline]
    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        let src = self.data as *const c_char;
        let len = libc::strlen(src) as uint;
        dup_to_c_str(src, len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Buf {
    data: *mut gchar,
}

impl UTF8Buf {

    pub unsafe fn wrap(data: *mut gchar) -> UTF8Buf {
        UTF8Buf { data: data }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> {
        unsafe { UTF8Chars::wrap(self.data as *const gchar) }
    }

    pub fn into_collection(self) -> UTF8Str {
        unsafe {
            let len = libc::strlen(self.data as *const c_char);
            UTF8Str { buf: transmute(self), len: len as uint }
        }
    }

    #[inline]
    pub fn to_string(&self) -> String { self.chars().to_string() }

    #[inline]
    pub fn to_owned(&self) -> String { self.to_string() }

    #[inline]
    pub fn into_string(self) -> String { self.to_string() }

    #[inline]
    pub fn into_owned(self) -> String { self.to_string() }

    pub fn is_empty(&self) -> bool { unsafe { *self.data == 0 } }
}

impl Drop for UTF8Buf {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.data as gpointer) }
    }
}

impl Clone for UTF8Buf {
    fn clone(&self) -> UTF8Buf {
        unsafe {
            UTF8Buf::wrap(ffi::g_strdup(self.data as *const gchar))
        }
    }
}

impl ToCStr for UTF8Buf {

    #[inline]
    fn to_c_str(&self) -> CString {
        self.chars().to_c_str()
    }

    #[inline]
    unsafe fn to_c_str_unchecked(&self) -> CString {
        self.chars().to_c_str_unchecked()
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Str {
    buf: UTF8Buf,
    len: uint
}

static NUL: gchar = 0;

impl UTF8Str {

    pub unsafe fn wrap(data: *mut gchar, len: uint) -> UTF8Str {
        UTF8Str { buf: UTF8Buf::wrap(data), len: len }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> { self.buf.chars() }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf_len(self.buf.data as *const u8, self.len)
        }
    }
}

impl Clone for UTF8Str {
    fn clone(&self) -> UTF8Str {
        unsafe {
            let copy = ffi::g_malloc((self.len + 1) as gsize) as *mut gchar;
            copy_nonoverlapping_memory(copy,
                    self.buf.data as *const gchar, self.len);
            *copy.offset(self.len as int) = NUL;
            UTF8Str::wrap(copy, self.len)
        }
    }
}

impl Str for UTF8Str {
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            slice::raw::buf_as_slice(
                self.buf.data as *const u8,
                self.len,
                |bytes| {
                    let s = str::raw::from_utf8(bytes);
                    transmute(s)
                })
        }
    }
}

impl StrAllocating for UTF8Str {
    fn into_string(self) -> String { self.to_string() }
}

impl Collection for UTF8Str {

    // Common sense says we should return the UTF-8 length,
    // but &str returns length in bytes, so...
    fn len(&self) -> uint { return self.len }

    fn is_empty(&self) -> bool { return self.len == 0 }
}

impl ToCStr for UTF8Str {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.buf.data as *const c_char, self.len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str(f)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str_unchecked(f)
    }
}

impl PartialEq for UTF8Str {
    fn eq(&self, other: &UTF8Str) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl Eq for UTF8Str { }

impl<S: Str> Equiv<S> for UTF8Str {
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

pub trait WithUTF8 {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T;
}

impl<'a> WithUTF8 for UTF8Chars<'a> {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data)
    }
}

impl WithUTF8 for UTF8Buf {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data as *const gchar)
    }
}

impl WithUTF8 for UTF8Str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.buf.with_utf8_c_str(f)
    }
}

impl<'a> WithUTF8 for &'a str {

    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}

impl WithUTF8 for String {

    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}
<commit_msg>utf8: Remove .to_owned() and .into_owned()<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use ffi;
use types::{gchar,gsize};
use types::{gpointer};

use libc;
use libc::c_char;
use std::c_str::{CString,ToCStr};
use std::kinds::marker;
use std::mem::transmute;
use std::ptr::copy_nonoverlapping_memory;
use std::slice;
use std::str;
use std::string;

pub struct UTF8Chars<'a> {
    data: *const gchar,
    lifetime: marker::ContravariantLifetime<'a>
}

impl<'a> UTF8Chars<'a> {
    pub unsafe fn wrap(ptr: *const gchar) -> UTF8Chars<'a> {
        UTF8Chars { data: ptr, lifetime: marker::ContravariantLifetime }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf(self.data as *const u8)
        }
    }
}

#[inline]
unsafe fn utf8_cont_bits(p: *const gchar) -> u32 {
    let byte = *(p as *const u8);
    debug_assert!((byte & 0xC0) == 0x80);
    (byte & 0x3F) as u32
}

impl<'a> Iterator<char> for UTF8Chars<'a> {
    fn next(&mut self) -> Option<char> {
        let p = self.data;
        let first_byte = unsafe { *(p as *const u8) };
        if first_byte == 0 {
            return None;
        }
        unsafe {
            let mut wc: u32;
            if first_byte < 0xC0 {
                debug_assert!(first_byte < 0x80);
                wc = first_byte as u32;
                self.data = p.offset(1);
            } else {
                let c1 = utf8_cont_bits(p.offset(1));
                if first_byte < 0xE0 {
                    wc = ((first_byte & 0x1F) as u32 << 6) | c1;
                    debug_assert!(wc >= 0x80);
                    self.data = p.offset(2);
                } else {
                    let c2 = utf8_cont_bits(p.offset(2));
                    if first_byte < 0xF0 {
                        wc = ((first_byte & 0x0F) as u32 << 12)
                             | (c1 << 6) | c2;
                        debug_assert!(wc >= 0x0800);
                        debug_assert!((wc & 0xF800) != 0xD800);
                        self.data = p.offset(3);
                    } else {
                        debug_assert!(first_byte <= 0xF4);
                        let c3 = utf8_cont_bits(p.offset(3));
                        wc = ((first_byte & 0x07) as u32 << 18)
                             | (c1 << 12) | (c2 << 6) | c3;
                        debug_assert!(wc >= 0x010000 && wc <= 0x10FFFF);
                        self.data = p.offset(4);
                    }
                }
            }
            Some(transmute(wc))
        }
    }
}

unsafe fn dup_to_c_str(source: *const c_char, len: uint) -> CString {
    let copy = libc::malloc(len as libc::size_t + 1) as *mut c_char;
    copy_nonoverlapping_memory(copy, source, len + 1);
    CString::new(copy as *const c_char, true)
}

impl<'a> ToCStr for UTF8Chars<'a> {

    #[inline]
    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        let src = self.data as *const c_char;
        let len = libc::strlen(src) as uint;
        dup_to_c_str(src, len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Buf {
    data: *mut gchar,
}

impl UTF8Buf {

    pub unsafe fn wrap(data: *mut gchar) -> UTF8Buf {
        UTF8Buf { data: data }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> {
        unsafe { UTF8Chars::wrap(self.data as *const gchar) }
    }

    pub fn into_collection(self) -> UTF8Str {
        unsafe {
            let len = libc::strlen(self.data as *const c_char);
            UTF8Str { buf: transmute(self), len: len as uint }
        }
    }

    #[inline]
    pub fn to_string(&self) -> String { self.chars().to_string() }

    #[inline]
    pub fn into_string(self) -> String { self.to_string() }

    pub fn is_empty(&self) -> bool { unsafe { *self.data == 0 } }
}

impl Drop for UTF8Buf {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.data as gpointer) }
    }
}

impl Clone for UTF8Buf {
    fn clone(&self) -> UTF8Buf {
        unsafe {
            UTF8Buf::wrap(ffi::g_strdup(self.data as *const gchar))
        }
    }
}

impl ToCStr for UTF8Buf {

    #[inline]
    fn to_c_str(&self) -> CString {
        self.chars().to_c_str()
    }

    #[inline]
    unsafe fn to_c_str_unchecked(&self) -> CString {
        self.chars().to_c_str_unchecked()
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Str {
    buf: UTF8Buf,
    len: uint
}

static NUL: gchar = 0;

impl UTF8Str {

    pub unsafe fn wrap(data: *mut gchar, len: uint) -> UTF8Str {
        UTF8Str { buf: UTF8Buf::wrap(data), len: len }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> { self.buf.chars() }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf_len(self.buf.data as *const u8, self.len)
        }
    }
}

impl Clone for UTF8Str {
    fn clone(&self) -> UTF8Str {
        unsafe {
            let copy = ffi::g_malloc((self.len + 1) as gsize) as *mut gchar;
            copy_nonoverlapping_memory(copy,
                    self.buf.data as *const gchar, self.len);
            *copy.offset(self.len as int) = NUL;
            UTF8Str::wrap(copy, self.len)
        }
    }
}

impl Str for UTF8Str {
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            slice::raw::buf_as_slice(
                self.buf.data as *const u8,
                self.len,
                |bytes| {
                    let s = str::raw::from_utf8(bytes);
                    transmute(s)
                })
        }
    }
}

impl StrAllocating for UTF8Str {
    fn into_string(self) -> String { self.to_string() }
}

impl Collection for UTF8Str {

    // Common sense says we should return the UTF-8 length,
    // but &str returns length in bytes, so...
    fn len(&self) -> uint { return self.len }

    fn is_empty(&self) -> bool { return self.len == 0 }
}

impl ToCStr for UTF8Str {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.buf.data as *const c_char, self.len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str(f)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str_unchecked(f)
    }
}

impl PartialEq for UTF8Str {
    fn eq(&self, other: &UTF8Str) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl Eq for UTF8Str { }

impl<S: Str> Equiv<S> for UTF8Str {
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

pub trait WithUTF8 {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T;
}

impl<'a> WithUTF8 for UTF8Chars<'a> {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data)
    }
}

impl WithUTF8 for UTF8Buf {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data as *const gchar)
    }
}

impl WithUTF8 for UTF8Str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.buf.with_utf8_c_str(f)
    }
}

impl<'a> WithUTF8 for &'a str {

    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}

impl WithUTF8 for String {

    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}
<|endoftext|>


<commit_before>use anyhow::Result;
use shellexpand;
use std::borrow::Borrow;
use std::fs;
use std::path::{Path, PathBuf};

pub fn make_path_buf<S: AsRef<str>>(s: S) -> Result<PathBuf> {
    shellexpand::full(s.as_ref())
        .map(|s| PathBuf::from(s.borrow() as &str))
        .map_err(Into::into)
}

#[cfg(windows)]
pub fn canonicalize_pretty<P: AsRef<Path>>(path: P) -> Fallible<PathBuf> {
    path.as_ref()
        .canonicalize()
        .map_err(Into::into)
        .map(|path| {
            path.to_string_lossy()
                .trim_left_matches(r"\\?\")
                .replace(r"\", "/")
        })
        .map(|s| PathBuf::from(s))
}

#[cfg(not(windows))]
pub fn canonicalize_pretty<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
    path.as_ref().canonicalize().map_err(Into::into)
}

pub trait StrSkip {
    fn skip(&self, n: usize) -> &str;
}

impl StrSkip for str {
    fn skip(&self, n: usize) -> &str {
        let mut s = self.chars();
        for _ in 0..n {
            s.next();
        }
        s.as_str()
    }
}

#[test]
fn test_skipped_1() {
    assert_eq!("hoge".skip(1), "oge");
    assert_eq!("あいueo".skip(1), "いueo");
}

pub fn write_content<P, F>(path: P, write_fn: F) -> Result<()>
where
    P: AsRef<Path>,
    F: FnOnce(&mut fs::File) -> Result<()>,
{
    fs::create_dir_all(path.as_ref().parent().unwrap())?;
    let mut file = fs::OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(&path)?;
    write_fn(&mut file)
}

pub mod process {
    use std::process::{Command, Stdio};

    pub fn inherit(name: &str) -> Command {
        let mut command = Command::new(name);
        command.stdin(Stdio::inherit());
        command.stdout(Stdio::inherit());
        command.stderr(Stdio::inherit());
        command
    }

    pub fn piped(name: &str) -> Command {
        let mut command = Command::new(name);
        command.stdin(Stdio::null());
        command.stdout(Stdio::piped());
        command.stderr(Stdio::piped());
        command
    }
}
<commit_msg>fix mistakes on Windows<commit_after>use anyhow::Result;
use shellexpand;
use std::borrow::Borrow;
use std::fs;
use std::path::{Path, PathBuf};

pub fn make_path_buf<S: AsRef<str>>(s: S) -> Result<PathBuf> {
    shellexpand::full(s.as_ref())
        .map(|s| PathBuf::from(s.borrow() as &str))
        .map_err(Into::into)
}

#[cfg(windows)]
pub fn canonicalize_pretty<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
    path.as_ref()
        .canonicalize()
        .map_err(Into::into)
        .map(|path| {
            path.to_string_lossy()
                .trim_start_matches(r"\\?\")
                .replace(r"\", "/")
        })
        .map(|s| PathBuf::from(s))
}

#[cfg(not(windows))]
pub fn canonicalize_pretty<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
    path.as_ref().canonicalize().map_err(Into::into)
}

pub trait StrSkip {
    fn skip(&self, n: usize) -> &str;
}

impl StrSkip for str {
    fn skip(&self, n: usize) -> &str {
        let mut s = self.chars();
        for _ in 0..n {
            s.next();
        }
        s.as_str()
    }
}

#[test]
fn test_skipped_1() {
    assert_eq!("hoge".skip(1), "oge");
    assert_eq!("あいueo".skip(1), "いueo");
}

pub fn write_content<P, F>(path: P, write_fn: F) -> Result<()>
where
    P: AsRef<Path>,
    F: FnOnce(&mut fs::File) -> Result<()>,
{
    fs::create_dir_all(path.as_ref().parent().unwrap())?;
    let mut file = fs::OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(&path)?;
    write_fn(&mut file)
}

pub mod process {
    use std::process::{Command, Stdio};

    pub fn inherit(name: &str) -> Command {
        let mut command = Command::new(name);
        command.stdin(Stdio::inherit());
        command.stdout(Stdio::inherit());
        command.stderr(Stdio::inherit());
        command
    }

    pub fn piped(name: &str) -> Command {
        let mut command = Command::new(name);
        command.stdin(Stdio::null());
        command.stdout(Stdio::piped());
        command.stderr(Stdio::piped());
        command
    }
}
<|endoftext|>


<commit_before>use ::*;
use relm::{Relm, RemoteRelm, Widget};
use gtk::prelude::*;
use gtk::{Window, WindowType, DrawingArea, Button};
use gtk::{FileChooserDialog};
use tokio_core::reactor::Interval;
use std::time::Duration;

use map::*;

#[derive(Clone)]
pub struct Model {
    map: Map,
    size: Pos,
    center: Pos,
    scale: i32,
}
impl Model {
    fn new() -> Self {
        Model {
            map: Map::acorn(),
            size: pos(250, 250),
            center: pos(0, 0),
            scale: 2,
        }
    }
}

#[derive(SimpleMsg)]
pub enum Msg {
    Motion(((f64, f64), u32)),
    Save,
    Open,
    Tick,
    Quit,
}

#[derive(Clone)]
pub struct Win {
    hbox: gtk::Box,
    button_box: gtk::ButtonBox,
    open_button: Button,
    save_button: Button,
    area: DrawingArea,
    window: Window,
}

impl Win {
    fn draw(&mut self, cells: Vec<&Pos>, model: &Model, top_left: &Pos) {
        use gdk::prelude::ContextExt;
        let cr = cairo::Context::create_from_window(&self.area.get_window().unwrap());
        cr.set_source_rgb(1., 1., 1.);
        cr.paint();
        cr.scale(model.scale as f64, model.scale as f64);
        cr.set_source_rgb(0., 0., 0.);
        for pos in cells {
            cr.rectangle((pos.x - top_left.x) as f64, (pos.y - top_left.y) as f64, 1., 1.);
        }
        cr.fill();
    }
}

impl Widget for Win {
    type Root = Window;
    type Model = Model;
    type Msg = Msg;

    fn root(&self) -> &Self::Root {
        &self.window
    }

    fn model() -> Self::Model {
        Model::new()
    }

    fn subscriptions(relm: &Relm<Msg>) {
        let stream = Interval::new(Duration::from_millis(30), relm.handle()).unwrap();
        relm.connect_exec_ignore_err(stream, Msg::Tick);
    }

    fn update(&mut self, event: Msg, model: &mut Self::Model) {
        match event {
            Msg::Tick => {
                model.map.next_generation();
                let top_left = pos(model.center.x - model.size.x / 2, model.center.y - model.size.y / 2);
                let cells = model.map.get_alive_cells_in(top_left.clone(), model.size.clone());
                self.draw(cells, model, &top_left);
            },
            Msg::Save => {
                let dialog = FileChooserDialog::new(
                    Some("Save File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Save);
                let cancel: i32 = gtk::ResponseType::Cancel.into();
                let accept: i32 = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Save", accept);
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        model.map.save(path).unwrap();
                    }
                }
                dialog.close();
            },
            Msg::Open => {
                let dialog = FileChooserDialog::new(
                    Some("Open File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Open);
                let cancel: i32 = gtk::ResponseType::Cancel.into();
                let accept: i32 = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Open", accept);
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        model.map = Map::open(path).unwrap();
                    }
                }
                dialog.close();
            },
            Msg::Motion(((x, y), t)) => {
                println!("({}, {}), {}", x, y, t);
            },
            Msg::Quit => gtk::main_quit(),
        }
    }

    fn view(relm: RemoteRelm<Msg>, model: &Self::Model) -> Self {
        let window = Window::new(WindowType::Toplevel);
        let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        let button_box = gtk::ButtonBox::new(gtk::Orientation::Vertical);
        let open_button = Button::new_with_label("Open");
        let save_button = Button::new_with_label("Save");
        let area = DrawingArea::new();
        area.set_size_request(model.size.x * model.scale, model.size.y * model.scale);
        area.set_events(area.get_events() | gdk::POINTER_MOTION_MASK.bits() as i32);
        area.set_events(area.get_events() | gdk::BUTTON_PRESS_MASK.bits() as i32);
        button_box.set_layout(gtk::ButtonBoxStyle::Start);

        button_box.pack_start(&open_button, false, false, 0);
        button_box.pack_start(&save_button, false, false, 0);
        hbox.pack_start(&area, false, false, 0);
        hbox.pack_start(&button_box, false, false, 0);
        window.add(&hbox);
        window.set_title("Game of Life");
        window.show_all();

        connect!(relm, window, connect_delete_event(_, _) (Some(Msg::Quit), Inhibit(false)));
        connect!(relm, area, connect_motion_notify_event(_, ev) (Some(Msg::Motion((ev.get_position(), 0))), Inhibit(false)));
        connect!(relm, save_button, connect_clicked(_), Msg::Save);
        connect!(relm, open_button, connect_clicked(_), Msg::Open);

        Win {
            hbox: hbox,
            button_box: button_box,
            open_button: open_button,
            save_button: save_button,
            area: area,
            window: window,
        }
    }
}
<commit_msg>Refactor: rename<commit_after>use ::*;
use relm::{Relm, RemoteRelm, Widget};
use gtk::prelude::*;
use gtk::{Window, WindowType, DrawingArea, Button};
use gtk::{FileChooserDialog};
use tokio_core::reactor::Interval;
use std::time::Duration;

use map::*;

#[derive(Clone)]
pub struct MyModel {
    map: Map,
    size: Pos,
    center: Pos,
    scale: i32,
}
impl MyModel {
    fn new() -> Self {
        MyModel {
            map: Map::acorn(),
            size: pos(250, 250),
            center: pos(0, 0),
            scale: 2,
        }
    }
}

#[derive(SimpleMsg)]
pub enum MyMsg {
    Motion(((f64, f64), u32)),
    Save,
    Open,
    Tick,
    Quit,
}

#[derive(Clone)]
pub struct Win {
    hbox: gtk::Box,
    button_box: gtk::ButtonBox,
    open_button: Button,
    save_button: Button,
    area: DrawingArea,
    window: Window,
}

impl Win {
    fn draw(&mut self, cells: Vec<&Pos>, model: &MyModel, top_left: &Pos) {
        use gdk::prelude::ContextExt;
        let cr = cairo::Context::create_from_window(&self.area.get_window().unwrap());
        cr.set_source_rgb(1., 1., 1.);
        cr.paint();
        cr.scale(model.scale as f64, model.scale as f64);
        cr.set_source_rgb(0., 0., 0.);
        for pos in cells {
            cr.rectangle((pos.x - top_left.x) as f64, (pos.y - top_left.y) as f64, 1., 1.);
        }
        cr.fill();
    }
}

impl Widget for Win {
    type Root = Window;
    type Model = MyModel;
    type Msg = MyMsg;

    fn root(&self) -> &Self::Root {
        &self.window
    }

    fn model() -> MyModel {
        MyModel::new()
    }

    fn subscriptions(relm: &Relm<MyMsg>) {
        let stream = Interval::new(Duration::from_millis(30), relm.handle()).unwrap();
        relm.connect_exec_ignore_err(stream, MyMsg::Tick);
    }

    fn update(&mut self, event: MyMsg, model: &mut MyModel) {
        match event {
            MyMsg::Tick => {
                model.map.next_generation();
                let top_left = pos(model.center.x - model.size.x / 2, model.center.y - model.size.y / 2);
                let cells = model.map.get_alive_cells_in(top_left.clone(), model.size.clone());
                self.draw(cells, model, &top_left);
            },
            MyMsg::Save => {
                let dialog = FileChooserDialog::new(
                    Some("Save File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Save);
                let cancel: i32 = gtk::ResponseType::Cancel.into();
                let accept: i32 = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Save", accept);
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        model.map.save(path).unwrap();
                    }
                }
                dialog.close();
            },
            MyMsg::Open => {
                let dialog = FileChooserDialog::new(
                    Some("Open File"),
                    Some(&self.window),
                    gtk::FileChooserAction::Open);
                let cancel: i32 = gtk::ResponseType::Cancel.into();
                let accept: i32 = gtk::ResponseType::Accept.into();
                dialog.add_button("Cancel", cancel);
                dialog.add_button("Open", accept);
                if accept == dialog.run() {
                    if let Some(path) = dialog.get_filename() {
                        model.map = Map::open(path).unwrap();
                    }
                }
                dialog.close();
            },
            MyMsg::Motion(((x, y), t)) => {
                println!("({}, {}), {}", x, y, t);
            },
            MyMsg::Quit => gtk::main_quit(),
        }
    }

    fn view(relm: RemoteRelm<MyMsg>, model: &MyModel) -> Self {
        let window = Window::new(WindowType::Toplevel);
        let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        let button_box = gtk::ButtonBox::new(gtk::Orientation::Vertical);
        let open_button = Button::new_with_label("Open");
        let save_button = Button::new_with_label("Save");
        let area = DrawingArea::new();
        area.set_size_request(model.size.x * model.scale, model.size.y * model.scale);
        area.set_events(area.get_events() | gdk::POINTER_MOTION_MASK.bits() as i32);
        area.set_events(area.get_events() | gdk::BUTTON_PRESS_MASK.bits() as i32);
        button_box.set_layout(gtk::ButtonBoxStyle::Start);

        button_box.pack_start(&open_button, false, false, 0);
        button_box.pack_start(&save_button, false, false, 0);
        hbox.pack_start(&area, false, false, 0);
        hbox.pack_start(&button_box, false, false, 0);
        window.add(&hbox);
        window.set_title("Game of Life");
        window.show_all();

        connect!(relm, window, connect_delete_event(_, _) (Some(MyMsg::Quit), Inhibit(false)));
        connect!(relm, area, connect_motion_notify_event(_, ev) (Some(MyMsg::Motion((ev.get_position(), 0))), Inhibit(false)));
        connect!(relm, save_button, connect_clicked(_), MyMsg::Save);
        connect!(relm, open_button, connect_clicked(_), MyMsg::Open);

        Win {
            hbox: hbox,
            button_box: button_box,
            open_button: open_button,
            save_button: save_button,
            area: area,
            window: window,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

//! # Serde code generator
//!
//! '''bash
//! cargo run --bin serdegen -- --help
//! '''

use serde_generate::{
    cpp, csharp, golang, java, python3, rust, typescript, CodeGeneratorConfig, Encoding,
    SourceInstaller,
};
use serde_reflection::Registry;
use std::path::PathBuf;
use structopt::{clap::arg_enum, StructOpt};

arg_enum! {
#[derive(Debug, StructOpt)]
enum Language {
    Python3,
    Cpp,
    Rust,
    Java,
    Go,
    TypeScript,
    CSharp,
}
}

arg_enum! {
#[derive(Debug, StructOpt, PartialEq, Eq, PartialOrd, Ord)]
enum Runtime {
    Serde,
    Bincode,
    Bcs,
}
}

#[derive(Debug, StructOpt)]
#[structopt(
    name = "Serde code generator",
    about = "Generate code for Serde containers"
)]
struct Options {
    /// Path to the YAML-encoded Serde formats.
    #[structopt(parse(from_os_str))]
    input: Option<PathBuf>,

    /// Language for code generation.
    #[structopt(long, possible_values = &Language::variants(), case_insensitive = true, default_value = "Python3")]
    language: Language,

    /// Directory where to write generated modules (otherwise print code on stdout).
    #[structopt(long)]
    target_source_dir: Option<PathBuf>,

    /// Optional runtimes to install in the `target_source_dir` (if applicable).
    /// Also triggers the generation of specialized methods for each runtime.
    #[structopt(long, possible_values = &Runtime::variants(), case_insensitive = true)]
    with_runtimes: Vec<Runtime>,

    /// Module name for the Serde formats installed in the `target_source_dir`.
    /// Rust crates may contain a version number separated with a colon, e.g. "test:1.2.0".
    /// (By default, the installer will use version "0.1.0".)
    #[structopt(long)]
    module_name: Option<String>,

    /// Optional package name (Python) or module path (Go) where to find Serde runtime dependencies.
    #[structopt(long)]
    serde_package_name: Option<String>,

    /// Translate enums without variant data (c-style enums) into their equivalent in the target language,
    /// if the target language and the generator code support them.
    #[structopt(long)]
    use_c_style_enums: bool,
}

fn get_codegen_config<'a, I>(name: String, runtimes: I, c_style_enums: bool) -> CodeGeneratorConfig
where
    I: IntoIterator<Item = &'a Runtime>,
{
    let mut encodings = Vec::new();
    for runtime in runtimes {
        match runtime {
            Runtime::Bincode => {
                encodings.push(Encoding::Bincode);
            }
            Runtime::Bcs => {
                encodings.push(Encoding::Bcs);
            }
            _ => (),
        }
    }
    CodeGeneratorConfig::new(name)
        .with_encodings(encodings)
        .with_c_style_enums(c_style_enums)
}

fn main() {
    let options = Options::from_args();
    let serde_package_name_opt = options.serde_package_name.clone();
    let named_registry_opt = match &options.input {
        None => None,
        Some(input) => {
            let name = options.module_name.clone().unwrap_or_else(|| {
                input
                    .file_stem()
                    .expect("failed to deduce module name from input path")
                    .to_string_lossy()
                    .into_owned()
            });
            let content = std::fs::read_to_string(input).expect("input file must be readable");
            let registry = serde_yaml::from_str::<Registry>(content.as_str()).unwrap();
            Some((registry, name))
        }
    };
    let runtimes: std::collections::BTreeSet<_> = options.with_runtimes.into_iter().collect();

    match options.target_source_dir {
        None => {
            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.use_c_style_enums);

                let stdout = std::io::stdout();
                let mut out = stdout.lock();
                match options.language {
                    Language::Python3 => python3::CodeGenerator::new(&config)
                        .with_serde_package_name(serde_package_name_opt)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Rust => rust::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Cpp => cpp::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Go => golang::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Java => panic!("Code generation in Java requires `--install-dir`"),
                    Language::TypeScript => typescript::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::CSharp => panic!("Code generation in C# requires `--install-dir`"),
                }
            }
        }

        Some(install_dir) => {
            let installer: Box<dyn SourceInstaller<Error = Box<dyn std::error::Error>>> =
                match options.language {
                    Language::Python3 => {
                        Box::new(python3::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::Rust => Box::new(rust::Installer::new(install_dir)),
                    Language::Cpp => Box::new(cpp::Installer::new(install_dir)),
                    Language::Java => Box::new(java::Installer::new(install_dir)),
                    Language::Go => {
                        Box::new(golang::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::TypeScript => Box::new(typescript::Installer::new(install_dir)),
                    Language::CSharp => Box::new(csharp::Installer::new(install_dir)),
                };

            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.use_c_style_enums);
                installer.install_module(&config, &registry).unwrap();
            }

            for runtime in runtimes {
                match runtime {
                    Runtime::Serde => installer.install_serde_runtime().unwrap(),
                    Runtime::Bincode => installer.install_bincode_runtime().unwrap(),
                    Runtime::Bcs => installer.install_bcs_runtime().unwrap(),
                }
            }
        }
    }
}
<commit_msg>[serde-generate] Fix --target-source-dir required message (#89)<commit_after>// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

//! # Serde code generator
//!
//! '''bash
//! cargo run --bin serdegen -- --help
//! '''

use serde_generate::{
    cpp, csharp, golang, java, python3, rust, typescript, CodeGeneratorConfig, Encoding,
    SourceInstaller,
};
use serde_reflection::Registry;
use std::path::PathBuf;
use structopt::{clap::arg_enum, StructOpt};

arg_enum! {
#[derive(Debug, StructOpt)]
enum Language {
    Python3,
    Cpp,
    Rust,
    Java,
    Go,
    TypeScript,
    CSharp,
}
}

arg_enum! {
#[derive(Debug, StructOpt, PartialEq, Eq, PartialOrd, Ord)]
enum Runtime {
    Serde,
    Bincode,
    Bcs,
}
}

#[derive(Debug, StructOpt)]
#[structopt(
    name = "Serde code generator",
    about = "Generate code for Serde containers"
)]
struct Options {
    /// Path to the YAML-encoded Serde formats.
    #[structopt(parse(from_os_str))]
    input: Option<PathBuf>,

    /// Language for code generation.
    #[structopt(long, possible_values = &Language::variants(), case_insensitive = true, default_value = "Python3")]
    language: Language,

    /// Directory where to write generated modules (otherwise print code on stdout).
    #[structopt(long)]
    target_source_dir: Option<PathBuf>,

    /// Optional runtimes to install in the `target_source_dir` (if applicable).
    /// Also triggers the generation of specialized methods for each runtime.
    #[structopt(long, possible_values = &Runtime::variants(), case_insensitive = true)]
    with_runtimes: Vec<Runtime>,

    /// Module name for the Serde formats installed in the `target_source_dir`.
    /// Rust crates may contain a version number separated with a colon, e.g. "test:1.2.0".
    /// (By default, the installer will use version "0.1.0".)
    #[structopt(long)]
    module_name: Option<String>,

    /// Optional package name (Python) or module path (Go) where to find Serde runtime dependencies.
    #[structopt(long)]
    serde_package_name: Option<String>,

    /// Translate enums without variant data (c-style enums) into their equivalent in the target language,
    /// if the target language and the generator code support them.
    #[structopt(long)]
    use_c_style_enums: bool,
}

fn get_codegen_config<'a, I>(name: String, runtimes: I, c_style_enums: bool) -> CodeGeneratorConfig
where
    I: IntoIterator<Item = &'a Runtime>,
{
    let mut encodings = Vec::new();
    for runtime in runtimes {
        match runtime {
            Runtime::Bincode => {
                encodings.push(Encoding::Bincode);
            }
            Runtime::Bcs => {
                encodings.push(Encoding::Bcs);
            }
            _ => (),
        }
    }
    CodeGeneratorConfig::new(name)
        .with_encodings(encodings)
        .with_c_style_enums(c_style_enums)
}

fn main() {
    let options = Options::from_args();
    let serde_package_name_opt = options.serde_package_name.clone();
    let named_registry_opt = match &options.input {
        None => None,
        Some(input) => {
            let name = options.module_name.clone().unwrap_or_else(|| {
                input
                    .file_stem()
                    .expect("failed to deduce module name from input path")
                    .to_string_lossy()
                    .into_owned()
            });
            let content = std::fs::read_to_string(input).expect("input file must be readable");
            let registry = serde_yaml::from_str::<Registry>(content.as_str()).unwrap();
            Some((registry, name))
        }
    };
    let runtimes: std::collections::BTreeSet<_> = options.with_runtimes.into_iter().collect();

    match options.target_source_dir {
        None => {
            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.use_c_style_enums);

                let stdout = std::io::stdout();
                let mut out = stdout.lock();
                match options.language {
                    Language::Python3 => python3::CodeGenerator::new(&config)
                        .with_serde_package_name(serde_package_name_opt)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Rust => rust::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Cpp => cpp::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Go => golang::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::Java => {
                        panic!("Code generation in Java requires `--target-source-dir`")
                    }
                    Language::TypeScript => typescript::CodeGenerator::new(&config)
                        .output(&mut out, &registry)
                        .unwrap(),
                    Language::CSharp => {
                        panic!("Code generation in C# requires `--target-source-dir`")
                    }
                }
            }
        }

        Some(install_dir) => {
            let installer: Box<dyn SourceInstaller<Error = Box<dyn std::error::Error>>> =
                match options.language {
                    Language::Python3 => {
                        Box::new(python3::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::Rust => Box::new(rust::Installer::new(install_dir)),
                    Language::Cpp => Box::new(cpp::Installer::new(install_dir)),
                    Language::Java => Box::new(java::Installer::new(install_dir)),
                    Language::Go => {
                        Box::new(golang::Installer::new(install_dir, serde_package_name_opt))
                    }
                    Language::TypeScript => Box::new(typescript::Installer::new(install_dir)),
                    Language::CSharp => Box::new(csharp::Installer::new(install_dir)),
                };

            if let Some((registry, name)) = named_registry_opt {
                let config = get_codegen_config(name, &runtimes, options.use_c_style_enums);
                installer.install_module(&config, &registry).unwrap();
            }

            for runtime in runtimes {
                match runtime {
                    Runtime::Serde => installer.install_serde_runtime().unwrap(),
                    Runtime::Bincode => installer.install_bincode_runtime().unwrap(),
                    Runtime::Bcs => installer.install_bcs_runtime().unwrap(),
                }
            }
        }
    }
}
<|endoftext|>