<commit_before>use crate::{FromSql, IsNull, ToSql, Type};
use bytes::buf::BufMutExt;
use bytes::{BufMut, BytesMut};
use serde_1::{Deserialize, Serialize};
use serde_json_1::Value;
use std::error::Error;
use std::fmt::Debug;
use std::io::Read;

/// A wrapper type to allow arbitrary `Serialize`/`Deserialize` types to convert to Postgres JSON values.
#[derive(Debug)]
pub struct Json<T>(pub T);

impl<'a, T> FromSql<'a> for Json<T>
where
    T: Deserialize<'a>,
{
    fn from_sql(ty: &Type, mut raw: &'a [u8]) -> Result<Json<T>, Box<dyn Error + Sync + Send>> {
        if *ty == Type::JSONB {
            let mut b = [0; 1];
            raw.read_exact(&mut b)?;
            // We only support version 1 of the jsonb binary format
            if b[0] != 1 {
                return Err("unsupported JSONB encoding version".into());
            }
        }
        serde_json_1::de::from_slice(raw)
            .map(Json)
            .map_err(Into::into)
    }

    accepts!(JSON, JSONB);
}

impl<T> ToSql for Json<T>
where
    T: Serialize + Debug,
{
    fn to_sql(
        &self,
        ty: &Type,
        out: &mut BytesMut,
    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
        if *ty == Type::JSONB {
            out.put_u8(1);
        }
        serde_json_1::ser::to_writer(out.writer(), &self.0)?;
        Ok(IsNull::No)
    }

    accepts!(JSON, JSONB);
    to_sql_checked!();
}

impl<'a> FromSql<'a> for Value {
    fn from_sql(ty: &Type, raw: &[u8]) -> Result<Value, Box<dyn Error + Sync + Send>> {
        Json::<Value>::from_sql(ty, raw).map(|json| json.0)
    }

    accepts!(JSON, JSONB);
}

impl ToSql for Value {
    fn to_sql(
        &self,
        ty: &Type,
        out: &mut BytesMut,
    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
        Json(self).to_sql(ty, out)
    }

    accepts!(JSON, JSONB);
    to_sql_checked!();
}
<commit_msg>derive Clone, PartialEq and Eq for postgres_types::Json<commit_after>use crate::{FromSql, IsNull, ToSql, Type};
use bytes::buf::BufMutExt;
use bytes::{BufMut, BytesMut};
use serde_1::{Deserialize, Serialize};
use serde_json_1::Value;
use std::error::Error;
use std::fmt::Debug;
use std::io::Read;

/// A wrapper type to allow arbitrary `Serialize`/`Deserialize` types to convert to Postgres JSON values.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Json<T>(pub T);

impl<'a, T> FromSql<'a> for Json<T>
where
    T: Deserialize<'a>,
{
    fn from_sql(ty: &Type, mut raw: &'a [u8]) -> Result<Json<T>, Box<dyn Error + Sync + Send>> {
        if *ty == Type::JSONB {
            let mut b = [0; 1];
            raw.read_exact(&mut b)?;
            // We only support version 1 of the jsonb binary format
            if b[0] != 1 {
                return Err("unsupported JSONB encoding version".into());
            }
        }
        serde_json_1::de::from_slice(raw)
            .map(Json)
            .map_err(Into::into)
    }

    accepts!(JSON, JSONB);
}

impl<T> ToSql for Json<T>
where
    T: Serialize + Debug,
{
    fn to_sql(
        &self,
        ty: &Type,
        out: &mut BytesMut,
    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
        if *ty == Type::JSONB {
            out.put_u8(1);
        }
        serde_json_1::ser::to_writer(out.writer(), &self.0)?;
        Ok(IsNull::No)
    }

    accepts!(JSON, JSONB);
    to_sql_checked!();
}

impl<'a> FromSql<'a> for Value {
    fn from_sql(ty: &Type, raw: &[u8]) -> Result<Value, Box<dyn Error + Sync + Send>> {
        Json::<Value>::from_sql(ty, raw).map(|json| json.0)
    }

    accepts!(JSON, JSONB);
}

impl ToSql for Value {
    fn to_sql(
        &self,
        ty: &Type,
        out: &mut BytesMut,
    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
        Json(self).to_sql(ty, out)
    }

    accepts!(JSON, JSONB);
    to_sql_checked!();
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use libra_types::transaction::ScriptABI;
use serde_generate as serdegen;
use serde_generate::SourceInstaller as _;
use serde_reflection::Registry;
use std::{io::Write, process::Command};
use tempfile::tempdir;
use transaction_builder_generator as buildgen;
use transaction_builder_generator::SourceInstaller as _;

fn get_libra_registry() -> Registry {
    let path = "../../testsuite/generate-format/tests/staged/libra.yaml";
    let content = std::fs::read_to_string(path).unwrap();
    serde_yaml::from_str::<Registry>(content.as_str()).unwrap()
}

fn get_stdlib_script_abis() -> Vec<ScriptABI> {
    let path = "../stdlib/compiled/transaction_scripts/abi";
    buildgen::read_abis(path).expect("reading ABI files should not fail")
}

// Cannot run this test in the CI of Libra.
#[test]
#[ignore]
fn test_that_python_code_parses_and_passes_pyre_check() {
    let registry = get_libra_registry();
    let abis = get_stdlib_script_abis();
    let dir = tempdir().unwrap();

    let src_dir_path = dir.path().join("src");
    let installer =
        serdegen::python3::Installer::new(src_dir_path.clone(), /* package */ None);
    installer.install_module("libra_types", &registry).unwrap();
    installer.install_serde_runtime().unwrap();

    let builder_dir_path = src_dir_path.join("libra_builders");
    std::fs::create_dir_all(builder_dir_path.clone()).unwrap();
    let source_path = builder_dir_path.join("__init__.py");

    let mut source = std::fs::File::create(&source_path).unwrap();
    buildgen::python3::output(&mut source, &abis).unwrap();

    let python_path = format!(
        "{}:{}",
        std::env::var("PYTHONPATH").unwrap_or_default(),
        src_dir_path.to_string_lossy(),
    );
    let status = Command::new("python3")
        .arg("-c")
        .arg("import serde_types; import libra_types; import libra_builders")
        .env("PYTHONPATH", python_path)
        .status()
        .unwrap();
    assert!(status.success());

    // This temporarily requires a checkout of serde-reflection.git next to libra.git
    // Hopefully, numpy's next release will include typeshed (.pyi) files and we will only
    // require a local install of numpy (on top of python3 and pyre).
    let status = Command::new("cp")
        .arg("-r")
        .arg("../../../serde-reflection/serde-generate/runtime/python/typeshed")
        .arg(dir.path())
        .status()
        .unwrap();
    assert!(status.success());

    let mut pyre_config = std::fs::File::create(dir.path().join(".pyre_configuration")).unwrap();
    writeln!(
        &mut pyre_config,
        r#"{{
  "source_directories": [
    "src"
  ],
  "search_path": [
    "typeshed"
  ]
}}"#,
    )
    .unwrap();

    let status = Command::new("pyre")
        .current_dir(dir.path())
        .arg("check")
        .status()
        .unwrap();
    assert!(status.success());
}

#[test]
fn test_that_rust_code_compiles() {
    let registry = get_libra_registry();
    let abis = get_stdlib_script_abis();
    let dir = tempdir().unwrap();

    let installer = serdegen::rust::Installer::new(dir.path().to_path_buf());
    installer.install_module("libra-types", &registry).unwrap();

    let builder_dir_path = dir.path().join("libra-builders");
    std::fs::create_dir_all(builder_dir_path.clone()).unwrap();

    let mut cargo = std::fs::File::create(&builder_dir_path.join("Cargo.toml")).unwrap();
    write!(
        cargo,
        r#"[package]
name = "libra-builders"
version = "0.1.0"
edition = "2018"

[dependencies]
libra-types = {{ path = "../libra-types", version = "0.1.0" }}
serde_bytes = "0.11"
"#,
    )
    .unwrap();
    std::fs::create_dir(builder_dir_path.join("src")).unwrap();
    let source_path = builder_dir_path.join("src/lib.rs");
    let mut source = std::fs::File::create(&source_path).unwrap();
    buildgen::rust::output(&mut source, &abis, /* local types */ false).unwrap();

    // Use a stable `target` dir to avoid downloading and recompiling crates everytime.
    let target_dir = std::env::current_dir().unwrap().join("../../target");
    let status = Command::new("cargo")
        .current_dir(dir.path().join("libra-builders"))
        .arg("build")
        .arg("--target-dir")
        .arg(target_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

#[test]
#[ignore]
fn test_that_cpp_code_compiles() {
    let registry = get_libra_registry();
    let abis = get_stdlib_script_abis();
    let dir = tempdir().unwrap();

    let lcs_installer = serdegen::cpp::Installer::new(dir.path().to_path_buf());
    lcs_installer
        .install_module("libra_types", &registry)
        .unwrap();
    lcs_installer.install_serde_runtime().unwrap();

    let abi_installer = buildgen::cpp::Installer::new(dir.path().to_path_buf());
    abi_installer
        .install_transaction_builders("libra_builder", &abis)
        .unwrap();

    let status = Command::new("clang++")
        .arg("--std=c++17")
        .arg("-g")
        .arg("-c")
        .arg(dir.path().join("libra_builder.cpp"))
        .status()
        .unwrap();
    assert!(status.success());
}

#[test]
#[ignore]
fn test_that_java_code_compiles() {
    let registry = get_libra_registry();
    let abis = get_stdlib_script_abis();
    let dir = tempdir().unwrap();

    let lcs_installer = serdegen::java::Installer::new(dir.path().to_path_buf());
    lcs_installer
        .install_module("org.libra.types", &registry)
        .unwrap();
    lcs_installer.install_serde_runtime().unwrap();

    let abi_installer = buildgen::java::Installer::new(dir.path().to_path_buf());
    abi_installer
        .install_transaction_builders("org.libra.builder.Builder", &abis)
        .unwrap();

    let paths = std::iter::empty()
        .chain(std::fs::read_dir(dir.path().join("com/facebook/serde")).unwrap())
        .chain(std::fs::read_dir(dir.path().join("org/libra/types")).unwrap())
        .chain(std::fs::read_dir(dir.path().join("org/libra/builder")).unwrap())
        .map(|e| e.unwrap().path());

    let status = Command::new("javac")
        .arg("-cp")
        .arg(dir.path())
        .arg("-d")
        .arg(dir.path())
        .args(paths)
        .status()
        .unwrap();
    assert!(status.success());
}
<commit_msg>[transaction-builder-generator][nit] clean up C++ test<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use libra_types::transaction::ScriptABI;
use serde_generate as serdegen;
use serde_generate::SourceInstaller as _;
use serde_reflection::Registry;
use std::{io::Write, process::Command};
use tempfile::tempdir;
use transaction_builder_generator as buildgen;
use transaction_builder_generator::SourceInstaller as _;

fn get_libra_registry() -> Registry {
    let path = "../../testsuite/generate-format/tests/staged/libra.yaml";
    let content = std::fs::read_to_string(path).unwrap();
    serde_yaml::from_str::<Registry>(content.as_str()).unwrap()
}

fn get_stdlib_script_abis() -> Vec<ScriptABI> {
    let path = "../stdlib/compiled/transaction_scripts/abi";
    buildgen::read_abis(path).expect("reading ABI files should not fail")
}

// Cannot run this test in the CI of Libra.
#[test]
#[ignore]
fn test_that_python_code_parses_and_passes_pyre_check() {
    let registry = get_libra_registry();
    let abis = get_stdlib_script_abis();
    let dir = tempdir().unwrap();

    let src_dir_path = dir.path().join("src");
    let installer =
        serdegen::python3::Installer::new(src_dir_path.clone(), /* package */ None);
    installer.install_module("libra_types", &registry).unwrap();
    installer.install_serde_runtime().unwrap();

    let builder_dir_path = src_dir_path.join("libra_builders");
    std::fs::create_dir_all(builder_dir_path.clone()).unwrap();
    let source_path = builder_dir_path.join("__init__.py");

    let mut source = std::fs::File::create(&source_path).unwrap();
    buildgen::python3::output(&mut source, &abis).unwrap();

    let python_path = format!(
        "{}:{}",
        std::env::var("PYTHONPATH").unwrap_or_default(),
        src_dir_path.to_string_lossy(),
    );
    let status = Command::new("python3")
        .arg("-c")
        .arg("import serde_types; import libra_types; import libra_builders")
        .env("PYTHONPATH", python_path)
        .status()
        .unwrap();
    assert!(status.success());

    // This temporarily requires a checkout of serde-reflection.git next to libra.git
    // Hopefully, numpy's next release will include typeshed (.pyi) files and we will only
    // require a local install of numpy (on top of python3 and pyre).
    let status = Command::new("cp")
        .arg("-r")
        .arg("../../../serde-reflection/serde-generate/runtime/python/typeshed")
        .arg(dir.path())
        .status()
        .unwrap();
    assert!(status.success());

    let mut pyre_config = std::fs::File::create(dir.path().join(".pyre_configuration")).unwrap();
    writeln!(
        &mut pyre_config,
        r#"{{
  "source_directories": [
    "src"
  ],
  "search_path": [
    "typeshed"
  ]
}}"#,
    )
    .unwrap();

    let status = Command::new("pyre")
        .current_dir(dir.path())
        .arg("check")
        .status()
        .unwrap();
    assert!(status.success());
}

