<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.

//! Provides the JSON/HTTP API for wallets to receive payments. Because
//! receiving money in MimbleWimble requires an interactive exchange, a
//! wallet server that's running at all time is required in many cases.
//!
//! The API looks like this:
//!
//! POST /v1/wallet/receive
//! > {
//! >   "amount": 10,
//! >   "blind_sum": "a12b7f...",
//! >   "tx": "f083de...",
//! > }
//!
//! < {
//! <   "tx": "f083de...",
//! <   "status": "ok"
//! < }
//!
//! POST /v1/wallet/finalize
//! > {
//! >   "tx": "f083de...",
//! > }
//!
//! POST /v1/wallet/receive_coinbase
//! > {
//! >   "amount": 1,
//! > }
//!
//! < {
//! <   "output": "8a90bc...",
//! <   "kernel": "f083de...",
//! < }
//!
//! Note that while at this point the finalize call is completely unecessary, a
//! double-exchange will be required as soon as we support Schnorr signatures.
//! So we may as well have it in place already.

use std::convert::From;
use secp;
use secp::key::SecretKey;

use core::core::{Block, Transaction, TxKernel, Output, build};
use core::ser;
use api::{self, ApiEndpoint, Operation, ApiResult};
use extkey::ExtendedKey;
use types::*;
use util;

/// Dummy wrapper for the hex-encoded serialized transaction.
#[derive(Serialize, Deserialize)]
struct TxWrapper {
	tx_hex: String,
}

/// Receive an already well formed JSON transaction issuance and finalize the
/// transaction, adding our receiving output, to broadcast to the rest of the
/// network.
pub fn receive_json_tx(
	config: &WalletConfig,
	ext_key: &ExtendedKey,
	partial_tx_str: &str,
) -> Result<(), Error> {
	let (amount, blinding, partial_tx) = partial_tx_from_json(partial_tx_str)?;
	let final_tx = receive_transaction(&config, ext_key, amount, blinding, partial_tx)?;
	let tx_hex = util::to_hex(ser::ser_vec(&final_tx).unwrap());

	let url = format!("{}/v1/pool/push", config.check_node_api_http_addr.as_str());
	let _: () = api::client::post(url.as_str(), &TxWrapper { tx_hex: tx_hex })
		.map_err(|e| Error::Node(e))?;
	Ok(())
}

/// Component used to receive coins, implements all the receiving end of the
/// wallet REST API as well as some of the command-line operations.
#[derive(Clone)]
pub struct WalletReceiver {
	pub key: ExtendedKey,
	pub config: WalletConfig,
}

impl ApiEndpoint for WalletReceiver {
	type ID = String;
	type T = String;
	type OP_IN = WalletReceiveRequest;
	type OP_OUT = CbData;

	fn operations(&self) -> Vec<Operation> {
		vec![
			Operation::Custom("coinbase".to_string()),
			Operation::Custom("receive_json_tx".to_string()),
		]
	}

	fn operation(&self, op: String, input: WalletReceiveRequest) -> ApiResult<CbData> {
		match op.as_str() {
			"coinbase" => {
				match input {
					WalletReceiveRequest::Coinbase(cb_amount) => {
						debug!("Operation {} with amount {}", op, cb_amount.amount);
						if cb_amount.amount == 0 {
							return Err(api::Error::Argument(format!("Zero amount not allowed.")));
						}
						let (out, kern) = receive_coinbase(
							&self.config,
							&self.key,
							cb_amount.amount,
						).map_err(|e| {
							api::Error::Internal(format!("Error building coinbase: {:?}", e))
						})?;
						let out_bin = ser::ser_vec(&out).map_err(|e| {
							api::Error::Internal(format!("Error serializing output: {:?}", e))
						})?;
						let kern_bin = ser::ser_vec(&kern).map_err(|e| {
							api::Error::Internal(format!("Error serializing kernel: {:?}", e))
						})?;
						Ok(CbData {
							output: util::to_hex(out_bin),
							kernel: util::to_hex(kern_bin),
						})
					}
					_ => Err(api::Error::Argument(
						format!("Incorrect request data: {}", op),
					)),
				}
			}
			"receive_json_tx" => {
				match input {
					WalletReceiveRequest::PartialTransaction(partial_tx_str) => {
						debug!("Operation {} with transaction {}", op, &partial_tx_str);
						receive_json_tx(&self.config, &self.key, &partial_tx_str)
							.map_err(|e| {
								api::Error::Internal(
									format!("Error processing partial transaction: {:?}", e),
								)
							})
							.unwrap();

						// TODO: Return emptiness for now, should be a proper enum return type
						Ok(CbData {
							output: String::from(""),
							kernel: String::from(""),
						})
					}
					_ => Err(api::Error::Argument(
						format!("Incorrect request data: {}", op),
					)),
				}
			}
			_ => Err(api::Error::Argument(format!("Unknown operation: {}", op))),
		}
	}
}

/// Build a coinbase output and the corresponding kernel
fn receive_coinbase(
	config: &WalletConfig,
	ext_key: &ExtendedKey,
	amount: u64,
) -> Result<(Output, TxKernel), Error> {
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);

	// operate within a lock on wallet data
	WalletData::with_wallet(&config.data_file_dir, |wallet_data| {

		// derive a new private for the reward
		let next_child = wallet_data.next_child(&ext_key.fingerprint);
		let coinbase_key = ext_key.derive(&secp, next_child).map_err(|e| Error::Key(e))?;

		// track the new output and return the stuff needed for reward
		wallet_data.append_output(OutputData {
			fingerprint: coinbase_key.fingerprint,
			n_child: coinbase_key.n_child,
			value: amount,
			status: OutputStatus::Unconfirmed,
			height: 0,
			lock_height: 0,
		});
		debug!(
			"Using child {} for a new coinbase output.",
			coinbase_key.n_child
		);

		Block::reward_output(coinbase_key.key, &secp).map_err(&From::from)
	})?
}

/// Builds a full transaction from the partial one sent to us for transfer
fn receive_transaction(
	config: &WalletConfig,
	ext_key: &ExtendedKey,
	amount: u64,
	blinding: SecretKey,
	partial: Transaction,
) -> Result<Transaction, Error> {

	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);

	// operate within a lock on wallet data
	WalletData::with_wallet(&config.data_file_dir, |wallet_data| {

		let next_child = wallet_data.next_child(&ext_key.fingerprint);
		let out_key = ext_key.derive(&secp, next_child).map_err(|e| Error::Key(e))?;

		let (tx_final, _) = build::transaction(vec![
			build::initial_tx(partial),
			build::with_excess(blinding),
			build::output(amount, out_key.key),
		])?;

		// make sure the resulting transaction is valid (could have been lied to
		// on excess)
		tx_final.validate(&secp)?;

		// track the new output and return the finalized transaction to broadcast
		wallet_data.append_output(OutputData {
			fingerprint: out_key.fingerprint,
			n_child: out_key.n_child,
			value: amount,
			status: OutputStatus::Unconfirmed,
			height: 0,
			lock_height: 0,
		});

		debug!(
			"Using child {} for a new transaction output.",
			out_key.n_child
		);

		Ok(tx_final)
	})?
}
<commit_msg>Add fee amount to wallet receive_transaction (mainly for testing purposes) (#150)<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.

//! Provides the JSON/HTTP API for wallets to receive payments. Because
//! receiving money in MimbleWimble requires an interactive exchange, a
//! wallet server that's running at all time is required in many cases.
//!
//! The API looks like this:
//!
//! POST /v1/wallet/receive
//! > {
//! >   "amount": 10,
//! >   "blind_sum": "a12b7f...",
//! >   "tx": "f083de...",
//! > }
//!
//! < {
//! <   "tx": "f083de...",
//! <   "status": "ok"
//! < }
//!
//! POST /v1/wallet/finalize
//! > {
//! >   "tx": "f083de...",
//! > }
//!
//! POST /v1/wallet/receive_coinbase
//! > {
//! >   "amount": 1,
//! > }
//!
//! < {
//! <   "output": "8a90bc...",
//! <   "kernel": "f083de...",
//! < }
//!
//! Note that while at this point the finalize call is completely unecessary, a
//! double-exchange will be required as soon as we support Schnorr signatures.
//! So we may as well have it in place already.

use std::convert::From;
use secp;
use secp::key::SecretKey;

use core::core::{Block, Transaction, TxKernel, Output, build};
use core::ser;
use api::{self, ApiEndpoint, Operation, ApiResult};
use extkey::ExtendedKey;
use types::*;
use util;

/// Dummy wrapper for the hex-encoded serialized transaction.
#[derive(Serialize, Deserialize)]
struct TxWrapper {
	tx_hex: String,
}

/// Receive an already well formed JSON transaction issuance and finalize the
/// transaction, adding our receiving output, to broadcast to the rest of the
/// network.
pub fn receive_json_tx(
	config: &WalletConfig,
	ext_key: &ExtendedKey,
	partial_tx_str: &str,
) -> Result<(), Error> {
	let (amount, blinding, partial_tx) = partial_tx_from_json(partial_tx_str)?;
	let final_tx = receive_transaction(&config, ext_key, amount, blinding, partial_tx)?;
	let tx_hex = util::to_hex(ser::ser_vec(&final_tx).unwrap());

	let url = format!("{}/v1/pool/push", config.check_node_api_http_addr.as_str());
	let _: () = api::client::post(url.as_str(), &TxWrapper { tx_hex: tx_hex })
		.map_err(|e| Error::Node(e))?;
	Ok(())
}

/// Component used to receive coins, implements all the receiving end of the
/// wallet REST API as well as some of the command-line operations.
#[derive(Clone)]
pub struct WalletReceiver {
	pub key: ExtendedKey,
	pub config: WalletConfig,
}

impl ApiEndpoint for WalletReceiver {
	type ID = String;
	type T = String;
	type OP_IN = WalletReceiveRequest;
	type OP_OUT = CbData;

	fn operations(&self) -> Vec<Operation> {
		vec![
			Operation::Custom("coinbase".to_string()),
			Operation::Custom("receive_json_tx".to_string()),
		]
	}

	fn operation(&self, op: String, input: WalletReceiveRequest) -> ApiResult<CbData> {
		match op.as_str() {
			"coinbase" => {
				match input {
					WalletReceiveRequest::Coinbase(cb_amount) => {
						debug!("Operation {} with amount {}", op, cb_amount.amount);
						if cb_amount.amount == 0 {
							return Err(api::Error::Argument(format!("Zero amount not allowed.")));
						}
						let (out, kern) = receive_coinbase(
							&self.config,
							&self.key,
							cb_amount.amount,
						).map_err(|e| {
							api::Error::Internal(format!("Error building coinbase: {:?}", e))
						})?;
						let out_bin = ser::ser_vec(&out).map_err(|e| {
							api::Error::Internal(format!("Error serializing output: {:?}", e))
						})?;
						let kern_bin = ser::ser_vec(&kern).map_err(|e| {
							api::Error::Internal(format!("Error serializing kernel: {:?}", e))
						})?;
						Ok(CbData {
							output: util::to_hex(out_bin),
							kernel: util::to_hex(kern_bin),
						})
					}
					_ => Err(api::Error::Argument(
						format!("Incorrect request data: {}", op),
					)),
				}
			}
			"receive_json_tx" => {
				match input {
					WalletReceiveRequest::PartialTransaction(partial_tx_str) => {
						debug!("Operation {} with transaction {}", op, &partial_tx_str);
						receive_json_tx(&self.config, &self.key, &partial_tx_str)
							.map_err(|e| {
								api::Error::Internal(
									format!("Error processing partial transaction: {:?}", e),
								)
							})
							.unwrap();

						// TODO: Return emptiness for now, should be a proper enum return type
						Ok(CbData {
							output: String::from(""),
							kernel: String::from(""),
						})
					}
					_ => Err(api::Error::Argument(
						format!("Incorrect request data: {}", op),
					)),
				}
			}
			_ => Err(api::Error::Argument(format!("Unknown operation: {}", op))),
		}
	}
}

/// Build a coinbase output and the corresponding kernel
fn receive_coinbase(
	config: &WalletConfig,
	ext_key: &ExtendedKey,
	amount: u64,
) -> Result<(Output, TxKernel), Error> {
	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);

	// operate within a lock on wallet data
	WalletData::with_wallet(&config.data_file_dir, |wallet_data| {

		// derive a new private for the reward
		let next_child = wallet_data.next_child(&ext_key.fingerprint);
		let coinbase_key = ext_key.derive(&secp, next_child).map_err(|e| Error::Key(e))?;

		// track the new output and return the stuff needed for reward
		wallet_data.append_output(OutputData {
			fingerprint: coinbase_key.fingerprint,
			n_child: coinbase_key.n_child,
			value: amount,
			status: OutputStatus::Unconfirmed,
			height: 0,
			lock_height: 0,
		});
		debug!(
			"Using child {} for a new coinbase output.",
			coinbase_key.n_child
		);

		Block::reward_output(coinbase_key.key, &secp).map_err(&From::from)
	})?
}