#[test]
fn test_that_rust_code_compiles() {
    let registry = get_libra_registry();
    let abis = get_stdlib_script_abis();
    let dir = tempdir().unwrap();

    let installer = serdegen::rust::Installer::new(dir.path().to_path_buf());
    installer.install_module("libra-types", &registry).unwrap();

    let builder_dir_path = dir.path().join("libra-builders");
    std::fs::create_dir_all(builder_dir_path.clone()).unwrap();

    let mut cargo = std::fs::File::create(&builder_dir_path.join("Cargo.toml")).unwrap();
    write!(
        cargo,
        r#"[package]
name = "libra-builders"
version = "0.1.0"
edition = "2018"

[dependencies]
libra-types = {{ path = "../libra-types", version = "0.1.0" }}
serde_bytes = "0.11"
"#,
    )
    .unwrap();
    std::fs::create_dir(builder_dir_path.join("src")).unwrap();
    let source_path = builder_dir_path.join("src/lib.rs");
    let mut source = std::fs::File::create(&source_path).unwrap();
    buildgen::rust::output(&mut source, &abis, /* local types */ false).unwrap();

    // Use a stable `target` dir to avoid downloading and recompiling crates everytime.
    let target_dir = std::env::current_dir().unwrap().join("../../target");
    let status = Command::new("cargo")
        .current_dir(dir.path().join("libra-builders"))
        .arg("build")
        .arg("--target-dir")
        .arg(target_dir)
        .status()
        .unwrap();
    assert!(status.success());
}

#[test]
#[ignore]
fn test_that_cpp_code_compiles() {
    let registry = get_libra_registry();
    let abis = get_stdlib_script_abis();
    let dir = tempdir().unwrap();

    let lcs_installer = serdegen::cpp::Installer::new(dir.path().to_path_buf());
    lcs_installer
        .install_module("libra_types", &registry)
        .unwrap();
    lcs_installer.install_serde_runtime().unwrap();

    let abi_installer = buildgen::cpp::Installer::new(dir.path().to_path_buf());
    abi_installer
        .install_transaction_builders("libra_builder", &abis)
        .unwrap();

    let status = Command::new("clang++")
        .arg("--std=c++17")
        .arg("-g")
        .arg("-c")
        .arg(dir.path().join("libra_builder.cpp"))
        .arg("-o")
        .arg(dir.path().join("libra_builder.o"))
        .status()
        .unwrap();
    assert!(status.success());
}

#[test]
#[ignore]
fn test_that_java_code_compiles() {
    let registry = get_libra_registry();
    let abis = get_stdlib_script_abis();
    let dir = tempdir().unwrap();

    let lcs_installer = serdegen::java::Installer::new(dir.path().to_path_buf());
    lcs_installer
        .install_module("org.libra.types", &registry)
        .unwrap();
    lcs_installer.install_serde_runtime().unwrap();

    let abi_installer = buildgen::java::Installer::new(dir.path().to_path_buf());
    abi_installer
        .install_transaction_builders("org.libra.builder.Builder", &abis)
        .unwrap();

    let paths = std::iter::empty()
        .chain(std::fs::read_dir(dir.path().join("com/facebook/serde")).unwrap())
        .chain(std::fs::read_dir(dir.path().join("org/libra/types")).unwrap())
        .chain(std::fs::read_dir(dir.path().join("org/libra/builder")).unwrap())
        .map(|e| e.unwrap().path());

    let status = Command::new("javac")
        .arg("-cp")
        .arg(dir.path())
        .arg("-d")
        .arg(dir.path())
        .args(paths)
        .status()
        .unwrap();
    assert!(status.success());
}
<|endoftext|>


<commit_before>use std::time::{Instant, Duration};
use rand::Rng;

use crate::progress::Progress;
use crate::sim::TestPacket;
use crate::dijkstra::Dijkstra;
use crate::graph::*;

/*
 * Test if all paths allow for routing.
 * This test does not allow the state of the routing algorithm to change.
 */
pub struct PassiveRoutingTest {
	show_progress: bool,
	is_done: bool,
	packets_send: u32,
	packets_lost: u32,
	packets_arrived: u32,
	route_costs_sum: u32,
	route_costs_min_sum: u32,
	nodes_connected: usize,
	nodes_disconnected: usize,
	run_time: Duration,
	dijkstra: Dijkstra
}

impl PassiveRoutingTest {
	pub fn new() -> Self {
		Self {
			show_progress: false,
			is_done: false,
			packets_send: 0,
			packets_lost: 0,
			packets_arrived: 0,
			route_costs_sum: 0,
			route_costs_min_sum: 0,
			nodes_connected: 0,
			nodes_disconnected: 0,
			run_time: Duration::new(0, 0),
			dijkstra: Dijkstra::new(),
		}
	}

	pub fn clear_stats(&mut self) {
		self.is_done =false;
		self.packets_send = 0;
		self.packets_lost = 0;
		self.packets_arrived = 0;
		self.route_costs_sum = 0;
		self.route_costs_min_sum = 0;
		self.nodes_connected = 0;
		self.nodes_disconnected = 0;
		self.run_time = Duration::new(0, 0);
	}

	pub fn clear(&mut self) {
		self.dijkstra.clear();
		self.clear_stats();
	}

	pub fn show_progress(&mut self, show_progress: bool) {
		self.show_progress = true;
	}

	fn test_path(&mut self, graph: &Graph, mut route: impl FnMut(&TestPacket) -> Option<u32>,
			source: ID, target: ID, costs_min: u32) {
		// maximum stretch we record
		let max_stretch = 2;
		let mut packet = TestPacket::new(source, source, source, target);
		let mut costs = 0u32;

		self.packets_send += 1;

		// max steps to try until we give up
		let max_steps = costs_min * max_stretch;

		for _ in 0..max_steps {
			if let Some(next) = route(&packet) {
				// Check if link really exists
				if let Some(link) = graph.get_link(packet.receiver, next) {
					costs += link.cost() as u32;
					if next == packet.destination {
						// packet arrived
						self.packets_arrived += 1;
						self.route_costs_sum += costs;
						self.route_costs_min_sum += costs_min;
						break;
					} else {
						// forward packet
						packet.transmitter = packet.receiver;
						packet.receiver = next;
					}
				} else {
					self.packets_lost += 1;
					break;
				}
			} else {
				self.packets_lost += 1;
				break;
			}
		}
	}

	pub fn run_samples(&mut self, graph: &Graph, mut route: impl FnMut(&TestPacket) -> Option<u32>,
			samples: usize) {
		self.clear();

		let node_count = graph.node_count();
		if node_count < 2 {
			return;
		}

		let now = Instant::now();
		let mut progress = Progress::new();
		let mut sample = 0;

		if self.show_progress {
			progress.start(samples, 0);
		}

		for _ in 0..samples {
			let source = rand::thread_rng().gen_range(0, node_count);
			let target = rand::thread_rng().gen_range(0, node_count);

			if source == target {
				// we do not test those paths
				continue;
			}

			let min = self.dijkstra.find_shortest_distance(graph, source as ID, target as ID);
			if !min.is_finite() {
				// no path from target to source => ignore
				self.nodes_disconnected += 1;
				continue;
			} else {
				self.nodes_connected += 1;
			}

			self.test_path(&graph, &mut route, source as ID, target as ID, min as u32);

			sample += 1;

			if self.show_progress {
				progress.update(samples, sample);
			}
		}

		if self.show_progress {
			progress.update(samples, samples);
		}

		self.run_time = now.elapsed();
		self.is_done = true;
	}

	pub fn run_all(&mut self, graph: &Graph, mut route: impl FnMut(&TestPacket) -> Option<u32>) {
		self.clear();

		let node_count = graph.node_count();
		if node_count < 2 {
			return;
		}

		let now = Instant::now();
		let tests = (node_count as usize).pow(2);
		//let mut progress = Progress::new("test: ");
		//let mut test = 0;

		//progress.start(tests, 0);
		for source in 0..node_count {
			for target in 0..node_count {
				if source == target {
					continue;
				}

				let min = self.dijkstra.find_shortest_distance(graph, source as ID, target as ID);
				if !min.is_finite() {
					// no path from target to source => ignore
					self.nodes_disconnected += 1;
					continue;
				} else {
					self.nodes_connected += 1;
				}

				self.test_path(&graph, &mut route, source as ID, target as ID, min as u32);

				//test += 1;
				//progress.update(tests, test);
			}
		}

		self.run_time = now.elapsed();

		//clear progress line
		//progress.clear_line();
	}

	pub fn duration(&self) -> Duration {
		self.run_time
	}

	pub fn stretch(&self) -> f32 {
		(self.route_costs_sum as f32) / (self.route_costs_min_sum as f32)
	}

	pub fn arrived(&self) -> f32 {
		100.0 * (self.packets_arrived as f32) / (self.packets_send as f32)
	}

	pub fn connectivity(&self) -> f32 {
		100.0 * (self.nodes_connected as f32) / (self.nodes_connected + self.nodes_disconnected) as f32
	}

	pub fn get_results(&self) -> Vec<(&'static str, f32)> {
		vec![
			("arrived", self.arrived()),
			("connectivity", self.connectivity()),
			("stretch", self.stretch())
		]
	}
}
<commit_msg>fix passive routing test<commit_after>use std::time::{Instant, Duration};
use rand::Rng;

use crate::progress::Progress;
use crate::sim::TestPacket;
use crate::dijkstra::Dijkstra;
use crate::graph::*;

/*
 * Test if all paths allow for routing.
 * This test does not allow the state of the routing algorithm to change.
 */
pub struct PassiveRoutingTest {
	show_progress: bool,
	is_done: bool,
	packets_send: u32,
	packets_lost: u32,
	packets_arrived: u32,
	route_costs_sum: u32,
	route_costs_min_sum: u32,
	nodes_connected: usize,
	nodes_disconnected: usize,
	max_stretch: u32,
	run_time: Duration,
	dijkstra: Dijkstra
}

impl PassiveRoutingTest {
	pub fn new() -> Self {
		Self {
			show_progress: false,
			is_done: false,
			packets_send: 0,
			packets_lost: 0,
			packets_arrived: 0,
			route_costs_sum: 0,
			route_costs_min_sum: 0,
			nodes_connected: 0,
			nodes_disconnected: 0,
			max_stretch: 2,
			run_time: Duration::new(0, 0),
			dijkstra: Dijkstra::new(),
		}
	}

	pub fn clear_stats(&mut self) {
		self.is_done =false;
		self.packets_send = 0;
		self.packets_lost = 0;
		self.packets_arrived = 0;
		self.route_costs_sum = 0;
		self.route_costs_min_sum = 0;
		self.nodes_connected = 0;
		self.nodes_disconnected = 0;
		self.run_time = Duration::new(0, 0);
	}

	pub fn clear(&mut self) {
		self.dijkstra.clear();
		self.clear_stats();
	}

	pub fn show_progress(&mut self, show_progress: bool) {
		self.show_progress = true;
	}

	fn test_path(&mut self, graph: &Graph, mut route: impl FnMut(&TestPacket) -> Option<u32>,
			source: ID, target: ID, costs_min: u32) {
		// maximum stretch we record
		let mut packet = TestPacket::new(source, source, source, target);
		let mut path_costs = 0u32;

		self.packets_send += 1;

		// max steps to try until we give up
		let max_steps = costs_min * self.max_stretch;

		for _ in 0..max_steps {
			if let Some(next) = route(&packet) {
				// Check if link really exists
				if let Some(link) = graph.get_link(packet.receiver, next) {
					path_costs += link.cost() as u32;
					if next == packet.destination {
						// packet arrived
						self.packets_arrived += 1;
						break;
					} else {
						// forward packet
						packet.transmitter = packet.receiver;
						packet.receiver = next;
					}
				} else {
					// invalid next hop
					self.packets_lost += 1;
					break;
				}
			} else {
				// no next hop
				self.packets_lost += 1;
				break;
			}
		}

		self.route_costs_sum += path_costs;
		self.route_costs_min_sum += costs_min;
	}

	pub fn run_samples(&mut self, graph: &Graph, mut route: impl FnMut(&TestPacket) -> Option<u32>,
			samples: usize) {
		self.clear();

		let node_count = graph.node_count();
		if node_count < 2 {
			return;
		}

		let now = Instant::now();
		let mut progress = Progress::new();
		let mut sample = 0;

		if self.show_progress {
			progress.start(samples, 0);
		}

		for _ in 0..samples {
			let source = rand::thread_rng().gen_range(0, node_count);
			let target = rand::thread_rng().gen_range(0, node_count);

			if source == target {
				// we do not test those paths
				continue;
			}

			let min = self.dijkstra.find_shortest_distance(graph, source as ID, target as ID);
			if !min.is_finite() {
				// no path from target to source => ignore
				self.nodes_disconnected += 1;
				continue;
			} else {
				self.nodes_connected += 1;
			}

			self.test_path(&graph, &mut route, source as ID, target as ID, min as u32);

			sample += 1;

			if self.show_progress {
				progress.update(samples, sample);
			}
		}

		if self.show_progress {
			progress.update(samples, samples);
		}

		self.run_time = now.elapsed();
		self.is_done = true;
	}

	pub fn run_all(&mut self, graph: &Graph, mut route: impl FnMut(&TestPacket) -> Option<u32>) {
		self.clear();

		let node_count = graph.node_count();
		if node_count < 2 {
			return;
		}

		let now = Instant::now();
		let tests = (node_count as usize).pow(2);
		//let mut progress = Progress::new("test: ");
		//let mut test = 0;

		//progress.start(tests, 0);
		for source in 0..node_count {
			for target in 0..node_count {
				if source == target {
					continue;
				}

				let min = self.dijkstra.find_shortest_distance(graph, source as ID, target as ID);
				if !min.is_finite() {
					// no path from target to source => ignore
					self.nodes_disconnected += 1;
					continue;
				} else {
					self.nodes_connected += 1;
				}

				self.test_path(&graph, &mut route, source as ID, target as ID, min as u32);

				//test += 1;
				//progress.update(tests, test);
			}
		}

		self.run_time = now.elapsed();

		//clear progress line
		//progress.clear_line();
	}

	pub fn duration(&self) -> Duration {
		self.run_time
	}

	pub fn stretch(&self) -> f32 {
		(self.route_costs_sum as f32) / (self.route_costs_min_sum as f32)
	}

	pub fn arrived(&self) -> f32 {
		100.0 * (self.packets_arrived as f32) / (self.packets_send as f32)
	}

	pub fn connectivity(&self) -> f32 {
		100.0 * (self.nodes_connected as f32) / (self.nodes_connected + self.nodes_disconnected) as f32
	}

	pub fn get_results(&self) -> Vec<(&'static str, f32)> {
		vec![
			("arrived", self.arrived()),
			("connectivity", self.connectivity()),
			("stretch", self.stretch())
		]
	}
}
<|endoftext|>


<commit_before>use prodbg_api::read_write::{Reader, Writer};
use prodbg_api::backend::{CBackendCallbacks};
use plugins::PluginHandler;
use reader_wrapper::{ReaderWrapper, WriterWrapper};
use backend_plugin::{BackendHandle, BackendPlugins};
use libc::{c_void};

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct SessionHandle(pub u64);

///! Session is a major part of ProDBG. There can be several sessions active at the same time
///! and each session has exactly one backend. There are only communication internally in a session
///! sessions can't (at least now) not talk to eachother.
///!
///! A backend can have several views at the same time. Data can be sent between the backend and
///| views using the PDReader/PDWriter APIs (prodbg::Writer prodbg::Reader in Rust) and this is the
///| only way for views and backends to talk with each other. There are several reasons for this
///| approach:
///!
///| 1. No "hacks" on trying to share memory. Plugins can be over a socket/webview/etc.
///! 2. Views and backends makes no assumetions on the inner workings of the others.
///! 3. Backends and views can post messages which anyone can decide to (optionally) act on.
///!
pub struct Session {
    pub handle: SessionHandle,
    pub reader: Reader,

    current_writer: usize,
    writers: [Writer; 2],

    backend: Option<BackendHandle>,
}

///! Connection options for Remote connections. Currently just one Ip adderss
///!
pub struct ConnectionSettings<'a> {
    pub address: &'a str,
}

impl Session {
    pub fn new(handle: SessionHandle) -> Session {
        Session {
            handle: handle,
            writers: [
                WriterWrapper::create_writer(),
                WriterWrapper::create_writer(),
            ],
            reader: ReaderWrapper::create_reader(),
            current_writer: 0,
            backend: None,
        }
    }

    pub fn get_current_writer(&mut self) -> &mut Writer {
        &mut self.writers[self.current_writer]
    }

    pub fn start_remote(_plugin_handler: &PluginHandler, _settings: &ConnectionSettings) {}

    pub fn start_local(_: &str, _: usize) {}

    pub fn set_backend(&mut self, backend: Option<BackendHandle>) {
        self.backend = backend
    }

    pub fn update(&mut self, backend_plugins: &mut BackendPlugins) {
        // swap the writers
        let c_writer = self.current_writer;
        let p_writer = (self.current_writer + 1) & 1;
        self.current_writer = p_writer;

        println!("{}", self.current_writer);

        ReaderWrapper::init_from_writer(&mut self.reader, &self.writers[p_writer]);
        ReaderWrapper::reset_writer(&mut self.writers[c_writer]);

        if let Some(backend) = backend_plugins.get_backend(self.backend) {
            unsafe {
                let plugin_funcs = backend.plugin_type.plugin_funcs as *mut CBackendCallbacks;
                ((*plugin_funcs).update.unwrap())(backend.plugin_data,
                                                  0,
                                                  self.reader.api as *mut c_void,
                                                  self.writers[p_writer].api as *mut c_void);
            }
        }
    }
}

///
/// Sessions handler
///
pub struct Sessions {
    instances: Vec<Session>,
    current: usize,
    session_counter: SessionHandle,
}

impl Sessions {
    pub fn new() -> Sessions {
        Sessions {
            instances: Vec::new(),
            current: 0,
            session_counter: SessionHandle(0),
        }
    }

    pub fn create_instance(&mut self) -> SessionHandle {
        let s = Session::new(self.session_counter);
        let handle = s.handle;
        self.instances.push(s);
        self.session_counter.0 += 1;
        handle
    }

    pub fn update(&mut self, backend_plugins: &mut BackendPlugins) {
        for session in self.instances.iter_mut() {
            session.update(backend_plugins);
        }
    }

    pub fn get_current(&mut self) -> &mut Session {
        let current = self.current;
        &mut self.instances[current]
    }

    pub fn get_session(&mut self, handle: SessionHandle) -> Option<&mut Session> {
        for i in 0..self.instances.len() {
            if self.instances[i].handle == handle {
                return Some(&mut self.instances[i]);
            }
        }

        None
    }
}

#[cfg(test)]
mod tests {
    use core::reader_wrapper::{ReaderWrapper};
    use super::*;

    #[test]
    fn create_session() {
        let _session = Session::new();
    }