/// Builds a full transaction from the partial one sent to us for transfer
fn receive_transaction(
	config: &WalletConfig,
	ext_key: &ExtendedKey,
	amount: u64,
	blinding: SecretKey,
	partial: Transaction,
) -> Result<Transaction, Error> {

	let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);

	// operate within a lock on wallet data
	WalletData::with_wallet(&config.data_file_dir, |wallet_data| {

		let next_child = wallet_data.next_child(&ext_key.fingerprint);
		let out_key = ext_key.derive(&secp, next_child).map_err(|e| Error::Key(e))?;

		// TODO - replace with real fee calculation
		// TODO - note we are not enforcing this in consensus anywhere yet
		let fee_amount = 1;
		let out_amount = amount - fee_amount;

		let (tx_final, _) = build::transaction(vec![
			build::initial_tx(partial),
			build::with_excess(blinding),
			build::output(out_amount, out_key.key),
			build::with_fee(fee_amount),
		])?;

		// make sure the resulting transaction is valid (could have been lied to
		// on excess)
		tx_final.validate(&secp)?;

		// track the new output and return the finalized transaction to broadcast
		wallet_data.append_output(OutputData {
			fingerprint: out_key.fingerprint,
			n_child: out_key.n_child,
			value: out_amount,
			status: OutputStatus::Unconfirmed,
			height: 0,
			lock_height: 0,
		});

		debug!(
			"Using child {} for a new transaction output.",
			out_key.n_child
		);

		Ok(tx_final)
	})?
}
<|endoftext|>


<commit_before>use screen::*;
use context::{Context, GameState};
use ui::{create_ui, Ui};
use piston_window::{self, PistonWindow};
use conrod::{Canvas, Button, Widget, Positionable, Sizeable, Labelable};
use conrod::color::{self, Colorable};

pub struct MainMenu {
    ui: Ui,
    state: Option<State>,
}

impl MainMenu {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        MainMenu {
            ui: create_ui(&window, &context.assets_path),
            state: None,
        }
    }
}

enum State {
    NewGame,
    Options,
    Exit,
}

impl Screen for MainMenu {
    fn on_input(&mut self, _: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        self.ui.handle_event(window);
        let mut result = Vec::new();

        match self.state.take() {
            Some(State::NewGame) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(Battle::new(&window, context))));
                context.game_state = GameState::InProgress;
            }
            Some(State::Options) => {
                result.push(InputResult::PushScreen(Box::new(Options::new(&window, context))));
            }
            Some(State::Exit) => {
                result.push(InputResult::Exit);
            }
            None => {}
        }

        result
    }

    fn on_draw(&mut self, _: &piston_window::RenderArgs, window: &PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, _: &piston_window::UpdateArgs) {
        let button_color = color::rgb(0.4, 0.75, 0.6);

        let state = &mut self.state;

        self.ui.set_widgets(|mut ui| {
            Canvas::new()
                .pad(30.)
                .color(color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .color(button_color)
                .label("New game")
                .react(|| *state = Some(State::NewGame))
                .set(NEW_GAME_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(NEW_GAME_BUTTON, 45.0)
                .color(button_color)
                .label("Options")
                .react(|| *state = Some(State::Options))
                .set(OPTIONS_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(OPTIONS_BUTTON, 45.0)
                .color(button_color)
                .label("Exit")
                .react(|| *state = Some(State::Exit))
                .set(EXIT_BUTTON, &mut ui);
        });
    }
}

widget_ids! {
    CANVAS,
    NEW_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}
<commit_msg>MainMenu: game state<commit_after>use screen::*;
use context::{Context, GameState};
use ui::{create_ui, Ui};
use piston_window::{self, PistonWindow};
use conrod::{Canvas, Button, Widget, Positionable, Sizeable, Labelable};
use conrod::color::{self, Colorable};

pub struct MainMenu {
    ui: Ui,
    state: Option<State>,
}

impl MainMenu {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        MainMenu {
            ui: create_ui(&window, &context.assets_path),
            state: None,
        }
    }
}

enum State {
    NewGame,
    Options,
    Exit,
}

impl Screen for MainMenu {
    fn on_input(&mut self, _: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        self.ui.handle_event(window);
        let mut result = Vec::new();

        match self.state.take() {
            Some(State::NewGame) => {
                result.push(InputResult::PopScreen);

                if let GameState::NotStarted = context.game_state {
                    // Start new game.
                    result.push(InputResult::PushScreen(Box::new(Battle::new(&window, context))));
                    context.game_state = GameState::InProgress;
                }
            }
            Some(State::Options) => {
                result.push(InputResult::PushScreen(Box::new(Options::new(&window, context))));
            }
            Some(State::Exit) => {
                result.push(InputResult::Exit);
            }
            None => {}
        }

        result
    }

    fn on_draw(&mut self, _: &piston_window::RenderArgs, window: &PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, _: &piston_window::UpdateArgs) {
        let button_color = color::rgb(0.4, 0.75, 0.6);

        let state = &mut self.state;

        self.ui.set_widgets(|mut ui| {
            Canvas::new()
                .pad(30.)
                .color(color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .color(button_color)
                .label("New game")
                .react(|| *state = Some(State::NewGame))
                .set(NEW_GAME_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(NEW_GAME_BUTTON, 45.0)
                .color(button_color)
                .label("Options")
                .react(|| *state = Some(State::Options))
                .set(OPTIONS_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(OPTIONS_BUTTON, 45.0)
                .color(button_color)
                .label("Exit")
                .react(|| *state = Some(State::Exit))
                .set(EXIT_BUTTON, &mut ui);
        });
    }
}

widget_ids! {
    CANVAS,
    NEW_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}
<|endoftext|>


<commit_before>extern crate winit;
use winit::event_loop::EventLoop;
use winit::window::WindowBuilder;

fn main() {
    let event_loop = EventLoop::new();
    let window = WindowBuilder::new().build(&event_loop).unwrap();
    println!("{:#?}\nPrimary: {:#?}", window.available_monitors(), window.primary_monitor());
}
<commit_msg>Use `dbg!()` macro in monitor list example (#931)<commit_after>extern crate winit;
use winit::event_loop::EventLoop;
use winit::window::WindowBuilder;

fn main() {
    let event_loop = EventLoop::new();
    let window = WindowBuilder::new().build(&event_loop).unwrap();

    dbg!(window.available_monitors());
    dbg!(window.primary_monitor());
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/prost-codegen/0.5.0")]

//! Protocol Buffers well-known types.
//!
//! Note that the documentation for the types defined in this crate are generated from the Protobuf
//! definitions, so code examples are not in Rust.
//!
//! See the [Protobuf reference][1] for more information about well-known types.
//!
//! [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf

use std::i32;
use std::i64;
use std::time;

include!("protobuf.rs");
pub mod compiler {
    include!("compiler.rs");
}

// The Protobuf `Duration` and `Timestamp` types can't delegate to the standard library equivalents
// because the Protobuf versions are signed. To make them easier to work with, `From` conversions
// are defined in both directions.

const NANOS_PER_SECOND: i32 = 1_000_000_000;

impl Duration {
    /// Normalizes the duration to a canonical format.
    ///
    /// Based on [`google::protobuf::util::CreateNormalized`][1].
    /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L79-L100
    fn normalize(&mut self) {
        // Make sure nanos is in the range.
        if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
            self.seconds += (self.nanos / NANOS_PER_SECOND) as i64;
            self.nanos %= NANOS_PER_SECOND;
        }

        // nanos should have the same sign as seconds.
        if self.seconds < 0 && self.nanos > 0 {
            self.seconds += 1;
            self.nanos -= NANOS_PER_SECOND;
        } else if self.seconds > 0 && self.nanos < 0 {
            self.seconds -= 1;
            self.nanos += NANOS_PER_SECOND;
        }
        // TODO: should this be checked?
        // debug_assert!(self.seconds >= -315_576_000_000 && self.seconds <= 315_576_000_000,
        //               "invalid duration: {:?}", self);
    }
}

/// Converts a `std::time::Duration` to a `Duration`.
impl From<time::Duration> for Duration {
    fn from(duration: time::Duration) -> Duration {
        let seconds = duration.as_secs();
        let seconds = if seconds > i64::MAX as u64 {
            i64::MAX
        } else {
            seconds as i64
        };
        let nanos = duration.subsec_nanos();
        let nanos = if nanos > i32::MAX as u32 {
            i32::MAX
        } else {
            nanos as i32
        };
        let mut duration = Duration { seconds, nanos };
        duration.normalize();
        duration
    }
}

/// Converts a `Duration` to a result containing a positive (`Ok`) or negative (`Err`)
/// `std::time::Duration`.
// TODO: convert this to TryFrom when it's stable.
impl From<Duration> for Result<time::Duration, time::Duration> {
    fn from(mut duration: Duration) -> Result<time::Duration, time::Duration> {
        duration.normalize();
        if duration.seconds >= 0 {
            Ok(time::Duration::new(
                duration.seconds as u64,
                duration.nanos as u32,
            ))
        } else {
            Err(time::Duration::new(
                (-duration.seconds) as u64,
                (-duration.nanos) as u32,
            ))
        }
    }
}

impl Timestamp {
    /// Normalizes the timestamp to a canonical format.
    ///
    /// Based on [`google::protobuf::util::CreateNormalized`][1].
    /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L59-L77
    fn normalize(&mut self) {
        // Make sure nanos is in the range.
        if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
            self.seconds += (self.nanos / NANOS_PER_SECOND) as i64;
            self.nanos %= NANOS_PER_SECOND;
        }

        // For Timestamp nanos should be in the range [0, 999999999].
        if self.nanos < 0 {
            self.seconds -= 1;
            self.nanos += NANOS_PER_SECOND;
        }

        // TODO: should this be checked?
        // debug_assert!(self.seconds >= -62_135_596_800 && self.seconds <= 253_402_300_799,
        //               "invalid timestamp: {:?}", self);
    }
}

/// Converts a `std::time::SystemTime` to a `Timestamp`.
impl From<time::SystemTime> for Timestamp {
    fn from(time: time::SystemTime) -> Timestamp {
        let duration = Duration::from(time.duration_since(time::UNIX_EPOCH).unwrap());
        Timestamp {
            seconds: duration.seconds,
            nanos: duration.nanos,
        }
    }
}

/// Converts a `Timestamp` to a `SystemTime`, or if the timestamp falls before the Unix epoch, a
/// duration containing the difference.
// TODO: convert this to TryFrom when it's stable.
impl From<Timestamp> for Result<time::SystemTime, time::Duration> {
    fn from(mut timestamp: Timestamp) -> Result<time::SystemTime, time::Duration> {
        timestamp.normalize();
        if timestamp.seconds >= 0 {
            Ok(time::UNIX_EPOCH
                + time::Duration::new(timestamp.seconds as u64, timestamp.nanos as u32))
        } else {
            let mut duration = Duration {
                seconds: -timestamp.seconds,
                nanos: timestamp.nanos,
            };
            duration.normalize();
            Err(time::Duration::new(
                duration.seconds as u64,
                duration.nanos as u32,
            ))
        }
    }
}
<commit_msg>More fallible Try to TryFrom conversions<commit_after>#![doc(html_root_url = "https://docs.rs/prost-codegen/0.5.0")]

//! Protocol Buffers well-known types.
//!
//! Note that the documentation for the types defined in this crate are generated from the Protobuf
//! definitions, so code examples are not in Rust.
//!
//! See the [Protobuf reference][1] for more information about well-known types.
//!
//! [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf

use std::convert::TryFrom;
use std::i32;
use std::i64;
use std::time;

include!("protobuf.rs");
pub mod compiler {
    include!("compiler.rs");
}

// The Protobuf `Duration` and `Timestamp` types can't delegate to the standard library equivalents
// because the Protobuf versions are signed. To make them easier to work with, `From` conversions
// are defined in both directions.

const NANOS_PER_SECOND: i32 = 1_000_000_000;

impl Duration {
    /// Normalizes the duration to a canonical format.
    ///
    /// Based on [`google::protobuf::util::CreateNormalized`][1].
    /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L79-L100
    fn normalize(&mut self) {
        // Make sure nanos is in the range.
        if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
            self.seconds += (self.nanos / NANOS_PER_SECOND) as i64;
            self.nanos %= NANOS_PER_SECOND;
        }

        // nanos should have the same sign as seconds.
        if self.seconds < 0 && self.nanos > 0 {
            self.seconds += 1;
            self.nanos -= NANOS_PER_SECOND;
        } else if self.seconds > 0 && self.nanos < 0 {
            self.seconds -= 1;
            self.nanos += NANOS_PER_SECOND;
        }
        // TODO: should this be checked?
        // debug_assert!(self.seconds >= -315_576_000_000 && self.seconds <= 315_576_000_000,
        //               "invalid duration: {:?}", self);
    }
}

/// Converts a `std::time::Duration` to a `Duration`.
impl From<time::Duration> for Duration {
    fn from(duration: time::Duration) -> Duration {
        let seconds = duration.as_secs();
        let seconds = if seconds > i64::MAX as u64 {
            i64::MAX
        } else {
            seconds as i64
        };
        let nanos = duration.subsec_nanos();
        let nanos = if nanos > i32::MAX as u32 {
            i32::MAX
        } else {
            nanos as i32
        };
        let mut duration = Duration { seconds, nanos };
        duration.normalize();
        duration
    }
}

impl TryFrom<Duration> for time::Duration {
    type Error = time::Duration;

    /// Converts a `Duration` to a result containing a positive (`Ok`) or negative (`Err`)
    /// `std::time::Duration`.
    fn try_from(mut duration: Duration) -> Result<time::Duration, time::Duration> {
        duration.normalize();
        if duration.seconds >= 0 {
            Ok(time::Duration::new(
                duration.seconds as u64,
                duration.nanos as u32,
            ))
        } else {
            Err(time::Duration::new(
                (-duration.seconds) as u64,
                (-duration.nanos) as u32,
            ))
        }
    }
}

impl Timestamp {
    /// Normalizes the timestamp to a canonical format.
    ///
    /// Based on [`google::protobuf::util::CreateNormalized`][1].
    /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L59-L77
    fn normalize(&mut self) {
        // Make sure nanos is in the range.
        if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
            self.seconds += (self.nanos / NANOS_PER_SECOND) as i64;
            self.nanos %= NANOS_PER_SECOND;
        }

        // For Timestamp nanos should be in the range [0, 999999999].
        if self.nanos < 0 {
            self.seconds -= 1;
            self.nanos += NANOS_PER_SECOND;
        }

        // TODO: should this be checked?
        // debug_assert!(self.seconds >= -62_135_596_800 && self.seconds <= 253_402_300_799,
        //               "invalid timestamp: {:?}", self);
    }
}

/// Converts a `std::time::SystemTime` to a `Timestamp`.
impl From<time::SystemTime> for Timestamp {
    fn from(time: time::SystemTime) -> Timestamp {
        let duration = Duration::from(time.duration_since(time::UNIX_EPOCH).unwrap());
        Timestamp {
            seconds: duration.seconds,
            nanos: duration.nanos,
        }
    }
}

impl TryFrom<Timestamp> for time::SystemTime {
    type Error = time::Duration;

    /// Converts a `Timestamp` to a `SystemTime`, or if the timestamp falls before the Unix epoch,
    /// a duration containing the difference.
    fn try_from(mut timestamp: Timestamp) -> Result<time::SystemTime, time::Duration> {
        timestamp.normalize();
        if timestamp.seconds >= 0 {
            Ok(time::UNIX_EPOCH
                + time::Duration::new(timestamp.seconds as u64, timestamp.nanos as u32))
        } else {
            let mut duration = Duration {
                seconds: -timestamp.seconds,
                nanos: timestamp.nanos,
            };
            duration.normalize();
            Err(time::Duration::new(
                duration.seconds as u64,
                duration.nanos as u32,
            ))
        }
    }
}
<|endoftext|>


<commit_before>extern crate protobuf;
extern crate proc_macro;

use std::collections::hash_map::HashMap;
use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};

use protobuf::descriptor::*;
use protobuf::Message;

use protobuf::prelude::*;

mod amend_io_error_util;
mod compiler_plugin;
mod customize;
mod enums;
mod file;
mod extensions;
mod field;
mod rust_name;
mod protobuf_name;
mod map;
mod message;
mod oneof;
mod rust_types_values;
mod serde;
mod well_known_types;
pub mod case_convert;
mod file_descriptor;
pub(crate) mod file_and_mod;

pub(crate) mod scope;
pub(crate) mod syntax;
pub(crate) mod strx;
pub(crate) mod rust;

use customize::customize_from_rustproto_for_file;
pub use customize::Customize;

pub mod code_writer;

use self::code_writer::CodeWriter;
use self::enums::*;
use self::extensions::*;
use self::message::*;
#[doc(hidden)]
pub use amend_io_error_util::amend_io_error;
use map::map_entry;
use scope::RootScope;
use scope::FileScope;
use file::proto_path_to_rust_mod;

pub use protobuf_name::ProtobufIdent;
pub use protobuf_name::ProtobufAbsolutePath;
pub use protobuf_name::ProtobufRelativePath;

fn escape_byte(s: &mut String, b: u8) {
    if b == b'\n' {
        write!(s, "\\n").unwrap();
    } else if b == b'\r' {
        write!(s, "\\r").unwrap();
    } else if b == b'\t' {
        write!(s, "\\t").unwrap();
    } else if b == b'\\' || b == b'"' {
        write!(s, "\\{}", b as char).unwrap();
    } else if b == b'\0' {
        write!(s, "\\0").unwrap();
    // ASCII printable except space
    } else if b > 0x20 && b < 0x7f {
        write!(s, "{}", b as char).unwrap();
    } else {
        write!(s, "\\x{:02x}", b).unwrap();
    }
}

fn write_file_descriptor_data(file: &FileDescriptorProto, w: &mut CodeWriter) {
    let fdp_bytes = file.write_to_bytes().unwrap();
    w.write_line("static file_descriptor_proto_data: &'static [u8] = b\"\\");
    w.indented(|w| {
        const MAX_LINE_LEN: usize = 72;

        let mut s = String::new();
        for &b in &fdp_bytes {
            let prev_len = s.len();
            escape_byte(&mut s, b);
            let truncate = s.len() > MAX_LINE_LEN;
            if truncate {
                s.truncate(prev_len);
            }
            if truncate || s.len() == MAX_LINE_LEN {
                write!(s, "\\").unwrap();
                w.write_line(&s);
                s.clear();
            }
            if truncate {
                escape_byte(&mut s, b);
            }
        }
        if !s.is_empty() {
            write!(s, "\\").unwrap();
            w.write_line(&s);
            s.clear();
        }
    });
    w.write_line("\";");
    w.write_line("");
    w.lazy_static(
        "file_descriptor_proto_lazy",
        "::protobuf::descriptor::FileDescriptorProto",
    );
    w.write_line("");
    w.def_fn(
        "parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto",
        |w| {
            w.write_line("::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap()");
        },
    );
    w.write_line("");
    w.pub_fn(
        "file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto",
        |w| {
            w.block("file_descriptor_proto_lazy.get(|| {", "})", |w| {
                w.write_line("parse_descriptor_proto()");
            });
        },
    );
}

fn gen_file(
    file: &FileDescriptorProto,
    _files_map: &HashMap<&Path, &FileDescriptorProto>,
    root_scope: &RootScope,
    customize: &Customize,
) -> Option<compiler_plugin::GenResult> {
    // TODO: use it
    let mut customize = customize.clone();
    // options specified in invocation have precedence over options specified in file
    customize.update_with(&customize_from_rustproto_for_file(
        file.options.get_message(),
    ));

    let scope = FileScope {
        file_descriptor: file,
    }.to_scope();
    let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
        file
            .options
            .get_message()
            .get_optimize_for()
            == file_options::OptimizeMode::LITE_RUNTIME
    });

    let mut v = Vec::new();

    {
        let mut w = CodeWriter::new(&mut v);

        w.write_generated_by("rust-protobuf", env!("CARGO_PKG_VERSION"));

        for message in &scope.get_messages() {
            // ignore map entries, because they are not used in map fields
            if map_entry(message).is_none() {
                w.write_line("");
                MessageGen::new(message, &root_scope, &customize).write(&mut w);
            }
        }
        for enum_type in &scope.get_enums() {
            w.write_line("");
            EnumGen::new(enum_type, &customize, root_scope).write(&mut w);
        }

        write_extensions(file, &root_scope, &mut w);

        if !lite_runtime {
            w.write_line("");
            write_file_descriptor_data(file, &mut w);
        }
    }

    Some(compiler_plugin::GenResult {
        name: format!("{}.rs", proto_path_to_rust_mod(file.get_name())),
        content: v,
    })
}