    #[test]
    fn write_simple_event() {
        let mut session = Session::new();

        session.writers[0].event_begin(0x44);
        session.writers[0].event_end();

        ReaderWrapper::init_from_writer(&mut session.reader, &session.writers[0]);

        assert_eq!(session.reader.get_event().unwrap(), 0x44);
    }
}

<commit_msg>Removed spam<commit_after>use prodbg_api::read_write::{Reader, Writer};
use prodbg_api::backend::{CBackendCallbacks};
use plugins::PluginHandler;
use reader_wrapper::{ReaderWrapper, WriterWrapper};
use backend_plugin::{BackendHandle, BackendPlugins};
use libc::{c_void};

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct SessionHandle(pub u64);

///! Session is a major part of ProDBG. There can be several sessions active at the same time
///! and each session has exactly one backend. There are only communication internally in a session
///! sessions can't (at least now) not talk to eachother.
///!
///! A backend can have several views at the same time. Data can be sent between the backend and
///| views using the PDReader/PDWriter APIs (prodbg::Writer prodbg::Reader in Rust) and this is the
///| only way for views and backends to talk with each other. There are several reasons for this
///| approach:
///!
///| 1. No "hacks" on trying to share memory. Plugins can be over a socket/webview/etc.
///! 2. Views and backends makes no assumetions on the inner workings of the others.
///! 3. Backends and views can post messages which anyone can decide to (optionally) act on.
///!
pub struct Session {
    pub handle: SessionHandle,
    pub reader: Reader,

    current_writer: usize,
    writers: [Writer; 2],

    backend: Option<BackendHandle>,
}

///! Connection options for Remote connections. Currently just one Ip adderss
///!
pub struct ConnectionSettings<'a> {
    pub address: &'a str,
}

impl Session {
    pub fn new(handle: SessionHandle) -> Session {
        Session {
            handle: handle,
            writers: [
                WriterWrapper::create_writer(),
                WriterWrapper::create_writer(),
            ],
            reader: ReaderWrapper::create_reader(),
            current_writer: 0,
            backend: None,
        }
    }

    pub fn get_current_writer(&mut self) -> &mut Writer {
        &mut self.writers[self.current_writer]
    }

    pub fn start_remote(_plugin_handler: &PluginHandler, _settings: &ConnectionSettings) {}

    pub fn start_local(_: &str, _: usize) {}

    pub fn set_backend(&mut self, backend: Option<BackendHandle>) {
        self.backend = backend
    }

    pub fn update(&mut self, backend_plugins: &mut BackendPlugins) {
        // swap the writers
        let c_writer = self.current_writer;
        let p_writer = (self.current_writer + 1) & 1;
        self.current_writer = p_writer;

        ReaderWrapper::init_from_writer(&mut self.reader, &self.writers[p_writer]);
        ReaderWrapper::reset_writer(&mut self.writers[c_writer]);

        if let Some(backend) = backend_plugins.get_backend(self.backend) {
            unsafe {
                let plugin_funcs = backend.plugin_type.plugin_funcs as *mut CBackendCallbacks;
                ((*plugin_funcs).update.unwrap())(backend.plugin_data,
                                                  0,
                                                  self.reader.api as *mut c_void,
                                                  self.writers[p_writer].api as *mut c_void);
            }
        }
    }
}

///
/// Sessions handler
///
pub struct Sessions {
    instances: Vec<Session>,
    current: usize,
    session_counter: SessionHandle,
}

impl Sessions {
    pub fn new() -> Sessions {
        Sessions {
            instances: Vec::new(),
            current: 0,
            session_counter: SessionHandle(0),
        }
    }

    pub fn create_instance(&mut self) -> SessionHandle {
        let s = Session::new(self.session_counter);
        let handle = s.handle;
        self.instances.push(s);
        self.session_counter.0 += 1;
        handle
    }

    pub fn update(&mut self, backend_plugins: &mut BackendPlugins) {
        for session in self.instances.iter_mut() {
            session.update(backend_plugins);
        }
    }

    pub fn get_current(&mut self) -> &mut Session {
        let current = self.current;
        &mut self.instances[current]
    }

    pub fn get_session(&mut self, handle: SessionHandle) -> Option<&mut Session> {
        for i in 0..self.instances.len() {
            if self.instances[i].handle == handle {
                return Some(&mut self.instances[i]);
            }
        }

        None
    }
}

#[cfg(test)]
mod tests {
    use core::reader_wrapper::{ReaderWrapper};
    use super::*;

    #[test]
    fn create_session() {
        let _session = Session::new();
    }

    #[test]
    fn write_simple_event() {
        let mut session = Session::new();

        session.writers[0].event_begin(0x44);
        session.writers[0].event_end();

        ReaderWrapper::init_from_writer(&mut session.reader, &session.writers[0]);

        assert_eq!(session.reader.get_event().unwrap(), 0x44);
    }
}

<|endoftext|>


<commit_before>use std::{fmt, str};

use common::{as_alias, column_identifier_no_alias, integer_literal, opt_multispace,
             type_identifier, Literal, SqlType};
use column::Column;

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticOperator {
    Add,
    Subtract,
    Multiply,
    Divide,
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticBase {
    Column(Column),
    Scalar(Literal),
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ArithmeticExpression {
    pub op: ArithmeticOperator,
    pub left: ArithmeticBase,
    pub right: ArithmeticBase,
    pub alias: Option<String>,
}

impl ArithmeticExpression {
    pub fn new(
        op: ArithmeticOperator,
        left: ArithmeticBase,
        right: ArithmeticBase,
        alias: Option<String>,
    ) -> Self {
        Self {
            op: op,
            left: left,
            right: right,
            alias: alias,
        }
    }
}

impl fmt::Display for ArithmeticOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticOperator::Add => write!(f, "+"),
            ArithmeticOperator::Subtract => write!(f, "-"),
            ArithmeticOperator::Multiply => write!(f, "*"),
            ArithmeticOperator::Divide => write!(f, "/"),
        }
    }
}

impl fmt::Display for ArithmeticBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticBase::Column(ref col) => write!(f, "{}", col),
            ArithmeticBase::Scalar(ref lit) => write!(f, "{}", lit.to_string()),
        }
    }
}

impl fmt::Display for ArithmeticExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.alias {
            Some(ref alias) => write!(f, "{} {} {} AS {}", self.left, self.op, self.right, alias),
            None => write!(f, "{} {} {}", self.left, self.op, self.right),
        }
    }
}

named!(pub arithmetic_cast<&[u8], (ArithmeticBase, Option<SqlType>)>,
    alt_complete!(
        do_parse!(
            tag_no_case!("cast") >>
            opt_multispace >>
            tag!("(") >>
            opt_multispace >>
            // TODO(malte): should be arbitrary expr
            v: arithmetic_base >>
            opt_multispace >>
            tag_no_case!("as") >>
            opt_multispace >>
            _sign: opt!(terminated!(tag_no_case!("signed"), opt_multispace)) >>
            typ: type_identifier >>
            opt_multispace >>
            tag!(")") >>
            (v, Some(typ))
        ) |
        do_parse!(
            v: arithmetic_base >>
            (v, None)
        )
    )
);

/// Parse standard math operators.
/// TODO(malte): this doesn't currently observe operator precedence.
named!(pub arithmetic_operator<&[u8], ArithmeticOperator>,
    alt_complete!(
          map!(tag!("+"), |_| ArithmeticOperator::Add)
        | map!(tag!("-"), |_| ArithmeticOperator::Subtract)
        | map!(tag!("*"), |_| ArithmeticOperator::Multiply)
        | map!(tag!("/"), |_| ArithmeticOperator::Divide)
    )
);

/// Base case for nested arithmetic expressions: column name or literal.
named!(pub arithmetic_base<&[u8], ArithmeticBase>,
    alt_complete!(
          map!(integer_literal, |il| ArithmeticBase::Scalar(il))
        | map!(column_identifier_no_alias, |ci| ArithmeticBase::Column(ci))
    )
);

/// Parse simple arithmetic expressions combining literals, and columns and literals.
/// TODO(malte): this doesn't currently support nested expressions.
named!(pub arithmetic_expression<&[u8], ArithmeticExpression>,
    complete!(do_parse!(
        left: arithmetic_cast >>
        opt_multispace >>
        op: arithmetic_operator >>
        opt_multispace >>
        right: arithmetic_cast >>
        alias: opt!(as_alias) >>
        (ArithmeticExpression {
            op: op,
            // TODO(malte): discards casts
            left: left.0,
            right: right.0,
            alias: match alias {
                None => None,
                Some(a) => Some(String::from(a)),
            },
        })
    ))
);

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

    #[test]
    fn it_parses_arithmetic_expressions() {
        use column::FunctionExpression;
        use super::ArithmeticOperator::*;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticBase::Column as ABColumn;

        let lit_ae = [
            "5 + 42",
            "5+42",
            "5 * 42",
            "5 - 42",
            "5 / 42",
            "2 * 10 AS twenty ",
        ];

        // N.B. trailing space in "5 + foo " is required because `sql_identifier`'s keyword
        // detection requires a follow-up character (in practice, there always is one because we
        // use semicolon-terminated queries).
        let col_lit_ae = [
            "foo+5",
            "foo + 5",
            "5 + foo ",
            "foo * bar AS foobar",
            "MAX(foo)-3333",
        ];

        let expected_lit_ae = [
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Multiply, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Divide, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(
                Multiply,
                Scalar(2.into()),
                Scalar(10.into()),
                Some(String::from("twenty")),
            ),
        ];
        let expected_col_lit_ae = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                Some(String::from("foobar")),
            ),
            ArithmeticExpression::new(
                Subtract,
                ABColumn(Column {
                    name: String::from("max(foo)"),
                    alias: None,
                    table: None,
                    function: Some(Box::new(FunctionExpression::Max("foo".into()))),
                }),
                Scalar(3333.into()),
                None,
            ),
        ];

        for (i, e) in lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_done());
            assert_eq!(res.unwrap().1, expected_lit_ae[i]);
        }

        for (i, e) in col_lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_done());
            assert_eq!(res.unwrap().1, expected_col_lit_ae[i]);
        }
    }

    #[test]
    fn it_displays_arithmetic_expressions() {
        use super::ArithmeticOperator::*;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticBase::Column as ABColumn;

        let expressions = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                None,
            ),
            ArithmeticExpression::new(Divide, Scalar(10.into()), Scalar(2.into()), None),
            ArithmeticExpression::new(
                Add,
                Scalar(10.into()),
                Scalar(2.into()),
                Some(String::from("bob")),
            ),
        ];

        let expected_strings = ["foo + 5", "5 - foo", "foo * bar", "10 / 2", "10 + 2 AS bob"];
        for (i, e) in expressions.iter().enumerate() {
            assert_eq!(expected_strings[i], format!("{}", e));
        }
    }

    #[test]
    fn it_parses_arithmetic_casts() {
        use super::ArithmeticOperator::*;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticBase::Column as ABColumn;

        let exprs = [
            "CAST(`t`.`foo` AS signed int) + CAST(`t`.`bar` AS signed int) ",
            "CAST(5 AS bigint) - foo ",
        ];

        // XXX(malte): currently discards the cast and type information!
        let expected = [
            ArithmeticExpression::new(
                Add,
                ABColumn(Column::from("t.foo")),
                ABColumn(Column::from("t.bar")),
                None,
            ),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
        ];

        for (i, e) in exprs.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_done(), "{} failed to parse", e);
            assert_eq!(res.unwrap().1, expected[i]);
        }
    }

}
<commit_msg>Slightly better tests for casts<commit_after>use nom::multispace;
use std::{fmt, str};

use common::{as_alias, column_identifier_no_alias, integer_literal, opt_multispace,
             type_identifier, Literal, SqlType};
use column::Column;

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticOperator {
    Add,
    Subtract,
    Multiply,
    Divide,
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticBase {
    Column(Column),
    Scalar(Literal),
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ArithmeticExpression {
    pub op: ArithmeticOperator,
    pub left: ArithmeticBase,
    pub right: ArithmeticBase,
    pub alias: Option<String>,
}

impl ArithmeticExpression {
    pub fn new(
        op: ArithmeticOperator,
        left: ArithmeticBase,
        right: ArithmeticBase,
        alias: Option<String>,
    ) -> Self {
        Self {
            op: op,
            left: left,
            right: right,
            alias: alias,
        }
    }
}

impl fmt::Display for ArithmeticOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticOperator::Add => write!(f, "+"),
            ArithmeticOperator::Subtract => write!(f, "-"),
            ArithmeticOperator::Multiply => write!(f, "*"),
            ArithmeticOperator::Divide => write!(f, "/"),
        }
    }
}

impl fmt::Display for ArithmeticBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticBase::Column(ref col) => write!(f, "{}", col),
            ArithmeticBase::Scalar(ref lit) => write!(f, "{}", lit.to_string()),
        }
    }
}

impl fmt::Display for ArithmeticExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.alias {
            Some(ref alias) => write!(f, "{} {} {} AS {}", self.left, self.op, self.right, alias),
            None => write!(f, "{} {} {}", self.left, self.op, self.right),
        }
    }
}

named!(pub arithmetic_cast<&[u8], (ArithmeticBase, Option<SqlType>)>,
    alt_complete!(
        do_parse!(
            tag_no_case!("cast") >>
            opt_multispace >>
            tag!("(") >>
            opt_multispace >>
            // TODO(malte): should be arbitrary expr
            v: arithmetic_base >>
            multispace >>
            tag_no_case!("as") >>
            multispace >>
            _sign: opt!(terminated!(tag_no_case!("signed"), multispace)) >>
            typ: type_identifier >>
            opt_multispace >>
            tag!(")") >>
            (v, Some(typ))
        ) |
        map!(arithmetic_base, |v| (v, None))
    )
);

/// Parse standard math operators.
/// TODO(malte): this doesn't currently observe operator precedence.
named!(pub arithmetic_operator<&[u8], ArithmeticOperator>,
    alt_complete!(
          map!(tag!("+"), |_| ArithmeticOperator::Add)
        | map!(tag!("-"), |_| ArithmeticOperator::Subtract)
        | map!(tag!("*"), |_| ArithmeticOperator::Multiply)
        | map!(tag!("/"), |_| ArithmeticOperator::Divide)
    )
);

/// Base case for nested arithmetic expressions: column name or literal.
named!(pub arithmetic_base<&[u8], ArithmeticBase>,
    alt_complete!(
          map!(integer_literal, |il| ArithmeticBase::Scalar(il))
        | map!(column_identifier_no_alias, |ci| ArithmeticBase::Column(ci))
    )
);

/// Parse simple arithmetic expressions combining literals, and columns and literals.
/// TODO(malte): this doesn't currently support nested expressions.
named!(pub arithmetic_expression<&[u8], ArithmeticExpression>,
    complete!(do_parse!(
        left: arithmetic_cast >>
        opt_multispace >>
        op: arithmetic_operator >>
        opt_multispace >>
        right: arithmetic_cast >>
        alias: opt!(as_alias) >>
        (ArithmeticExpression {
            op: op,
            // TODO(malte): discards casts
            left: left.0,
            right: right.0,
            alias: match alias {
                None => None,
                Some(a) => Some(String::from(a)),
            },
        })
    ))
);

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

    #[test]
    fn it_parses_arithmetic_expressions() {
        use column::FunctionExpression;
        use super::ArithmeticOperator::*;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticBase::Column as ABColumn;

        let lit_ae = [
            "5 + 42",
            "5+42",
            "5 * 42",
            "5 - 42",
            "5 / 42",
            "2 * 10 AS twenty ",
        ];

        // N.B. trailing space in "5 + foo " is required because `sql_identifier`'s keyword
        // detection requires a follow-up character (in practice, there always is one because we
        // use semicolon-terminated queries).
        let col_lit_ae = [
            "foo+5",
            "foo + 5",
            "5 + foo ",
            "foo * bar AS foobar",
            "MAX(foo)-3333",
        ];

        let expected_lit_ae = [
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Multiply, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Divide, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(
                Multiply,
                Scalar(2.into()),
                Scalar(10.into()),
                Some(String::from("twenty")),
            ),
        ];
        let expected_col_lit_ae = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                Some(String::from("foobar")),
            ),
            ArithmeticExpression::new(
                Subtract,
                ABColumn(Column {
                    name: String::from("max(foo)"),
                    alias: None,
                    table: None,
                    function: Some(Box::new(FunctionExpression::Max("foo".into()))),
                }),
                Scalar(3333.into()),
                None,
            ),
        ];

        for (i, e) in lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_done());
            assert_eq!(res.unwrap().1, expected_lit_ae[i]);
        }

        for (i, e) in col_lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_done());
            assert_eq!(res.unwrap().1, expected_col_lit_ae[i]);
        }
    }

    #[test]
    fn it_displays_arithmetic_expressions() {
        use super::ArithmeticOperator::*;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticBase::Column as ABColumn;

        let expressions = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                None,
            ),
            ArithmeticExpression::new(Divide, Scalar(10.into()), Scalar(2.into()), None),
            ArithmeticExpression::new(
                Add,
                Scalar(10.into()),
                Scalar(2.into()),
                Some(String::from("bob")),
            ),
        ];

        let expected_strings = ["foo + 5", "5 - foo", "foo * bar", "10 / 2", "10 + 2 AS bob"];
        for (i, e) in expressions.iter().enumerate() {
            assert_eq!(expected_strings[i], format!("{}", e));
        }
    }

    #[test]
    fn it_parses_arithmetic_casts() {
        use super::ArithmeticOperator::*;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticBase::Column as ABColumn;

        let exprs = [
            "CAST(`t`.`foo` AS signed int) + CAST(`t`.`bar` AS signed int) ",
            "CAST(5 AS bigint) - foo ",
            "CAST(5 AS bigint) - foo AS 5_minus_foo",
        ];

        // XXX(malte): currently discards the cast and type information!
        let expected = [
            ArithmeticExpression::new(
                Add,
                ABColumn(Column::from("t.foo")),
                ABColumn(Column::from("t.bar")),
                None,
            ),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Subtract,
                Scalar(5.into()),
                ABColumn("foo".into()),
                Some("5_minus_foo".into()),
            ),
        ];

        for (i, e) in exprs.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_done(), "{} failed to parse", e);
            assert_eq!(res.unwrap().1, expected[i]);
        }
    }

}
<|endoftext|>


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

struct VM {
	stack: Vec<Operator>,
}

impl VM {
	fn pop <'a> (&'a mut self, ret: &mut Operator) {
		*ret = self.stack.pop().expect("gg reinstall");
	}

	fn push <'a> (&'a mut self, op: Operator) {
		self.stack.push(op);
	}

	fn eval <'a> (&'a mut self, op: Operator) {

	}
}

enum Operator {
	//stack
	Dup,
	Drop,
	Swap,
	Over,
	Rot,

	//debug
	Print,

	//math
	Add,
	Subtract,
	Multiply,
	Divide,
	Mod,
	And,
	Or,
	Xor,
	Lshift,
	Rshift,
	Abs,
	Max,
	Min,
	Invert,
	Negate,

	//custom
	Define,

	//values and custom calls
	Value(i32),
	Other,
}

fn parse(s: &str) -> Operator {
	match s {
		//stack operations:
		"dup" => Operator::Dup,
		"drop" => Operator::Drop,
		"swap" => Operator::Swap,
		"over" => Operator::Over,
		"rot" => Operator::Rot,

		//debug operations:
		"." => Operator::Print,

		//math operations:
		"+" => Operator::Add,
		"-" => Operator::Subtract,
		"*" => Operator::Multiply,
		"/" => Operator::Divide,
		"mod" => Operator::Mod,
		"and" => Operator::And,
		"or" => Operator::Or,
		"xor" => Operator::Xor,
		"lshift" => Operator::Lshift,
		"<<" => Operator::Lshift,
		"rshift" => Operator::Rshift,
		">>" => Operator::Rshift,
		"abs" => Operator::Abs,
		"max" => Operator::Max,
		"min" => Operator::Min,
		"invert" => Operator::Invert,
		"negate" => Operator::Negate,

		//custom definitions
		":" => Operator::Define,

		//value or custom operator
		x => {
			let y: Option<i32> = FromStr::from_str(x).ok();
			match y{
				Some(i) => Operator::Value(i),
				None => Operator::Other,
			}
		},
	}
}

fn main() {
	let mut x = io::stdin();
	let mut vm = VM {stack: vec![Operator::Print]};

	loop{
		let mut line: String = "".to_string();
		let _ = x.read_line(&mut line);

		for o in line.split(" "){
			println!("evaling: {}", o.trim());
			let b = parse(o.trim());
			vm.eval(b);
		}
	}
}
<commit_msg>implements add function<commit_after>use std::io;
use std::str::FromStr;

struct VM {
	stack: Vec<Operator>,
}

impl VM {
	fn pop <'a> (&'a mut self, ret: &mut Operator) {
		*ret = self.stack.pop().expect("gg reinstall");
	}

	fn push <'a> (&'a mut self, op: Operator) {
		self.stack.push(op);
	}

	fn eval <'a> (&'a mut self, op: Operator) {

	}

	fn add <'a> (&'a mut self) {
		let mut x = Operator::Other;
		let mut y = Operator::Other;
		self.pop(&mut x);
		self.pop(&mut y);
		let z = match x{
			Operator::Value(i) => match y{
				Operator::Value(j) => i+j,
				_ => panic!("can only add ints"),
			},
			_ => panic!("can only add ints"),
		};
		self.push(Operator::Value(z));
	}
}