// This function is also used externally by cargo plugin
// https://github.com/plietar/rust-protobuf-build
// So be careful changing its signature.
pub fn gen(
    file_descriptors: &[FileDescriptorProto],
    files_to_generate: &[PathBuf],
    customize: &Customize,
) -> Vec<compiler_plugin::GenResult> {
    let root_scope = RootScope {
        file_descriptors: file_descriptors,
    };

    let mut results: Vec<compiler_plugin::GenResult> = Vec::new();
    let files_map: HashMap<&Path, &FileDescriptorProto> =
        file_descriptors.iter().map(|f| (Path::new(f.get_name()), f)).collect();

    for file_name in files_to_generate {
        let file = files_map.get(file_name.as_path()).expect(&format!(
            "file not found in file descriptors: {:?}, files: {:?}",
            file_name, files_map.keys()
        ));
        results.extend(gen_file(file, &files_map, &root_scope, customize));
    }
    results
}

pub fn gen_and_write(
    file_descriptors: &[FileDescriptorProto],
    files_to_generate: &[PathBuf],
    out_dir: &Path,
    customize: &Customize,
) -> io::Result<()> {
    let results = gen(file_descriptors, files_to_generate, customize);

    for r in &results {
        let mut file_path = out_dir.to_owned();
        file_path.push(&r.name);
        let mut file_writer = File::create(&file_path)
            .map_err(|e| amend_io_error(e, format!("failed to create {:?}", file_path)))?;
        file_writer
            .write_all(&r.content)
            .map_err(|e| amend_io_error(e, format!("failed to write to {:?}", file_path)))?;
        file_writer
            .flush()
            .map_err(|e| amend_io_error(e, format!("failed to flush {:?}", file_path)))?;
    }

    Ok(())
}

pub fn protoc_gen_rust_main() {
    compiler_plugin::plugin_main(|r| {
        let customize = Customize::parse_from_parameter(r.parameter).expect("parse options");
        gen(r.file_descriptors, r.files_to_generate, &customize)
    });
}
<commit_msg>Return error in codegen explicitly if out_dir does not exist<commit_after>extern crate protobuf;
extern crate proc_macro;

use std::collections::hash_map::HashMap;
use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};

use protobuf::descriptor::*;
use protobuf::Message;

use protobuf::prelude::*;

mod amend_io_error_util;
mod compiler_plugin;
mod customize;
mod enums;
mod file;
mod extensions;
mod field;
mod rust_name;
mod protobuf_name;
mod map;
mod message;
mod oneof;
mod rust_types_values;
mod serde;
mod well_known_types;
pub mod case_convert;
mod file_descriptor;
pub(crate) mod file_and_mod;

pub(crate) mod scope;
pub(crate) mod syntax;
pub(crate) mod strx;
pub(crate) mod rust;

use customize::customize_from_rustproto_for_file;
pub use customize::Customize;

pub mod code_writer;

use self::code_writer::CodeWriter;
use self::enums::*;
use self::extensions::*;
use self::message::*;
#[doc(hidden)]
pub use amend_io_error_util::amend_io_error;
use map::map_entry;
use scope::RootScope;
use scope::FileScope;
use file::proto_path_to_rust_mod;

pub use protobuf_name::ProtobufIdent;
pub use protobuf_name::ProtobufAbsolutePath;
pub use protobuf_name::ProtobufRelativePath;

fn escape_byte(s: &mut String, b: u8) {
    if b == b'\n' {
        write!(s, "\\n").unwrap();
    } else if b == b'\r' {
        write!(s, "\\r").unwrap();
    } else if b == b'\t' {
        write!(s, "\\t").unwrap();
    } else if b == b'\\' || b == b'"' {
        write!(s, "\\{}", b as char).unwrap();
    } else if b == b'\0' {
        write!(s, "\\0").unwrap();
    // ASCII printable except space
    } else if b > 0x20 && b < 0x7f {
        write!(s, "{}", b as char).unwrap();
    } else {
        write!(s, "\\x{:02x}", b).unwrap();
    }
}

fn write_file_descriptor_data(file: &FileDescriptorProto, w: &mut CodeWriter) {
    let fdp_bytes = file.write_to_bytes().unwrap();
    w.write_line("static file_descriptor_proto_data: &'static [u8] = b\"\\");
    w.indented(|w| {
        const MAX_LINE_LEN: usize = 72;

        let mut s = String::new();
        for &b in &fdp_bytes {
            let prev_len = s.len();
            escape_byte(&mut s, b);
            let truncate = s.len() > MAX_LINE_LEN;
            if truncate {
                s.truncate(prev_len);
            }
            if truncate || s.len() == MAX_LINE_LEN {
                write!(s, "\\").unwrap();
                w.write_line(&s);
                s.clear();
            }
            if truncate {
                escape_byte(&mut s, b);
            }
        }
        if !s.is_empty() {
            write!(s, "\\").unwrap();
            w.write_line(&s);
            s.clear();
        }
    });
    w.write_line("\";");
    w.write_line("");
    w.lazy_static(
        "file_descriptor_proto_lazy",
        "::protobuf::descriptor::FileDescriptorProto",
    );
    w.write_line("");
    w.def_fn(
        "parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto",
        |w| {
            w.write_line("::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap()");
        },
    );
    w.write_line("");
    w.pub_fn(
        "file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto",
        |w| {
            w.block("file_descriptor_proto_lazy.get(|| {", "})", |w| {
                w.write_line("parse_descriptor_proto()");
            });
        },
    );
}

fn gen_file(
    file: &FileDescriptorProto,
    _files_map: &HashMap<&Path, &FileDescriptorProto>,
    root_scope: &RootScope,
    customize: &Customize,
) -> Option<compiler_plugin::GenResult> {
    // TODO: use it
    let mut customize = customize.clone();
    // options specified in invocation have precedence over options specified in file
    customize.update_with(&customize_from_rustproto_for_file(
        file.options.get_message(),
    ));

    let scope = FileScope {
        file_descriptor: file,
    }.to_scope();
    let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
        file
            .options
            .get_message()
            .get_optimize_for()
            == file_options::OptimizeMode::LITE_RUNTIME
    });

    let mut v = Vec::new();

    {
        let mut w = CodeWriter::new(&mut v);

        w.write_generated_by("rust-protobuf", env!("CARGO_PKG_VERSION"));

        for message in &scope.get_messages() {
            // ignore map entries, because they are not used in map fields
            if map_entry(message).is_none() {
                w.write_line("");
                MessageGen::new(message, &root_scope, &customize).write(&mut w);
            }
        }
        for enum_type in &scope.get_enums() {
            w.write_line("");
            EnumGen::new(enum_type, &customize, root_scope).write(&mut w);
        }

        write_extensions(file, &root_scope, &mut w);

        if !lite_runtime {
            w.write_line("");
            write_file_descriptor_data(file, &mut w);
        }
    }

    Some(compiler_plugin::GenResult {
        name: format!("{}.rs", proto_path_to_rust_mod(file.get_name())),
        content: v,
    })
}

// This function is also used externally by cargo plugin
// https://github.com/plietar/rust-protobuf-build
// So be careful changing its signature.
pub fn gen(
    file_descriptors: &[FileDescriptorProto],
    files_to_generate: &[PathBuf],
    customize: &Customize,
) -> Vec<compiler_plugin::GenResult> {
    let root_scope = RootScope {
        file_descriptors: file_descriptors,
    };

    let mut results: Vec<compiler_plugin::GenResult> = Vec::new();
    let files_map: HashMap<&Path, &FileDescriptorProto> =
        file_descriptors.iter().map(|f| (Path::new(f.get_name()), f)).collect();

    for file_name in files_to_generate {
        let file = files_map.get(file_name.as_path()).expect(&format!(
            "file not found in file descriptors: {:?}, files: {:?}",
            file_name, files_map.keys()
        ));
        results.extend(gen_file(file, &files_map, &root_scope, customize));
    }
    results
}

pub fn gen_and_write(
    file_descriptors: &[FileDescriptorProto],
    files_to_generate: &[PathBuf],
    out_dir: &Path,
    customize: &Customize,
) -> io::Result<()> {
    match out_dir.metadata() {
        Ok(m) => {
            if !m.is_dir() {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                        format!("{} is not a directory", out_dir.display())));
            }
        }
        Err(e) => {
            return Err(amend_io_error(e,
                format!("{} does not exist or not accessible", out_dir.display())));
        }
    }

    let results = gen(file_descriptors, files_to_generate, customize);

    for r in &results {
        let mut file_path = out_dir.to_owned();
        file_path.push(&r.name);
        let mut file_writer = File::create(&file_path)
            .map_err(|e| amend_io_error(e, format!("failed to create {:?}", file_path)))?;
        file_writer
            .write_all(&r.content)
            .map_err(|e| amend_io_error(e, format!("failed to write to {:?}", file_path)))?;
        file_writer
            .flush()
            .map_err(|e| amend_io_error(e, format!("failed to flush {:?}", file_path)))?;
    }

    Ok(())
}

pub fn protoc_gen_rust_main() {
    compiler_plugin::plugin_main(|r| {
        let customize = Customize::parse_from_parameter(r.parameter).expect("parse options");
        gen(r.file_descriptors, r.files_to_generate, &customize)
    });
}
<|endoftext|>


<commit_before>use fall_tree::{NodeType, FileStats};
use lex::Token;

use tree_builder::{Node, TokenSequence};

pub struct Parser<'r> {
    node_types: &'r [NodeType],
    rules: &'r [SynRule],
    start_rule: Expr,
}

#[derive(Serialize, Deserialize)]
pub struct SynRule {
    pub body: Expr,
}

#[derive(Serialize, Deserialize, Debug)]
pub enum Expr {
    Pub(usize, Box<Expr>),
    Or(Vec<Expr>),
    And(Vec<Expr>, Option<usize>),
    Rule(usize),
    Token(usize),
    ContextualToken(usize, String),
    Rep(Box<Expr>),
    WithSkip(Box<Expr>, Box<Expr>),
    Opt(Box<Expr>),
    Not(Box<Expr>),
    NotAhead(Box<Expr>),
    Eof,
    Layer(Box<Expr>, Box<Expr>),
    Pratt(Vec<PrattVariant>),
    Enter(u32, Box<Expr>),
    IsIn(u32),
    Call(Box<Expr>, Vec<(u32, Expr)>),
    Var(u32),
}

#[derive(Serialize, Deserialize, Debug)]
pub enum PrattVariant {
    Atom { body: Box<Expr> },
    Binary {
        ty: usize,
        op: Box<Expr>,
        priority: u32,
    },
    Postfix {
        ty: usize,
        op: Box<Expr>
    }
}

struct Ctx<'p> {
    ticks: u64,
    predicate_mode: bool,
    contexts: [bool; 16],
    args: [Option<&'p Expr>; 16]
}

impl<'p> Ctx<'p> {
    fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::composite(ty)
    }

    fn create_error_node(&mut self) -> Node {
        Node::error()
    }

    fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        tokens.bump()
    }

    fn create_contextual_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>, ty: NodeType, text: &str)
                                       -> Option<(Node, TokenSequence<'t>)> {
        tokens.bump_by_text(ty, text)
    }

    fn create_success_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        Node::success(tokens)
    }

    fn push_child(&self, parent: &mut Node, child: Node) {
        if self.predicate_mode {
            return;
        }
        match child {
            // Microoptimization: don't store empty success nodes
            Node::Composite { ty: None, ref children, .. } if children.is_empty() => return,
            _ => {}
        }
        parent.push_child(child)
    }
}

impl<'r> Parser<'r> {
    pub fn new(node_types: &'r [NodeType], rules: &'r [SynRule]) -> Parser<'r> {
        Parser { node_types, rules: rules, start_rule: Expr::Rule(0) }
    }

    pub fn parse(&self, tokens: TokenSequence, stats: &mut FileStats) -> Node {
        let mut ctx = Ctx { ticks: 0, predicate_mode: false, contexts: [false; 16], args: [None; 16] };
        let (mut file_node, mut leftover) = self
            .parse_exp(&self.start_rule, tokens, &mut ctx)
            .unwrap_or_else(|| {
                let ty = match self.rules[0].body {
                    Expr::Pub(ty, _) => ty,
                    _ => panic!("First rule must be public"),
                };
                let ty = self.node_type(ty);
                (ctx.create_composite_node(Some(ty)), tokens)
            });

        let mut error = ctx.create_error_node();
        let mut skipped = false;
        while leftover.current().is_some() {
            skipped = true;
            let p = ctx.create_leaf_node(leftover);
            leftover = p.1;
            ctx.push_child(&mut error, p.0)
        }
        if skipped {
            ctx.push_child(&mut file_node, error)
        }
        stats.parsing_ticks = ctx.ticks;
        file_node
    }

    fn parse_exp<'t, 'p>(&'p self, expr: &'p Expr, tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                         -> Option<(Node, TokenSequence<'t>)> {
        ctx.ticks += 1;
        match *expr {
            Expr::Pub(ty, ref body) => if let Some((node, ts)) = self.parse_exp(body, tokens, ctx) {
                let mut result = ctx.create_composite_node(Some(self.node_type(ty)));
                ctx.push_child(&mut result, node);
                Some((result, ts))
            } else {
                None
            },

            Expr::Or(ref parts) => self.parse_any(parts.iter(), tokens, ctx),

            Expr::And(ref parts, commit) => {
                let mut node = ctx.create_composite_node(None);
                let commit = commit.unwrap_or(parts.len());
                let mut tokens = tokens;
                for (i, p) in parts.iter().enumerate() {
                    if let Some((n, ts)) = self.parse_exp(p, tokens, ctx) {
                        tokens = ts;
                        ctx.push_child(&mut node, n);
                    } else {
                        if i < commit {
                            return None
                        }
                        let error_node = ctx.create_error_node();
                        ctx.push_child(&mut node, error_node);
                        break
                    }
                }
                Some((node, tokens))
            }

            Expr::Rule(id) => self.parse_exp(&self.rules[id].body, tokens, ctx),

            Expr::Token(ty) => {
                if let Some(current) = tokens.current() {
                    if self.token_set_contains(&[ty], current) {
                        return Some(ctx.create_leaf_node(tokens))
                    }
                }
                None
            }

            Expr::ContextualToken(ty, ref text) => {
                ctx.create_contextual_leaf_node(tokens, self.node_type(ty), &*text)
            }

            Expr::Opt(ref body) => self.parse_exp(body, tokens, ctx).or_else(|| {
                Some(ctx.create_success_node(tokens))
            }),
            Expr::Not(ref expr) => {
                if tokens.current().is_some() && self.parse_exp_pred(expr, tokens, ctx).is_none() {
                    return Some(ctx.create_leaf_node(tokens))
                }
                None
            }
            Expr::NotAhead(ref e) => if self.parse_exp(e, tokens, ctx).is_some() {
                None
            } else {
                Some(ctx.create_success_node(tokens))
            },
            Expr::Eof => if tokens.current().is_none() {
                Some(ctx.create_success_node(tokens))
            } else {
                None
            },
            Expr::Layer(ref l, ref e) => {
                if let Some(rest) = self.parse_exp_pred(l, tokens, ctx) {
                    let mut result = ctx.create_composite_node(None);
                    let layer = tokens.prefix(rest);
                    if let Some((layer_contents, mut leftovers)) = self.parse_exp(e, layer, ctx) {
                        ctx.push_child(&mut result, layer_contents);
                        if leftovers.current().is_some() {
                            let mut error = ctx.create_error_node();
                            while leftovers.current().is_some() {
                                let p = ctx.create_leaf_node(leftovers);
                                ctx.push_child(&mut error, p.0);
                                leftovers = p.1;
                            }
                            ctx.push_child(&mut result, error)
                        }
                    };
                    return Some((result, rest));
                };
                None
            }

            Expr::Rep(ref body) => {
                let mut node = ctx.create_composite_node(None);
                let mut tokens = tokens;
                loop {
                    if let Some((n, t)) = self.parse_exp(body, tokens, ctx) {
                        ctx.push_child(&mut node, n);
                        tokens = t;
                    } else {
                        break;
                    }
                }
                Some((node, tokens))
            }

            Expr::WithSkip(ref first, ref body) => {
                let mut error = ctx.create_error_node();
                let mut result = ctx.create_composite_node(None);
                let mut skipped = false;
                let mut tokens = tokens;
                loop {
                    if tokens.current().is_none() {
                        return None;
                    }
                    if let Some(_) = self.parse_exp_pred(first, tokens, ctx) {
                        if let Some((node, ts)) = self.parse_exp(body, tokens, ctx) {
                            if skipped {
                                ctx.push_child(&mut result, error);
                            }
                            ctx.push_child(&mut result, node);
                            return Some((result, ts));
                        }
                    }

                    skipped = true;
                    let (node, new_tokens) = ctx.create_leaf_node(tokens);
                    tokens = new_tokens;
                    ctx.push_child(&mut error, node);
                }
            }

            Expr::Pratt(ref g) => self.parse_pratt(&*g, tokens, ctx, 0),

            Expr::Enter(idx, ref e) => {
                let idx = idx as usize;
                let old = ctx.contexts[idx];
                ctx.contexts[idx] = true;
                let result = self.parse_exp(&*e, tokens, ctx);
                ctx.contexts[idx] = old;
                result
            }

            Expr::IsIn(idx) => if ctx.contexts[idx as usize] {
                Some(ctx.create_success_node(tokens))
            } else {
                None
            },

            Expr::Call(ref body, ref args) => {
                let old = ctx.args;
                for &(i, ref a) in args.iter() {
                    ctx.args[i as usize] = Some(a);
                }
                let result = self.parse_exp(body, tokens, ctx);
                ctx.args = old;
                result
            }

            Expr::Var(i) => {
                let expr = ctx.args[i as usize].unwrap();
                self.parse_exp(expr, tokens, ctx)
            }
        }
    }

    fn parse_any<'t, 'p, I: Iterator<Item=&'p Expr>>(&'p self, options: I, tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                                                     -> Option<(Node, TokenSequence<'t>)> {
        for p in options {
            if let Some(result) = self.parse_exp(p, tokens, ctx) {
                return Some(result)
            }
        }
        None
    }

    fn parse_pratt<'t, 'p>(&'p self, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>, min_prior: u32)
                           -> Option<(Node, TokenSequence<'t>)> {
        let atoms = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Atom { ref body } => Some(body.as_ref()),
                _ => None
            }
        });

        let (mut lhs, mut tokens) = match self.parse_any(atoms, tokens, ctx) {
            Some(p) => p,
            None => return None
        };

        'outer: loop {
            let postfix = expr_grammar.iter().filter_map(|v| {
                match *v {
                    PrattVariant::Postfix { ty, ref op } => {
                        Some((self.node_type(ty), op.as_ref()))
                    }
                    _ => None
                }
            });
            for (ty, op) in postfix {
                if let Some((op_node, rest)) = self.parse_exp(op, tokens, ctx) {
                    let mut node = ctx.create_composite_node(Some(ty));
                    ::std::mem::swap(&mut node, &mut lhs);
                    ctx.push_child(&mut lhs, node);
                    ctx.push_child(&mut lhs, op_node);
                    tokens = rest;
                    continue 'outer;
                }
            }

            let bins = expr_grammar.iter().filter_map(|v| {
                match *v {
                    PrattVariant::Binary { ty, ref op, priority } if priority > min_prior => {
                        Some((self.node_type(ty), op.as_ref(), priority))
                    }
                    _ => None
                }
            });

            for (ty, op, p) in bins {
                if let Some((op_node, rest)) = self.parse_exp(op, tokens, ctx) {
                    if let Some((rhs_node, rest)) = self.parse_pratt(expr_grammar, rest, ctx, p) {
                        let mut node = ctx.create_composite_node(Some(ty));
                        ::std::mem::swap(&mut node, &mut lhs);
                        ctx.push_child(&mut lhs, node);
                        ctx.push_child(&mut lhs, op_node);
                        ctx.push_child(&mut lhs, rhs_node);
                        tokens = rest;
                        continue 'outer;
                    }
                }
            }
            break
        }
        Some((lhs, tokens))
    }

    fn parse_exp_pred<'t, 'p>(&'p self, expr: &'p Expr, tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                              -> Option<(TokenSequence<'t>)> {
        let old_mode = ctx.predicate_mode;
        ctx.predicate_mode = true;
        let result = self.parse_exp(expr, tokens, ctx);
        ctx.predicate_mode = old_mode;
        result.map(|(_, ts)| ts)
    }

    fn token_set_contains(&self, ts: &[usize], token: Token) -> bool {
        ts.iter().any(|&t| self.node_type(t) == token.ty)
    }

    fn node_type(&self, idx: usize) -> NodeType {
        self.node_types[idx]
    }
}
<commit_msg>Simplify<commit_after>use fall_tree::{NodeType, FileStats};