enum Operator {
	//stack
	Dup,
	Drop,
	Swap,
	Over,
	Rot,

	//debug
	Print,

	//math
	Add,
	Subtract,
	Multiply,
	Divide,
	Mod,
	And,
	Or,
	Xor,
	Lshift,
	Rshift,
	Abs,
	Max,
	Min,
	Invert,
	Negate,

	//custom
	Define,

	//values and custom calls
	Value(i32),
	Other,
}

fn parse(s: &str) -> Operator {
	match s {
		//stack operations:
		"dup" => Operator::Dup,
		"drop" => Operator::Drop,
		"swap" => Operator::Swap,
		"over" => Operator::Over,
		"rot" => Operator::Rot,

		//debug operations:
		"." => Operator::Print,

		//math operations:
		"+" => Operator::Add,
		"-" => Operator::Subtract,
		"*" => Operator::Multiply,
		"/" => Operator::Divide,
		"mod" => Operator::Mod,
		"and" => Operator::And,
		"or" => Operator::Or,
		"xor" => Operator::Xor,
		"lshift" => Operator::Lshift,
		"<<" => Operator::Lshift,
		"rshift" => Operator::Rshift,
		">>" => Operator::Rshift,
		"abs" => Operator::Abs,
		"max" => Operator::Max,
		"min" => Operator::Min,
		"invert" => Operator::Invert,
		"negate" => Operator::Negate,

		//custom definitions
		":" => Operator::Define,

		//value or custom operator
		x => {
			let y: Option<i32> = FromStr::from_str(x).ok();
			match y{
				Some(i) => Operator::Value(i),
				None => Operator::Other,
			}
		},
	}
}

fn main() {
	let mut x = io::stdin();
	let mut vm = VM {stack: vec![Operator::Print]};

	loop{
		let mut line: String = "".to_string();
		let _ = x.read_line(&mut line);

		for o in line.split(" "){
			println!("evaling: {}", o.trim());
			let b = parse(o.trim());
			vm.eval(b);
		}
	}
}
<|endoftext|>


<commit_before>use std::io::stdin;

fn main() {

	let mut x = stdin();

	loop{
		let mut y: String = "".to_string();
		let _ = x.read_line(&mut y);

		let z = y.chars().next();
	    println!("Hello, world! {}", match z{
	    	Some(b) => match b{
	    		'+' => "addition!",
	    		_ => "other!",
	    	},
	    	None => "none!",
	    });
	}
}
<commit_msg>operator enum<commit_after>use std::io::stdin;

enum Operator {
	Add,
	Subtract,
	Push,
	Pop,
	None,
}

fn parse(s: String) -> Operator {
	let c = s.chars().next();
	match c {
		Some(i) => match i {
		'+' => Operator::Add,
		'-' => Operator::Subtract,
		_ => Operator::Push,
		},
		None => Operator::None,
	}

}

fn main() {

	let mut x = stdin();

	loop{
		let mut y: String = "".to_string();
		let _ = x.read_line(&mut y);

		let z = parse(y);
	    println!("{}", match z{
	    	Operator::Add => "Addition!",
	    	Operator::Subtract => "Subtraction!",
	    	_ => "other!",
	    });
	}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate mdbook;
#[macro_use]
extern crate clap;

// Dependencies for the Watch feature
#[cfg(feature = "watch")]
extern crate notify;
#[cfg(feature = "watch")]
extern crate time;
#[cfg(feature = "watch")]
extern crate crossbeam;

// Dependencies for the Serve feature
#[cfg(feature = "serve")]
extern crate iron;
#[cfg(feature = "serve")]
extern crate staticfile;
#[cfg(feature = "serve")]
extern crate ws;

use std::env;
use std::error::Error;
use std::io::{self, Write};
use std::path::{Path, PathBuf};

use clap::{App, ArgMatches, SubCommand, AppSettings};

// Uses for the Watch feature
#[cfg(feature = "watch")]
use notify::Watcher;
#[cfg(feature = "watch")]
use std::sync::mpsc::channel;

use mdbook::MDBook;

const NAME: &'static str = "mdbook";

fn main() {
    // Create a list of valid arguments and sub-commands
    let matches = App::new(NAME)
                    .about("Create a book in form of a static website from markdown files")
                    .author("Mathieu David <mathieudavid@mathieudavid.org>")
                    // Get the version from our Cargo.toml using clap's crate_version!() macro
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .after_help("For more information about a specific command, try `mdbook <command> --help`\nSource code for mdbook available at: https://github.com/azerupi/mdBook")
                    .subcommand(SubCommand::with_name("init")
                        .about("Create boilerplate structure and files in the directory")
                        // the {n} denotes a newline which will properly aligned in all help messages
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")
                        .arg_from_usage("--theme 'Copies the default theme into your source folder'")
                        .arg_from_usage("--force 'skip confirmation prompts'"))
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
                    .subcommand(SubCommand::with_name("watch")
                        .about("Watch the files for changes")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
                    .subcommand(SubCommand::with_name("serve")
                        .about("Serve the book at http://localhost:3000. Rebuild and reload on change.")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")
                        .arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'")
                        .arg_from_usage("-w, --websocket-port=[ws-port] 'Use another port for the websocket connection (livereload){n}(Defaults to 3001)'")
                        .arg_from_usage("-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'")
                        .arg_from_usage("-a, --address=[address] 'Address that the browser can reach the websocket server from{n}(Defaults to the interface addres)'"))
                    .subcommand(SubCommand::with_name("test")
                        .about("Test that code samples compile"))
                    .get_matches();

    // Check which subcomamnd the user ran...
    let res = match matches.subcommand() {
        ("init", Some(sub_matches)) => init(sub_matches),
        ("build", Some(sub_matches)) => build(sub_matches),
        #[cfg(feature = "watch")]
        ("watch", Some(sub_matches)) => watch(sub_matches),
        #[cfg(feature = "serve")]
        ("serve", Some(sub_matches)) => serve(sub_matches),
        ("test", Some(sub_matches)) => test(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
    }
}

// Simple function that user comfirmation
fn confirm() -> bool {
    io::stdout().flush().unwrap();
    let mut s = String::new();
    io::stdin().read_line(&mut s).ok();
    match &*s.trim() {
        "Y" | "y" | "yes" | "Yes" => true,
        _ => false,
    }
}

// Init command implementation
fn init(args: &ArgMatches) -> Result<(), Box<Error>> {

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir);

    // Call the function that does the initialization
    try!(book.init());

    // If flag `--theme` is present, copy theme to src
    if args.is_present("theme") {

        // Skip this if `--force` is present
        if !args.is_present("force") {
            // Print warning
            print!("\nCopying the default theme to {:?}", book.get_src());
            println!("could potentially overwrite files already present in that directory.");
            print!("\nAre you sure you want to continue? (y/n) ");

            // Read answer from user and exit if it's not 'yes'
            if !confirm() {
                println!("\nSkipping...\n");
                println!("All done, no errors...");
                ::std::process::exit(0);
            }
        }

        // Call the function that copies the theme
        try!(book.copy_theme());
        println!("\nTheme copied.");

    }

    // Because of `src/book/mdbook.rs#L37-L39`, `dest` will always start with `root`
    let is_dest_inside_root = book.get_dest().starts_with(book.get_root());

    if !args.is_present("force") && is_dest_inside_root {
        println!("\nDo you want a .gitignore to be created? (y/n)");

        if confirm() {
            book.create_gitignore();
            println!("\n.gitignore created.");
        }
    }

    println!("\nAll done, no errors...");

    Ok(())
}

// Build command implementation
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    try!(book.build());

    Ok(())
}

// Watch command implementation
#[cfg(feature = "watch")]
fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    trigger_on_change(&mut book, |event, book| {
        if let Some(path) = event.path {
            println!("File changed: {:?}\nBuilding book...\n", path);
            match book.build() {
                Err(e) => println!("Error while building: {:?}", e),
                _ => {},
            }
            println!("");
        }
    });

    Ok(())
}

// Watch command implementation
#[cfg(feature = "serve")]
fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
    const RELOAD_COMMAND: &'static str = "reload";

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();
    let port = args.value_of("port").unwrap_or("3000");
    let ws_port = args.value_of("ws-port").unwrap_or("3001");
    let interface = args.value_of("interface").unwrap_or("localhost");
    let public_address = args.value_of("address").unwrap_or(interface);

    let address = format!("{}:{}", interface, port);
    let ws_address = format!("{}:{}", interface, ws_port);

    book.set_livereload(format!(r#"
        <script type="text/javascript">
            var socket = new WebSocket("ws://{}:{}");
            socket.onmessage = function (event) {{
                if (event.data === "{}") {{
                    socket.close();
                    location.reload(true); // force reload from server (not from cache)
                }}
            }};

            window.onbeforeunload = function() {{
                socket.close();
            }}
        </script>
    "#, public_address, ws_port, RELOAD_COMMAND).to_owned());

    try!(book.build());

    let staticfile = staticfile::Static::new(book.get_dest());
    let iron = iron::Iron::new(staticfile);
    let _iron = iron.http(&*address).unwrap();

    let ws_server = ws::WebSocket::new(|_| {
        |_| {
            Ok(())
        }
    }).unwrap();

    let broadcaster = ws_server.broadcaster();

    std::thread::spawn(move || {
        ws_server.listen(&*ws_address).unwrap();
    });

    println!("\nServing on {}", address);

    trigger_on_change(&mut book, move |event, book| {
        if let Some(path) = event.path {
            println!("File changed: {:?}\nBuilding book...\n", path);
            match book.build() {
                Err(e) => println!("Error while building: {:?}", e),
                _ => broadcaster.send(RELOAD_COMMAND).unwrap(),
            }
            println!("");
        }
    });

    Ok(())
}

fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    try!(book.test());

    Ok(())
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}

// Calls the closure when a book source file is changed. This is blocking!
#[cfg(feature = "watch")]
fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
    where F: Fn(notify::Event, &mut MDBook) -> ()
{
    // Create a channel to receive the events.
    let (tx, rx) = channel();

    let w: Result<notify::RecommendedWatcher, notify::Error> = notify::Watcher::new(tx);

    match w {
        Ok(mut watcher) => {
            // Add the source directory to the watcher
            if let Err(e) = watcher.watch(book.get_src()) {
                println!("Error while watching {:?}:\n    {:?}", book.get_src(), e);
                ::std::process::exit(0);
            };

            // Add the book.json file to the watcher if it exists, because it's not
            // located in the source directory
            if let Err(_) = watcher.watch(book.get_root().join("book.json")) {
                // do nothing if book.json is not found
            }

            let mut previous_time = time::get_time();

            println!("\nListening for changes...\n");

            loop {
                match rx.recv() {
                    Ok(event) => {
                        // Skip the event if an event has already been issued in the last second
                        let time = time::get_time();
                        if time - previous_time < time::Duration::seconds(1) {
                            continue;
                        } else {
                            previous_time = time;
                        }

                        closure(event, book);
                    },
                    Err(e) => {
                        println!("An error occured: {:?}", e);
                    },
                }
            }
        },
        Err(e) => {
            println!("Error while trying to watch the files:\n\n\t{:?}", e);
            ::std::process::exit(0);
        },
    }
}
<commit_msg>Exit with a nonzero status if we get an error<commit_after>#[macro_use]
extern crate mdbook;
#[macro_use]
extern crate clap;