use tree_builder::{Node, TokenSequence};

pub struct Parser<'r> {
    node_types: &'r [NodeType],
    rules: &'r [SynRule],
    start_rule: Expr,
}

#[derive(Serialize, Deserialize)]
pub struct SynRule {
    pub body: Expr,
}

#[derive(Serialize, Deserialize, Debug)]
pub enum Expr {
    Pub(usize, Box<Expr>),
    Or(Vec<Expr>),
    And(Vec<Expr>, Option<usize>),
    Rule(usize),
    Token(usize),
    ContextualToken(usize, String),
    Rep(Box<Expr>),
    WithSkip(Box<Expr>, Box<Expr>),
    Opt(Box<Expr>),
    Not(Box<Expr>),
    NotAhead(Box<Expr>),
    Eof,
    Layer(Box<Expr>, Box<Expr>),
    Pratt(Vec<PrattVariant>),
    Enter(u32, Box<Expr>),
    IsIn(u32),
    Call(Box<Expr>, Vec<(u32, Expr)>),
    Var(u32),
}

#[derive(Serialize, Deserialize, Debug)]
pub enum PrattVariant {
    Atom { body: Box<Expr> },
    Binary {
        ty: usize,
        op: Box<Expr>,
        priority: u32,
    },
    Postfix {
        ty: usize,
        op: Box<Expr>
    }
}

struct Ctx<'p> {
    ticks: u64,
    predicate_mode: bool,
    contexts: [bool; 16],
    args: [Option<&'p Expr>; 16]
}

impl<'p> Ctx<'p> {
    fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::composite(ty)
    }

    fn create_error_node(&mut self) -> Node {
        Node::error()
    }

    fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        tokens.bump()
    }

    fn create_contextual_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>, ty: NodeType, text: &str)
                                       -> Option<(Node, TokenSequence<'t>)> {
        tokens.bump_by_text(ty, text)
    }

    fn create_success_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        Node::success(tokens)
    }

    fn push_child(&self, parent: &mut Node, child: Node) {
        if self.predicate_mode {
            return;
        }
        match child {
            // Microoptimization: don't store empty success nodes
            Node::Composite { ty: None, ref children, .. } if children.is_empty() => return,
            _ => {}
        }
        parent.push_child(child)
    }
}

impl<'r> Parser<'r> {
    pub fn new(node_types: &'r [NodeType], rules: &'r [SynRule]) -> Parser<'r> {
        Parser { node_types, rules: rules, start_rule: Expr::Rule(0) }
    }

    pub fn parse(&self, tokens: TokenSequence, stats: &mut FileStats) -> Node {
        let mut ctx = Ctx { ticks: 0, predicate_mode: false, contexts: [false; 16], args: [None; 16] };
        let (mut file_node, mut leftover) = self
            .parse_exp(&self.start_rule, tokens, &mut ctx)
            .unwrap_or_else(|| {
                let ty = match self.rules[0].body {
                    Expr::Pub(ty, _) => ty,
                    _ => panic!("First rule must be public"),
                };
                let ty = self.node_type(ty);
                (ctx.create_composite_node(Some(ty)), tokens)
            });

        let mut error = ctx.create_error_node();
        let mut skipped = false;
        while leftover.current().is_some() {
            skipped = true;
            let p = ctx.create_leaf_node(leftover);
            leftover = p.1;
            ctx.push_child(&mut error, p.0)
        }
        if skipped {
            ctx.push_child(&mut file_node, error)
        }
        stats.parsing_ticks = ctx.ticks;
        file_node
    }

    fn parse_exp<'t, 'p>(&'p self, expr: &'p Expr, tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                         -> Option<(Node, TokenSequence<'t>)> {
        ctx.ticks += 1;
        match *expr {
            Expr::Pub(ty, ref body) => if let Some((node, ts)) = self.parse_exp(body, tokens, ctx) {
                let mut result = ctx.create_composite_node(Some(self.node_type(ty)));
                ctx.push_child(&mut result, node);
                Some((result, ts))
            } else {
                None
            },

            Expr::Or(ref parts) => self.parse_any(parts.iter(), tokens, ctx),

            Expr::And(ref parts, commit) => {
                let mut node = ctx.create_composite_node(None);
                let commit = commit.unwrap_or(parts.len());
                let mut tokens = tokens;
                for (i, p) in parts.iter().enumerate() {
                    if let Some((n, ts)) = self.parse_exp(p, tokens, ctx) {
                        tokens = ts;
                        ctx.push_child(&mut node, n);
                    } else {
                        if i < commit {
                            return None
                        }
                        let error_node = ctx.create_error_node();
                        ctx.push_child(&mut node, error_node);
                        break
                    }
                }
                Some((node, tokens))
            }

            Expr::Rule(id) => self.parse_exp(&self.rules[id].body, tokens, ctx),

            Expr::Token(ty) => {
                if let Some(current) = tokens.current() {
                    if self.node_type(ty) == current.ty {
                        return Some(ctx.create_leaf_node(tokens))
                    }
                }
                None
            }

            Expr::ContextualToken(ty, ref text) => {
                ctx.create_contextual_leaf_node(tokens, self.node_type(ty), &*text)
            }

            Expr::Opt(ref body) => self.parse_exp(body, tokens, ctx).or_else(|| {
                Some(ctx.create_success_node(tokens))
            }),
            Expr::Not(ref expr) => {
                if tokens.current().is_some() && self.parse_exp_pred(expr, tokens, ctx).is_none() {
                    return Some(ctx.create_leaf_node(tokens))
                }
                None
            }
            Expr::NotAhead(ref e) => if self.parse_exp(e, tokens, ctx).is_some() {
                None
            } else {
                Some(ctx.create_success_node(tokens))
            },
            Expr::Eof => if tokens.current().is_none() {
                Some(ctx.create_success_node(tokens))
            } else {
                None
            },
            Expr::Layer(ref l, ref e) => {
                if let Some(rest) = self.parse_exp_pred(l, tokens, ctx) {
                    let mut result = ctx.create_composite_node(None);
                    let layer = tokens.prefix(rest);
                    if let Some((layer_contents, mut leftovers)) = self.parse_exp(e, layer, ctx) {
                        ctx.push_child(&mut result, layer_contents);
                        if leftovers.current().is_some() {
                            let mut error = ctx.create_error_node();
                            while leftovers.current().is_some() {
                                let p = ctx.create_leaf_node(leftovers);
                                ctx.push_child(&mut error, p.0);
                                leftovers = p.1;
                            }
                            ctx.push_child(&mut result, error)
                        }
                    };
                    return Some((result, rest));
                };
                None
            }

            Expr::Rep(ref body) => {
                let mut node = ctx.create_composite_node(None);
                let mut tokens = tokens;
                loop {
                    if let Some((n, t)) = self.parse_exp(body, tokens, ctx) {
                        ctx.push_child(&mut node, n);
                        tokens = t;
                    } else {
                        break;
                    }
                }
                Some((node, tokens))
            }

            Expr::WithSkip(ref first, ref body) => {
                let mut error = ctx.create_error_node();
                let mut result = ctx.create_composite_node(None);
                let mut skipped = false;
                let mut tokens = tokens;
                loop {
                    if tokens.current().is_none() {
                        return None;
                    }
                    if let Some(_) = self.parse_exp_pred(first, tokens, ctx) {
                        if let Some((node, ts)) = self.parse_exp(body, tokens, ctx) {
                            if skipped {
                                ctx.push_child(&mut result, error);
                            }
                            ctx.push_child(&mut result, node);
                            return Some((result, ts));
                        }
                    }

                    skipped = true;
                    let (node, new_tokens) = ctx.create_leaf_node(tokens);
                    tokens = new_tokens;
                    ctx.push_child(&mut error, node);
                }
            }

            Expr::Pratt(ref g) => self.parse_pratt(&*g, tokens, ctx, 0),

            Expr::Enter(idx, ref e) => {
                let idx = idx as usize;
                let old = ctx.contexts[idx];
                ctx.contexts[idx] = true;
                let result = self.parse_exp(&*e, tokens, ctx);
                ctx.contexts[idx] = old;
                result
            }

            Expr::IsIn(idx) => if ctx.contexts[idx as usize] {
                Some(ctx.create_success_node(tokens))
            } else {
                None
            },

            Expr::Call(ref body, ref args) => {
                let old = ctx.args;
                for &(i, ref a) in args.iter() {
                    ctx.args[i as usize] = Some(a);
                }
                let result = self.parse_exp(body, tokens, ctx);
                ctx.args = old;
                result
            }

            Expr::Var(i) => {
                let expr = ctx.args[i as usize].unwrap();
                self.parse_exp(expr, tokens, ctx)
            }
        }
    }

    fn parse_any<'t, 'p, I: Iterator<Item=&'p Expr>>(&'p self, options: I, tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                                                     -> Option<(Node, TokenSequence<'t>)> {
        for p in options {
            if let Some(result) = self.parse_exp(p, tokens, ctx) {
                return Some(result)
            }
        }
        None
    }

    fn parse_pratt<'t, 'p>(&'p self, expr_grammar: &'p [PrattVariant], tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>, min_prior: u32)
                           -> Option<(Node, TokenSequence<'t>)> {
        let atoms = expr_grammar.iter().filter_map(|v| {
            match *v {
                PrattVariant::Atom { ref body } => Some(body.as_ref()),
                _ => None
            }
        });

        let (mut lhs, mut tokens) = match self.parse_any(atoms, tokens, ctx) {
            Some(p) => p,
            None => return None
        };

        'outer: loop {
            let postfix = expr_grammar.iter().filter_map(|v| {
                match *v {
                    PrattVariant::Postfix { ty, ref op } => {
                        Some((self.node_type(ty), op.as_ref()))
                    }
                    _ => None
                }
            });
            for (ty, op) in postfix {
                if let Some((op_node, rest)) = self.parse_exp(op, tokens, ctx) {
                    let mut node = ctx.create_composite_node(Some(ty));
                    ::std::mem::swap(&mut node, &mut lhs);
                    ctx.push_child(&mut lhs, node);
                    ctx.push_child(&mut lhs, op_node);
                    tokens = rest;
                    continue 'outer;
                }
            }

            let bins = expr_grammar.iter().filter_map(|v| {
                match *v {
                    PrattVariant::Binary { ty, ref op, priority } if priority > min_prior => {
                        Some((self.node_type(ty), op.as_ref(), priority))
                    }
                    _ => None
                }
            });

            for (ty, op, p) in bins {
                if let Some((op_node, rest)) = self.parse_exp(op, tokens, ctx) {
                    if let Some((rhs_node, rest)) = self.parse_pratt(expr_grammar, rest, ctx, p) {
                        let mut node = ctx.create_composite_node(Some(ty));
                        ::std::mem::swap(&mut node, &mut lhs);
                        ctx.push_child(&mut lhs, node);
                        ctx.push_child(&mut lhs, op_node);
                        ctx.push_child(&mut lhs, rhs_node);
                        tokens = rest;
                        continue 'outer;
                    }
                }
            }
            break
        }
        Some((lhs, tokens))
    }

    fn parse_exp_pred<'t, 'p>(&'p self, expr: &'p Expr, tokens: TokenSequence<'t>, ctx: &mut Ctx<'p>)
                              -> Option<(TokenSequence<'t>)> {
        let old_mode = ctx.predicate_mode;
        ctx.predicate_mode = true;
        let result = self.parse_exp(expr, tokens, ctx);
        ctx.predicate_mode = old_mode;
        result.map(|(_, ts)| ts)
    }

    fn node_type(&self, idx: usize) -> NodeType {
        self.node_types[idx]
    }
}
<|endoftext|>