// Dependencies for the Watch feature
#[cfg(feature = "watch")]
extern crate notify;
#[cfg(feature = "watch")]
extern crate time;
#[cfg(feature = "watch")]
extern crate crossbeam;

// Dependencies for the Serve feature
#[cfg(feature = "serve")]
extern crate iron;
#[cfg(feature = "serve")]
extern crate staticfile;
#[cfg(feature = "serve")]
extern crate ws;

use std::env;
use std::error::Error;
use std::io::{self, Write};
use std::path::{Path, PathBuf};

use clap::{App, ArgMatches, SubCommand, AppSettings};

// Uses for the Watch feature
#[cfg(feature = "watch")]
use notify::Watcher;
#[cfg(feature = "watch")]
use std::sync::mpsc::channel;

use mdbook::MDBook;

const NAME: &'static str = "mdbook";

fn main() {
    // Create a list of valid arguments and sub-commands
    let matches = App::new(NAME)
                    .about("Create a book in form of a static website from markdown files")
                    .author("Mathieu David <mathieudavid@mathieudavid.org>")
                    // Get the version from our Cargo.toml using clap's crate_version!() macro
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .after_help("For more information about a specific command, try `mdbook <command> --help`\nSource code for mdbook available at: https://github.com/azerupi/mdBook")
                    .subcommand(SubCommand::with_name("init")
                        .about("Create boilerplate structure and files in the directory")
                        // the {n} denotes a newline which will properly aligned in all help messages
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")
                        .arg_from_usage("--theme 'Copies the default theme into your source folder'")
                        .arg_from_usage("--force 'skip confirmation prompts'"))
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
                    .subcommand(SubCommand::with_name("watch")
                        .about("Watch the files for changes")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
                    .subcommand(SubCommand::with_name("serve")
                        .about("Serve the book at http://localhost:3000. Rebuild and reload on change.")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")
                        .arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'")
                        .arg_from_usage("-w, --websocket-port=[ws-port] 'Use another port for the websocket connection (livereload){n}(Defaults to 3001)'")
                        .arg_from_usage("-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'")
                        .arg_from_usage("-a, --address=[address] 'Address that the browser can reach the websocket server from{n}(Defaults to the interface addres)'"))
                    .subcommand(SubCommand::with_name("test")
                        .about("Test that code samples compile"))
                    .get_matches();

    // Check which subcomamnd the user ran...
    let res = match matches.subcommand() {
        ("init", Some(sub_matches)) => init(sub_matches),
        ("build", Some(sub_matches)) => build(sub_matches),
        #[cfg(feature = "watch")]
        ("watch", Some(sub_matches)) => watch(sub_matches),
        #[cfg(feature = "serve")]
        ("serve", Some(sub_matches)) => serve(sub_matches),
        ("test", Some(sub_matches)) => test(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
        ::std::process::exit(101);
    }
}

// Simple function that user comfirmation
fn confirm() -> bool {
    io::stdout().flush().unwrap();
    let mut s = String::new();
    io::stdin().read_line(&mut s).ok();
    match &*s.trim() {
        "Y" | "y" | "yes" | "Yes" => true,
        _ => false,
    }
}

// Init command implementation
fn init(args: &ArgMatches) -> Result<(), Box<Error>> {

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir);

    // Call the function that does the initialization
    try!(book.init());

    // If flag `--theme` is present, copy theme to src
    if args.is_present("theme") {

        // Skip this if `--force` is present
        if !args.is_present("force") {
            // Print warning
            print!("\nCopying the default theme to {:?}", book.get_src());
            println!("could potentially overwrite files already present in that directory.");
            print!("\nAre you sure you want to continue? (y/n) ");

            // Read answer from user and exit if it's not 'yes'
            if !confirm() {
                println!("\nSkipping...\n");
                println!("All done, no errors...");
                ::std::process::exit(0);
            }
        }

        // Call the function that copies the theme
        try!(book.copy_theme());
        println!("\nTheme copied.");

    }

    // Because of `src/book/mdbook.rs#L37-L39`, `dest` will always start with `root`
    let is_dest_inside_root = book.get_dest().starts_with(book.get_root());

    if !args.is_present("force") && is_dest_inside_root {
        println!("\nDo you want a .gitignore to be created? (y/n)");

        if confirm() {
            book.create_gitignore();
            println!("\n.gitignore created.");
        }
    }

    println!("\nAll done, no errors...");

    Ok(())
}

// Build command implementation
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    try!(book.build());

    Ok(())
}

// Watch command implementation
#[cfg(feature = "watch")]
fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    trigger_on_change(&mut book, |event, book| {
        if let Some(path) = event.path {
            println!("File changed: {:?}\nBuilding book...\n", path);
            match book.build() {
                Err(e) => println!("Error while building: {:?}", e),
                _ => {},
            }
            println!("");
        }
    });

    Ok(())
}

// Watch command implementation
#[cfg(feature = "serve")]
fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
    const RELOAD_COMMAND: &'static str = "reload";

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();
    let port = args.value_of("port").unwrap_or("3000");
    let ws_port = args.value_of("ws-port").unwrap_or("3001");
    let interface = args.value_of("interface").unwrap_or("localhost");
    let public_address = args.value_of("address").unwrap_or(interface);

    let address = format!("{}:{}", interface, port);
    let ws_address = format!("{}:{}", interface, ws_port);

    book.set_livereload(format!(r#"
        <script type="text/javascript">
            var socket = new WebSocket("ws://{}:{}");
            socket.onmessage = function (event) {{
                if (event.data === "{}") {{
                    socket.close();
                    location.reload(true); // force reload from server (not from cache)
                }}
            }};

            window.onbeforeunload = function() {{
                socket.close();
            }}
        </script>
    "#, public_address, ws_port, RELOAD_COMMAND).to_owned());

    try!(book.build());

    let staticfile = staticfile::Static::new(book.get_dest());
    let iron = iron::Iron::new(staticfile);
    let _iron = iron.http(&*address).unwrap();

    let ws_server = ws::WebSocket::new(|_| {
        |_| {
            Ok(())
        }
    }).unwrap();

    let broadcaster = ws_server.broadcaster();

    std::thread::spawn(move || {
        ws_server.listen(&*ws_address).unwrap();
    });

    println!("\nServing on {}", address);

    trigger_on_change(&mut book, move |event, book| {
        if let Some(path) = event.path {
            println!("File changed: {:?}\nBuilding book...\n", path);
            match book.build() {
                Err(e) => println!("Error while building: {:?}", e),
                _ => broadcaster.send(RELOAD_COMMAND).unwrap(),
            }
            println!("");
        }
    });

    Ok(())
}

fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    try!(book.test());

    Ok(())
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}

// Calls the closure when a book source file is changed. This is blocking!
#[cfg(feature = "watch")]
fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
    where F: Fn(notify::Event, &mut MDBook) -> ()
{
    // Create a channel to receive the events.
    let (tx, rx) = channel();

    let w: Result<notify::RecommendedWatcher, notify::Error> = notify::Watcher::new(tx);

    match w {
        Ok(mut watcher) => {
            // Add the source directory to the watcher
            if let Err(e) = watcher.watch(book.get_src()) {
                println!("Error while watching {:?}:\n    {:?}", book.get_src(), e);
                ::std::process::exit(0);
            };

            // Add the book.json file to the watcher if it exists, because it's not
            // located in the source directory
            if let Err(_) = watcher.watch(book.get_root().join("book.json")) {
                // do nothing if book.json is not found
            }

            let mut previous_time = time::get_time();

            println!("\nListening for changes...\n");

            loop {
                match rx.recv() {
                    Ok(event) => {
                        // Skip the event if an event has already been issued in the last second
                        let time = time::get_time();
                        if time - previous_time < time::Duration::seconds(1) {
                            continue;
                        } else {
                            previous_time = time;
                        }

                        closure(event, book);
                    },
                    Err(e) => {
                        println!("An error occured: {:?}", e);
                    },
                }
            }
        },
        Err(e) => {
            println!("Error while trying to watch the files:\n\n\t{:?}", e);
            ::std::process::exit(0);
        },
    }
}
<|endoftext|>


<commit_before>extern crate git2;

use git2::*;
use std::path::Path;
use scratch::Scratch;
use super::Hooks;
use super::RepoHost;
use super::ReviewUploadResult;

pub struct CentralGit
{
    branch: String,
}

impl CentralGit
{
    pub fn new(branch: &str) -> Self
    {
        CentralGit { branch: branch.to_string() }
    }
}

pub fn module_ref(module: &str, branch: &str) -> String
{
    format!("refs/{}/{}/refs/heads/{}",
            "centralgit_0ee845b3_9c3f_41ee_9149_9e98a65ecf35",
            module,
            branch)
}

impl Hooks for CentralGit
{
    fn branch(&self) -> &str
    {
        return &self.branch;
    }

    fn review_upload(&self,
                     scratch: &Scratch,
                     host: &RepoHost,
                     newrev: Object,
                     module: &str)
        -> ReviewUploadResult
    {
        debug!(".\n\n==== Doing review upload for module {}", &module);

        let new = newrev.id();

        let (walk, initial) = if let Some(old) = scratch.tracking(host, &module, &self.branch()) {

            let old = old.id();

            if old == new {
                return ReviewUploadResult::NoChanges;
            }

            match scratch.repo.graph_descendant_of(new, old) {
                Err(_) | Ok(false) => {
                    debug!("graph_descendant_of({},{})", new, old);
                    return ReviewUploadResult::RejectNoFF;
                }
                Ok(true) => (),
            }

            debug!("==== walking commits from {} to {}", old, new);

            let mut walk = scratch.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            let range = format!("{}..{}", old, new);
            walk.push_range(&range).expect(&format!("walk: invalid range: {}", range));;
            walk.hide(old).expect("walk: can't hide");
            (walk, false)
        }
        else {
            let mut walk = scratch.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            walk.push(new).expect("walk: can't push");
            (walk, true)
        };

        let mut current =
            scratch.tracking(host, host.central(), &self.branch).expect("no central tracking").id();

        for rev in walk {
            let rev = rev.expect("walk: invalid rev");

            debug!("==== walking commit {}", rev);

            let module_commit = scratch.repo
                .find_commit(rev)
                .expect("walk: object is not actually a commit");

            if module_commit.parents().count() > 1 {
                // TODO: also do this check on pushes to cenral refs/for/branch
                // TODO: invectigate the possibility of allowing merge commits
                return ReviewUploadResult::RejectMerge;
            }

            if module != host.central() {
                debug!("==== Rewriting commit {}", rev);

                let tree = module_commit.tree().expect("walk: commit has no tree");
                let parent =
                    scratch.repo.find_commit(current).expect("walk: current object is no commit");

                let new_tree = scratch.replace_subtree(Path::new(module),
                                                       tree.id(),
                                                       &parent.tree()
                                                           .expect("walk: parent has no tree"));

                current = scratch.rewrite(&module_commit, &vec![&parent], &new_tree);
            }
        }

        if module != host.central() {
            return ReviewUploadResult::Uploaded(current, initial);
        }
        else {
            return ReviewUploadResult::Central;
        }
    }