<commit_before>use text_edit::{TextEdit, combine_edits};
use {Node, File};

pub struct FileEdit<'f> {
    file: &'f File,
    inserted: Vec<(Node<'f>, String)>,
    replaced: Vec<(Node<'f>, String)>,
    deleted: Vec<Node<'f>>,
}

impl<'f> FileEdit<'f> {
    pub fn new(file: &File) -> FileEdit {
        FileEdit {
            file: file,
            inserted: Vec::new(),
            replaced: Vec::new(),
            deleted: Vec::new(),
        }
    }

    pub fn replace(&mut self, node: Node<'f>, replacement: Node) {
        self.replace_with_text(node, replacement.text().to_string())
    }

    pub fn replace_with_text(&mut self, node: Node<'f>, replacement: String) {
        self.replaced.push((node, replacement))
    }

    pub fn delete(&mut self, node: Node<'f>) {
        self.deleted.push(node)
    }

    pub fn insert_text_after(&mut self, anchor: Node<'f>, text: String) {
        self.inserted.push((anchor, text))
    }

    pub fn into_text_edit(self) -> TextEdit {
        self.text_edit_for_node(self.file.root())
    }

    fn text_edit_for_node(&self, node: Node<'f>) -> TextEdit {
        if self.deleted.iter().find(|&&n| n == node).is_some() {
            return TextEdit::delete_range(node.range());
        }

        if let Some(&(_, ref replacement)) = self.replaced.iter().find(|&&(n, _)| n == node) {
            return TextEdit::replace_range(node.range(), replacement.clone());
        }

        let mut result = TextEdit::empty();

        for child in node.children() {
            let new_edit = combine_edits(
                self.file.text(),
                &result,
                &self.text_edit_for_node(child)
            ).expect("conflicting edits");
            result = new_edit;
        }

        if let Some(&(_, ref replacement)) = self.inserted.iter().find(|&&(n, _)| n == node) {
            let insert = TextEdit::insert(node.range().end(), replacement.clone());
            let new_edit = combine_edits(self.file.text(), &result, &insert)
                .expect("conflicting edits");
            result = new_edit;
        }
        result
    }
}
<commit_msg>simplify<commit_after>use text_edit::{TextEdit, combine_edits};
use {Node, File};

pub struct FileEdit<'f> {
    file: &'f File,
    inserted: Vec<(Node<'f>, String)>,
    replaced: Vec<(Node<'f>, String)>,
    deleted: Vec<Node<'f>>,
}

impl<'f> FileEdit<'f> {
    pub fn new(file: &File) -> FileEdit {
        FileEdit {
            file,
            inserted: Vec::new(),
            replaced: Vec::new(),
            deleted: Vec::new(),
        }
    }

    pub fn replace(&mut self, node: Node<'f>, replacement: Node) {
        self.replace_with_text(node, replacement.text().to_string())
    }

    pub fn replace_with_text(&mut self, node: Node<'f>, replacement: String) {
        self.replaced.push((node, replacement))
    }

    pub fn delete(&mut self, node: Node<'f>) {
        self.deleted.push(node)
    }

    pub fn insert_text_after(&mut self, anchor: Node<'f>, text: String) {
        self.inserted.push((anchor, text))
    }

    pub fn into_text_edit(self) -> TextEdit {
        self.text_edit_for_node(self.file.root())
    }

    fn text_edit_for_node(&self, node: Node<'f>) -> TextEdit {
        if self.deleted.iter().find(|&&n| n == node).is_some() {
            return TextEdit::delete_range(node.range());
        }

        if let Some(&(_, ref replacement)) = self.replaced.iter().find(|&&(n, _)| n == node) {
            return TextEdit::replace_range(node.range(), replacement.clone());
        }

        let mut result = TextEdit::empty();

        for child in node.children() {
            let new_edit = combine_edits(
                self.file.text(),
                &result,
                &self.text_edit_for_node(child)
            ).expect("conflicting edits");
            result = new_edit;
        }

        if let Some(&(_, ref replacement)) = self.inserted.iter().find(|&&(n, _)| n == node) {
            let insert = TextEdit::insert(node.range().end(), replacement.clone());
            let new_edit = combine_edits(self.file.text(), &result, &insert)
                .expect("conflicting edits");
            result = new_edit;
        }
        result
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate toml;
extern crate regex;

use base::math::*;
use self::clap::{App, Arg, ArgMatches};
use self::regex::Regex;
use std::error::Error as StdError;
use std::path::Path;
use std::fs::File;
use std::io::{Read, Write};
use self::toml::Value;
use std::string::String;

pub struct Config {
    pub resolution: Dimension2u,
    pub window_mode: WindowMode,
    pub window_title: String,
    pub vsync: bool,
    pub seed: u64, /* view range
                    * anti aliasing
                    * Controls
                    * frames
                    * seed
                    * Chunkrange */
}
impl Config {
    /// creates a new Config in three steps:
    /// 1. loads default config
    /// 2. Overrides from toml config file
    /// 3. Overrides from command line
    pub fn load_config() -> Result<Config, Box<StdError>> {
        let matches = App::new("Plantex")
            .version(env!("CARGO_PKG_VERSION"))
            .about("Game about Plants!")
            .arg(Arg::with_name("Resolution")
                .help("(e.g. =1280x720) 'Sets Resolution to new value'")
                .takes_value(true)
                .long("resolution"))
            .arg(Arg::with_name("WindowMode")
                .help("[Windowed, FullScreen] 'Sets WindowMode'")
                .takes_value(true)
                .long("windowmode"))
            .arg(Arg::with_name("Vsync")
                .help("[on/off]")
                .takes_value(true)
                .long("vsync"))
            .arg(Arg::with_name("Seed")
                .help("'Takes a specified seed to generate map'")
                .takes_value(true)
                .long("seed"))
            .arg(Arg::with_name("File")
                .help("Takes config file")
                .takes_value(true)
                .long("config-file"))
            .arg(Arg::with_name("Write_Config_File")
                .help("'Writes Config File with default values'")
                .long("write-config"))
            .get_matches();

        let conf = Config::default();

        if matches.is_present("Write_Config_File") {
            if Path::new("config.toml").exists() {
                return Err("Config.toml already exists".into());
            }
            let toml = r#"
[Graphic]
resolution_width = 800
resolution_height = 600
windowmode = "Windowed"
vsync = true

[Game_settings]
seed = 42
            "#;

            let mut f = try!(File::create("config.toml"));

            try!(f.write_all(&toml.to_string().into_bytes()));
        };

        let t_conf = try!(config_toml(conf, &matches));
        let conf_final = try!(config_command(t_conf, &matches));
        Ok(conf_final)
    }
}

impl Default for Config {
    fn default() -> Self {
        Config {
            resolution: Dimension2::new(800, 600),
            window_mode: WindowMode::Windowed,
            window_title: format!("Plantex {}", env!("CARGO_PKG_VERSION")),
            vsync: false,
            seed: 42,
        }
    }
}

fn config_toml(mut default_config: Config, matches: &ArgMatches) -> Result<Config, Box<StdError>> {
    let mut name = "config.toml";
    if let Some(file) = matches.value_of("File") {
        let file_reg = Regex::new(".*\\.toml").unwrap();

        if file_reg.is_match(file) && Path::new(file).exists() {
            name = file;
        } else {
            return Err("invalid File in command line".into());
        }
    }
    if Path::new(name).exists() {
        let mut f = try!(File::open(name));
        let mut s = String::new();

        try!(f.read_to_string(&mut s));

        let value: Value = match s.parse() {
            Ok(n) => n,
            _ => return Err("corrupted config file".into()),
        };

        let mut res_toml = match value.lookup("Graphic.resolution_width") {
            Some(n) => n,
            None => return Err("resolution_width in config file is invalid".into()),
        };
        let int_res_width = match res_toml.as_integer() {
            Some(n) => {
                if n < 1 {
                    return Err("resolution can not be negative".into());
                } else {
                    n as u32
                }
            }

            None => return Err("resolution_width in config file has no integer".into()),
        };

        res_toml = match value.lookup("Graphic.resolution_height") {
            Some(n) => n,
            None => return Err("resolution_height in config file is invalid".into()),
        };
        let int_res_height = match res_toml.as_integer() {
            Some(n) => {
                if n < 1 {
                    return Err("resolution can not be negative".into());
                } else {
                    n as u32
                }
            }

            None => return Err("resolution_height in config file has no integer".into()),
        };

        default_config.resolution = Dimension2::new(int_res_width, int_res_height);

        let window = match value.lookup("Graphic.windowmode") {
            Some(n) => n,
            None => return Err("resolution_height in config file is invalid".into()),
        };

        match window.as_str() {
            Some(n) => {
                match n {
                    "Windowed" => default_config.window_mode = WindowMode::Windowed,
                    "FullScreen" => default_config.window_mode = WindowMode::FullScreen,
                    _ => return Err("invalid Window Mode in config file".into()),
                }
            }
            _ => return Err("invalid Window Mode in config file".into()),
        }

        let sync = match value.lookup("Graphic.vsync") {
            Some(n) => n,
            None => return Err("resolution_height in config file is invalid".into()),
        };

        match sync.as_bool() {
            Some(n) => default_config.vsync = n,
            None => return Err("vsync value in config file is invalid".into()),
        };

        let seed = match value.lookup("Game_settings.seed") {
            Some(n) => n,
            None => return Err("seed in config file is invalid".into()),
        };

        match seed.as_integer() {
            Some(n) => {
                if n < 0 {
                    return Err("seed can not be negative".into());
                } else {
                    default_config.seed = n as u64
                }
            }
            None => return Err("seed in config file is invalid".into()),
        };

    }

    Ok(default_config)
}

fn config_command(mut toml_config: Config, matches: &ArgMatches) -> Result<Config, Box<StdError>> {

    if let Some(res) = matches.value_of("Resolution") {
        let reg_res = Regex::new(r"^([1-9]\d{1,4})x([1-9]\d{1,4})").unwrap();

        if reg_res.is_match(res) {
            for cap in reg_res.captures_iter(res) {
                let res_x = cap.at(1).unwrap().parse::<u32>().unwrap();
                let res_y = cap.at(2).unwrap().parse::<u32>().unwrap();
                toml_config.resolution = Dimension2::new(res_x, res_y);
            }
        } else {
            return Err("invalid resolution in command line argument".into());
        }
    }

    if let Some(mode) = matches.value_of("WindowMode") {
        match mode {
            "Windowed" => toml_config.window_mode = WindowMode::Windowed,
            "FullScreen" => toml_config.window_mode = WindowMode::FullScreen,
            _ => return Err("invalid Window Mode in command line argument".into()),
        }
    }

    if let Some(sync) = matches.value_of("Vsync") {
        match sync {
            "on" => toml_config.vsync = true,
            "off" => toml_config.vsync = false,
            _ => return Err("Vsync can only be set on or off on command line".into()),
        }
    }

    if let Some(seed) = matches.value_of("Seed") {
        match seed.parse::<u64>() {
            Ok(n) => toml_config.seed = n,
            _ => return Err("Seed from command line is invalid".into()),
        }
    }
    Ok(toml_config)
}
pub enum WindowMode {
    Windowed,
    // FullScreenWindow, // TODO: maybe add this
    FullScreen,
}
<commit_msg>used raw string<commit_after>extern crate clap;
extern crate toml;
extern crate regex;

use base::math::*;
use self::clap::{App, Arg, ArgMatches};
use self::regex::Regex;
use std::error::Error as StdError;
use std::path::Path;
use std::fs::File;
use std::io::{Read, Write};
use self::toml::Value;
use std::string::String;

pub struct Config {
    pub resolution: Dimension2u,
    pub window_mode: WindowMode,
    pub window_title: String,
    pub vsync: bool,
    pub seed: u64, /* view range
                    * anti aliasing
                    * Controls
                    * frames
                    * seed
                    * Chunkrange */
}
impl Config {
    /// creates a new Config in three steps:
    /// 1. loads default config
    /// 2. Overrides from toml config file
    /// 3. Overrides from command line
    pub fn load_config() -> Result<Config, Box<StdError>> {
        let matches = App::new("Plantex")
            .version(env!("CARGO_PKG_VERSION"))
            .about("Game about Plants!")
            .arg(Arg::with_name("Resolution")
                .help("(e.g. =1280x720) 'Sets Resolution to new value'")
                .takes_value(true)
                .long("resolution"))
            .arg(Arg::with_name("WindowMode")
                .help("[Windowed, FullScreen] 'Sets WindowMode'")
                .takes_value(true)
                .long("windowmode"))
            .arg(Arg::with_name("Vsync")
                .help("[on/off]")
                .takes_value(true)
                .long("vsync"))
            .arg(Arg::with_name("Seed")
                .help("'Takes a specified seed to generate map'")
                .takes_value(true)
                .long("seed"))
            .arg(Arg::with_name("File")
                .help("Takes config file")
                .takes_value(true)
                .long("config-file"))
            .arg(Arg::with_name("Write_Config_File")
                .help("'Writes Config File with default values'")
                .long("write-config"))
            .get_matches();

        let conf = Config::default();

        if matches.is_present("Write_Config_File") {
            if Path::new("config.toml").exists() {
                return Err("Config.toml already exists".into());
            }
            let toml = r#"
[Graphic]
resolution_width = 800
resolution_height = 600
windowmode = "Windowed"
vsync = true

[Game_settings]
seed = 42
            "#;

            let mut f = try!(File::create("config.toml"));

            try!(f.write_all(&toml.to_string().into_bytes()));
        };

        let t_conf = try!(config_toml(conf, &matches));
        let conf_final = try!(config_command(t_conf, &matches));
        Ok(conf_final)
    }
}

impl Default for Config {
    fn default() -> Self {
        Config {
            resolution: Dimension2::new(800, 600),
            window_mode: WindowMode::Windowed,
            window_title: format!("Plantex {}", env!("CARGO_PKG_VERSION")),
            vsync: false,
            seed: 42,
        }
    }
}

fn config_toml(mut default_config: Config, matches: &ArgMatches) -> Result<Config, Box<StdError>> {
    let mut name = "config.toml";
    if let Some(file) = matches.value_of("File") {
        let file_reg = Regex::new(r#".*\\.toml"#).unwrap();

        if file_reg.is_match(file) && Path::new(file).exists() {
            name = file;
        } else {
            return Err("invalid File in command line".into());
        }
    }
    if Path::new(name).exists() {
        let mut f = try!(File::open(name));
        let mut s = String::new();

        try!(f.read_to_string(&mut s));

        let value: Value = match s.parse() {
            Ok(n) => n,
            _ => return Err("corrupted config file".into()),
        };

        let mut res_toml = match value.lookup("Graphic.resolution_width") {
            Some(n) => n,
            None => return Err("resolution_width in config file is invalid".into()),
        };
        let int_res_width = match res_toml.as_integer() {
            Some(n) => {
                if n < 1 {
                    return Err("resolution can not be negative".into());
                } else {
                    n as u32
                }
            }

            None => return Err("resolution_width in config file has no integer".into()),
        };

        res_toml = match value.lookup("Graphic.resolution_height") {
            Some(n) => n,
            None => return Err("resolution_height in config file is invalid".into()),
        };
        let int_res_height = match res_toml.as_integer() {
            Some(n) => {
                if n < 1 {
                    return Err("resolution can not be negative".into());
                } else {
                    n as u32
                }
            }

            None => return Err("resolution_height in config file has no integer".into()),
        };

        default_config.resolution = Dimension2::new(int_res_width, int_res_height);

        let window = match value.lookup("Graphic.windowmode") {
            Some(n) => n,
            None => return Err("resolution_height in config file is invalid".into()),
        };

        match window.as_str() {
            Some(n) => {
                match n {
                    "Windowed" => default_config.window_mode = WindowMode::Windowed,
                    "FullScreen" => default_config.window_mode = WindowMode::FullScreen,
                    _ => return Err("invalid Window Mode in config file".into()),
                }
            }
            _ => return Err("invalid Window Mode in config file".into()),
        }

        let sync = match value.lookup("Graphic.vsync") {
            Some(n) => n,
            None => return Err("resolution_height in config file is invalid".into()),
        };

        match sync.as_bool() {
            Some(n) => default_config.vsync = n,
            None => return Err("vsync value in config file is invalid".into()),
        };

        let seed = match value.lookup("Game_settings.seed") {
            Some(n) => n,
            None => return Err("seed in config file is invalid".into()),
        };

        match seed.as_integer() {
            Some(n) => {
                if n < 0 {
                    return Err("seed can not be negative".into());
                } else {
                    default_config.seed = n as u64
                }
            }
            None => return Err("seed in config file is invalid".into()),
        };

    }

    Ok(default_config)
}

fn config_command(mut toml_config: Config, matches: &ArgMatches) -> Result<Config, Box<StdError>> {

    if let Some(res) = matches.value_of("Resolution") {
        let reg_res = Regex::new(r"^([1-9]\d{1,4})x([1-9]\d{1,4})").unwrap();

        if reg_res.is_match(res) {
            for cap in reg_res.captures_iter(res) {
                let res_x = cap.at(1).unwrap().parse::<u32>().unwrap();
                let res_y = cap.at(2).unwrap().parse::<u32>().unwrap();
                toml_config.resolution = Dimension2::new(res_x, res_y);
            }
        } else {
            return Err("invalid resolution in command line argument".into());
        }
    }

    if let Some(mode) = matches.value_of("WindowMode") {
        match mode {
            "Windowed" => toml_config.window_mode = WindowMode::Windowed,
            "FullScreen" => toml_config.window_mode = WindowMode::FullScreen,
            _ => return Err("invalid Window Mode in command line argument".into()),
        }
    }

    if let Some(sync) = matches.value_of("Vsync") {
        match sync {
            "on" => toml_config.vsync = true,
            "off" => toml_config.vsync = false,
            _ => return Err("Vsync can only be set on or off on command line".into()),
        }
    }

    if let Some(seed) = matches.value_of("Seed") {
        match seed.parse::<u64>() {
            Ok(n) => toml_config.seed = n,
            _ => return Err("Seed from command line is invalid".into()),
        }
    }
    Ok(toml_config)
}
pub enum WindowMode {
    Windowed,
    // FullScreenWindow, // TODO: maybe add this
    FullScreen,
}
<|endoftext|>


<commit_before><commit_msg>sync: clean up OnceCell (#3945)<commit_after><|endoftext|>


<commit_before>#![cfg_attr(nightly, feature(custom_derive, plugin))]
#![cfg_attr(nightly, plugin(serde_macros))]

extern crate serde;
extern crate serde_json;

#[cfg(feature = "serde_macros")]
include!("main.rs.in");

#[cfg(not(feature = "serde_macros"))]
include!(concat!(env!("OUT_DIR"), "/main.rs"));
<commit_msg>Fix nightly check in serde-syntex-example<commit_after>#![cfg_attr(feature = "serde_macros", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde_macros", plugin(serde_macros))]

extern crate serde;
extern crate serde_json;

#[cfg(feature = "serde_macros")]
include!("main.rs.in");

#[cfg(not(feature = "serde_macros"))]
include!(concat!(env!("OUT_DIR"), "/main.rs"));
<|endoftext|>