    fn pre_create_project(&self, scratch: &Scratch, rev: Oid, project: &str)
    {
        if let Ok(_) = scratch.repo.refname_to_id(&module_ref(project, &self.branch())) {
            debug!("=== module ref for {} already exists", project);
        }
        else {
            if let Some(commit) = scratch.split_subdir(&project, rev) {
                scratch.repo
                    .reference(&module_ref(project, &self.branch()),
                               commit,
                               true,
                               "subtree_split")
                    .expect("can't create reference");
            }
            else {
                debug!("=== subdir empty: {}", project);
            }
        }
    }

    fn project_created(&self, scratch: &Scratch, host: &RepoHost, _project: &str)
    {
        if let Some(rev) = scratch.tracking(host, host.central(), &self.branch()) {
            self.central_submit(scratch, host, rev);
        }
    }

    fn central_submit(&self, scratch: &Scratch, host: &RepoHost, newrev: Object)
    {
        debug!(" ---> central_submit (sha1 of commit: {})", &newrev.id());

        let central_commit = newrev.as_commit().expect("could not get commit from obj");
        let central_tree = central_commit.tree().expect("commit has no tree");

        for module in host.projects() {
            if module == host.central() {
                continue;
            }
            debug!("");
            debug!("==== fetching tracking branch for module: {}", &module);
            match scratch.tracking(host, &module, &self.branch()) {
                Some(_) => (),
                None => {
                    debug!("====    no tracking branch for module {} => project does not exist \
                            or is empty",
                           &module);
                    debug!("====    initializing with subdir history");

                    self.pre_create_project(scratch, newrev.id(), &module);
                }
            };
            self.pre_create_project(scratch, newrev.id(), &module);

            let module_commit_obj = if let Ok(rev) = scratch.repo
                .revparse_single(&module_ref(&module, &self.branch())) {
                debug!("=== OK module ref : {}", module);
                rev
            }
            else {
                debug!("=== NO module ref : {}", module);
                continue;
            };

            let parents = vec![module_commit_obj.as_commit()
                                   .expect("could not get commit from obj")];

            debug!("==== checking for changes in module: {:?}", module);

            // new tree is sub-tree of complete central tree
            let old_tree_id = if let Ok(tree) = parents[0].tree() {
                tree.id()
            }
            else {
                Oid::from_str("0000000000000000000000000000000000000000").unwrap()
            };

            let new_tree_id = if let Ok(tree_entry) = central_tree.get_path(&Path::new(&module)) {
                tree_entry.id()
            }
            else {
                Oid::from_str("0000000000000000000000000000000000000000").unwrap()
            };

            // if sha1's are equal the content is equal
            if new_tree_id != old_tree_id && !new_tree_id.is_zero() {
                let new_tree =
                    scratch.repo.find_tree(new_tree_id).expect("central_submit: can't find tree");
                debug!("====    commit changes module => make commit on module");
                let module_commit = scratch.rewrite(central_commit, &parents, &new_tree);
                scratch.repo
                    .reference(&module_ref(&module, &self.branch()),
                               module_commit,
                               true,
                               "rewrite")
                    .expect("can't create reference");
            }
            else {
                debug!("====    commit does not change module => skipping");
            }
        }

        for module in host.projects() {
            if let Ok(module_commit) = scratch.repo
                .refname_to_id(&module_ref(&module, &self.branch())) {
                let output = scratch.push(host,
                                          module_commit,
                                          &module,
                                          &format!("refs/heads/{}", self.branch()));
                debug!("{}", output);
            }
        }
    }
}
<commit_msg>make it faster<commit_after>extern crate git2;

use git2::*;
use std::path::Path;
use scratch::Scratch;
use super::Hooks;
use super::RepoHost;
use super::ReviewUploadResult;

pub struct CentralGit
{
    branch: String,
}

impl CentralGit
{
    pub fn new(branch: &str) -> Self
    {
        CentralGit { branch: branch.to_string() }
    }
}

pub fn module_ref(module: &str, branch: &str) -> String
{
    format!("refs/{}/{}/refs/heads/{}",
            "centralgit_0ee845b3_9c3f_41ee_9149_9e98a65ecf35",
            module,
            branch)
}

impl Hooks for CentralGit
{
    fn branch(&self) -> &str
    {
        return &self.branch;
    }

    fn review_upload(&self,
                     scratch: &Scratch,
                     host: &RepoHost,
                     newrev: Object,
                     module: &str)
        -> ReviewUploadResult
    {
        debug!(".\n\n==== Doing review upload for module {}", &module);

        let new = newrev.id();

        let (walk, initial) = if let Some(old) = scratch.tracking(host, &module, &self.branch()) {

            let old = old.id();

            if old == new {
                return ReviewUploadResult::NoChanges;
            }

            match scratch.repo.graph_descendant_of(new, old) {
                Err(_) | Ok(false) => {
                    debug!("graph_descendant_of({},{})", new, old);
                    return ReviewUploadResult::RejectNoFF;
                }
                Ok(true) => (),
            }

            debug!("==== walking commits from {} to {}", old, new);

            let mut walk = scratch.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            let range = format!("{}..{}", old, new);
            walk.push_range(&range).expect(&format!("walk: invalid range: {}", range));;
            walk.hide(old).expect("walk: can't hide");
            (walk, false)
        }
        else {
            let mut walk = scratch.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            walk.push(new).expect("walk: can't push");
            (walk, true)
        };

        let mut current =
            scratch.tracking(host, host.central(), &self.branch).expect("no central tracking").id();

        for rev in walk {
            let rev = rev.expect("walk: invalid rev");

            debug!("==== walking commit {}", rev);

            let module_commit = scratch.repo
                .find_commit(rev)
                .expect("walk: object is not actually a commit");

            if module_commit.parents().count() > 1 {
                // TODO: also do this check on pushes to cenral refs/for/branch
                // TODO: invectigate the possibility of allowing merge commits
                return ReviewUploadResult::RejectMerge;
            }

            if module != host.central() {
                debug!("==== Rewriting commit {}", rev);

                let tree = module_commit.tree().expect("walk: commit has no tree");
                let parent =
                    scratch.repo.find_commit(current).expect("walk: current object is no commit");

                let new_tree = scratch.replace_subtree(Path::new(module),
                                                       tree.id(),
                                                       &parent.tree()
                                                           .expect("walk: parent has no tree"));

                current = scratch.rewrite(&module_commit, &vec![&parent], &new_tree);
            }
        }

        if module != host.central() {
            return ReviewUploadResult::Uploaded(current, initial);
        }
        else {
            return ReviewUploadResult::Central;
        }
    }

    fn pre_create_project(&self, scratch: &Scratch, rev: Oid, project: &str)
    {
        if let Ok(_) = scratch.repo.refname_to_id(&module_ref(project, &self.branch())) {
            debug!("=== module ref for {} already exists", project);
        }
        else {
            if let Some(commit) = scratch.split_subdir(&project, rev) {
                scratch.repo
                    .reference(&module_ref(project, &self.branch()),
                               commit,
                               true,
                               "subtree_split")
                    .expect("can't create reference");
            }
            else {
                debug!("=== subdir empty: {}", project);
            }
        }
    }

    fn project_created(&self, scratch: &Scratch, host: &RepoHost, _project: &str)
    {
        if let Some(rev) = scratch.tracking(host, host.central(), &self.branch()) {
            self.central_submit(scratch, host, rev);
        }
    }

    fn central_submit(&self, scratch: &Scratch, host: &RepoHost, newrev: Object)
    {
        debug!(" ---> central_submit (sha1 of commit: {})", &newrev.id());

        let central_commit = newrev.as_commit().expect("could not get commit from obj");
        let central_tree = central_commit.tree().expect("commit has no tree");

        let mut changed = vec![];

        for module in host.projects() {
            if module == host.central() {
                continue;
            }
            debug!("");
            debug!("==== fetching tracking branch for module: {}", &module);
            match scratch.tracking(host, &module, &self.branch()) {
                Some(_) => (),
                None => {
                    debug!("====    no tracking branch for module {} => project does not exist \
                            or is empty",
                           &module);
                    debug!("====    initializing with subdir history");

                    self.pre_create_project(scratch, newrev.id(), &module);
                    changed.push(module.to_string());
                }
            };
            self.pre_create_project(scratch, newrev.id(), &module);

            let module_commit_obj = if let Ok(rev) = scratch.repo
                .revparse_single(&module_ref(&module, &self.branch())) {
                debug!("=== OK module ref : {}", module);
                rev
            }
            else {
                debug!("=== NO module ref : {}", module);
                continue;
            };

            let parents = vec![module_commit_obj.as_commit()
                                   .expect("could not get commit from obj")];

            debug!("==== checking for changes in module: {:?}", module);

            // new tree is sub-tree of complete central tree
            let old_tree_id = if let Ok(tree) = parents[0].tree() {
                tree.id()
            }
            else {
                Oid::from_str("0000000000000000000000000000000000000000").unwrap()
            };

            let new_tree_id = if let Ok(tree_entry) = central_tree.get_path(&Path::new(&module)) {
                tree_entry.id()
            }
            else {
                Oid::from_str("0000000000000000000000000000000000000000").unwrap()
            };

            // if sha1's are equal the content is equal
            if new_tree_id != old_tree_id && !new_tree_id.is_zero() {
                changed.push(module.to_string());
                let new_tree =
                    scratch.repo.find_tree(new_tree_id).expect("central_submit: can't find tree");
                debug!("====    commit changes module => make commit on module");
                let module_commit = scratch.rewrite(central_commit, &parents, &new_tree);
                scratch.repo
                    .reference(&module_ref(&module, &self.branch()),
                               module_commit,
                               true,
                               "rewrite")
                    .expect("can't create reference");
            }
            else {
                debug!("====    commit does not change module => skipping");
            }
        }

        for module in changed {
            if let Ok(module_commit) = scratch.repo
                .refname_to_id(&module_ref(&module, &self.branch())) {
                let output = scratch.push(host,
                                          module_commit,
                                          &module,
                                          &format!("refs/heads/{}", self.branch()));
                debug!("{}", output);
            }
        }
    }
}
<|endoftext|>