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

//! Implements storage primitives required by the chain

use std::sync::Arc;

use util::secp::pedersen::Commitment;

use types::*;
use core::core::hash::{Hash, Hashed};
use core::core::{Block, BlockHeader};
use core::consensus::TargetError;
use core::core::target::Difficulty;
use grin_store::{self, option_to_not_found, to_key, Error, u64_to_key};

const STORE_SUBPATH: &'static str = "chain";

const BLOCK_HEADER_PREFIX: u8 = 'h' as u8;
const BLOCK_PREFIX: u8 = 'b' as u8;
const HEAD_PREFIX: u8 = 'H' as u8;
const HEADER_HEAD_PREFIX: u8 = 'I' as u8;
const SYNC_HEAD_PREFIX: u8 = 's' as u8;
const HEADER_HEIGHT_PREFIX: u8 = '8' as u8;
const COMMIT_POS_PREFIX: u8 = 'c' as u8;
const BLOCK_MARKER_PREFIX: u8 = 'm' as u8;
const BLOCK_PMMR_FILE_METADATA_PREFIX: u8 = 'p' as u8;

/// An implementation of the ChainStore trait backed by a simple key-value
/// store.
pub struct ChainKVStore {
	db: grin_store::Store,
}

impl ChainKVStore {
	/// Create new chain store
	pub fn new(root_path: String) -> Result<ChainKVStore, Error> {
		let db = grin_store::Store::open(format!("{}/{}", root_path, STORE_SUBPATH).as_str())?;
		Ok(ChainKVStore { db: db })
	}
}

impl ChainStore for ChainKVStore {
	fn head(&self) -> Result<Tip, Error> {
		option_to_not_found(self.db.get_ser(&vec![HEAD_PREFIX]))
	}

	fn head_header(&self) -> Result<BlockHeader, Error> {
		self.get_block_header(&try!(self.head()).last_block_h)
	}

	fn save_head(&self, t: &Tip) -> Result<(), Error> {
		self.db
			.batch()
			.put_ser(&vec![HEAD_PREFIX], t)?
			.put_ser(&vec![HEADER_HEAD_PREFIX], t)?
			.write()
	}

	fn save_body_head(&self, t: &Tip) -> Result<(), Error> {
		self.db.put_ser(&vec![HEAD_PREFIX], t)
	}

	fn get_header_head(&self) -> Result<Tip, Error> {
		option_to_not_found(self.db.get_ser(&vec![HEADER_HEAD_PREFIX]))
	}

	fn save_header_head(&self, t: &Tip) -> Result<(), Error> {
		self.db.put_ser(&vec![HEADER_HEAD_PREFIX], t)
	}

	fn get_sync_head(&self) -> Result<Tip, Error> {
		option_to_not_found(self.db.get_ser(&vec![SYNC_HEAD_PREFIX]))
	}

	fn save_sync_head(&self, t: &Tip) -> Result<(), Error> {
		self.db.put_ser(&vec![SYNC_HEAD_PREFIX], t)
	}

	fn init_head(&self) -> Result<(), Error> {
		if self.get_header_head().is_err() {
			let tip = self.head()?;
			self.save_header_head(&tip)?;
		}
		let header_tip = self.get_header_head()?;
		self.save_sync_head(&header_tip)
	}

	// Reset both header_head and sync_head to the current head of the body chain
	fn reset_head(&self) -> Result<(), Error> {
		let tip = self.head()?;
		self.save_header_head(&tip)?;
		self.save_sync_head(&tip)
	}

	fn get_block(&self, h: &Hash) -> Result<Block, Error> {
		option_to_not_found(self.db.get_ser(&to_key(BLOCK_PREFIX, &mut h.to_vec())))
	}

	fn block_exists(&self, h: &Hash) -> Result<bool, Error> {
		self.db.exists(&to_key(BLOCK_PREFIX, &mut h.to_vec()))
	}

	fn get_block_header(&self, h: &Hash) -> Result<BlockHeader, Error> {
		option_to_not_found(
			self.db
				.get_ser(&to_key(BLOCK_HEADER_PREFIX, &mut h.to_vec())),
		)
	}

	/// Save the block and its header
	fn save_block(&self, b: &Block) -> Result<(), Error> {
		let batch = self.db
			.batch()
			.put_ser(&to_key(BLOCK_PREFIX, &mut b.hash().to_vec())[..], b)?
			.put_ser(
				&to_key(BLOCK_HEADER_PREFIX, &mut b.hash().to_vec())[..],
				&b.header,
			)?;
		batch.write()
	}

	/// Delete a full block. Does not delete any record associated with a block
	/// header.
	fn delete_block(&self, bh: &Hash) -> Result<(), Error> {
		self.db.delete(&to_key(BLOCK_PREFIX, &mut bh.to_vec())[..])
	}

	fn is_on_current_chain(&self, header: &BlockHeader) -> Result<(), Error> {
		let header_at_height = self.get_header_by_height(header.height)?;
		if header.hash() == header_at_height.hash() {
			Ok(())
		} else {
			Err(Error::NotFoundErr)
		}
	}

	fn save_block_header(&self, bh: &BlockHeader) -> Result<(), Error> {
		self.db.put_ser(
			&to_key(BLOCK_HEADER_PREFIX, &mut bh.hash().to_vec())[..],
			bh,
		)
	}

	fn get_header_by_height(&self, height: u64) -> Result<BlockHeader, Error> {
		option_to_not_found(self.db.get_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, height)))
			.and_then(|hash| self.get_block_header(&hash))
	}

	fn save_header_height(&self, bh: &BlockHeader) -> Result<(), Error> {
		self.db
			.put_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, bh.height), &bh.hash())
	}

	fn delete_header_by_height(&self, height: u64) -> Result<(), Error> {
		self.db.delete(&u64_to_key(HEADER_HEIGHT_PREFIX, height))
	}

	fn save_output_pos(&self, commit: &Commitment, pos: u64) -> Result<(), Error> {
		self.db.put_ser(
			&to_key(COMMIT_POS_PREFIX, &mut commit.as_ref().to_vec())[..],
			&pos,
		)
	}

	fn get_output_pos(&self, commit: &Commitment) -> Result<u64, Error> {
		option_to_not_found(
			self.db
				.get_ser(&to_key(COMMIT_POS_PREFIX, &mut commit.as_ref().to_vec())),
		)
	}

	fn delete_output_pos(&self, commit: &[u8]) -> Result<(), Error> {
		self.db
			.delete(&to_key(COMMIT_POS_PREFIX, &mut commit.to_vec()))
	}

	fn save_block_marker(&self, bh: &Hash, marker: &(u64, u64)) -> Result<(), Error> {
		self.db
			.put_ser(&to_key(BLOCK_MARKER_PREFIX, &mut bh.to_vec())[..], &marker)
	}

	fn get_block_marker(&self, bh: &Hash) -> Result<(u64, u64), Error> {
		option_to_not_found(
			self.db
				.get_ser(&to_key(BLOCK_MARKER_PREFIX, &mut bh.to_vec())),
		)
	}

	fn delete_block_marker(&self, bh: &Hash) -> Result<(), Error> {
		self.db
			.delete(&to_key(BLOCK_MARKER_PREFIX, &mut bh.to_vec()))
	}

	fn save_block_pmmr_file_metadata(
		&self,
		h: &Hash,
		md: &PMMRFileMetadataCollection,
	) -> Result<(), Error> {
		self.db.put_ser(
			&to_key(BLOCK_PMMR_FILE_METADATA_PREFIX, &mut h.to_vec())[..],
			&md,
		)
	}

	fn get_block_pmmr_file_metadata(&self, h: &Hash) -> Result<PMMRFileMetadataCollection, Error> {
		option_to_not_found(
			self.db
				.get_ser(&to_key(BLOCK_PMMR_FILE_METADATA_PREFIX, &mut h.to_vec())),
		)
	}

	fn delete_block_pmmr_file_metadata(&self, h: &Hash) -> Result<(), Error> {
		self.db
			.delete(&to_key(BLOCK_PMMR_FILE_METADATA_PREFIX, &mut h.to_vec())[..])
	}

	/// Maintain consistency of the "header_by_height" index by traversing back
	/// through the current chain and updating "header_by_height" until we reach
	/// a block_header that is consistent with its height (everything prior to
	/// this will be consistent).
	/// We need to handle the case where we have no index entry for a given
	/// height to account for the case where we just switched to a new fork and
	/// the height jumped beyond current chain height.
	fn setup_height(&self, header: &BlockHeader, old_tip: &Tip) -> Result<(), Error> {
		// remove headers ahead if we backtracked
		for n in header.height..old_tip.height {
			self.delete_header_by_height(n)?;
		}
		self.build_by_height_index(header, false)
	}

	fn build_by_height_index(&self, header: &BlockHeader, force: bool) -> Result<(), Error> {
		self.save_header_height(&header)?;

		if header.height > 0 {
			let mut prev_header = self.get_block_header(&header.previous)?;
			while prev_header.height > 0 {
				if !force {
					if let Ok(_) = self.is_on_current_chain(&prev_header) {
						break;
					}
				}
				self.save_header_height(&prev_header)?;

				prev_header = self.get_block_header(&prev_header.previous)?;
			}
		}
		Ok(())
	}
}

/// An iterator on blocks, from latest to earliest, specialized to return
/// information pertaining to block difficulty calculation (timestamp and
/// previous difficulties). Mostly used by the consensus next difficulty
/// calculation.
pub struct DifficultyIter {
	start: Hash,
	store: Arc<ChainStore>,

	// maintain state for both the "next" header in this iteration
	// and its previous header in the chain ("next next" in the iteration)
	// so we effectively read-ahead as we iterate through the chain back
	// toward the genesis block (while maintaining current state)
	header: Option<BlockHeader>,
	prev_header: Option<BlockHeader>,
}

impl DifficultyIter {
	/// Build a new iterator using the provided chain store and starting from
	/// the provided block hash.
	pub fn from(start: Hash, store: Arc<ChainStore>) -> DifficultyIter {
		DifficultyIter {
			start: start,
			store: store,
			header: None,
			prev_header: None,
		}
	}
}

impl Iterator for DifficultyIter {
	type Item = Result<(u64, Difficulty), TargetError>;

	fn next(&mut self) -> Option<Self::Item> {
		// Get both header and previous_header if this is the initial iteration.
		// Otherwise move prev_header to header and get the next prev_header.
		self.header = if self.header.is_none() {
			self.store.get_block_header(&self.start).ok()
		} else {
			self.prev_header.clone()
		};

		// If we have a header we can do this iteration.
		// Otherwise we are done.
		if let Some(header) = self.header.clone() {
			self.prev_header = self.store.get_block_header(&header.previous).ok();

			let prev_difficulty = self.prev_header
				.clone()
				.map_or(Difficulty::zero(), |x| x.total_difficulty);
			let difficulty = header.total_difficulty - prev_difficulty;

			Some(Ok((header.timestamp.to_timespec().sec as u64, difficulty)))
		} else {
			return None;
		}
	}
}
<commit_msg>fix off by one in setup_height (#988)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Implements storage primitives required by the chain

use std::sync::Arc;

use util::secp::pedersen::Commitment;

use types::*;
use core::core::hash::{Hash, Hashed};
use core::core::{Block, BlockHeader};
use core::consensus::TargetError;
use core::core::target::Difficulty;
use grin_store::{self, option_to_not_found, to_key, Error, u64_to_key};

const STORE_SUBPATH: &'static str = "chain";

const BLOCK_HEADER_PREFIX: u8 = 'h' as u8;
const BLOCK_PREFIX: u8 = 'b' as u8;
const HEAD_PREFIX: u8 = 'H' as u8;
const HEADER_HEAD_PREFIX: u8 = 'I' as u8;
const SYNC_HEAD_PREFIX: u8 = 's' as u8;
const HEADER_HEIGHT_PREFIX: u8 = '8' as u8;
const COMMIT_POS_PREFIX: u8 = 'c' as u8;
const BLOCK_MARKER_PREFIX: u8 = 'm' as u8;
const BLOCK_PMMR_FILE_METADATA_PREFIX: u8 = 'p' as u8;

/// An implementation of the ChainStore trait backed by a simple key-value
/// store.
pub struct ChainKVStore {
	db: grin_store::Store,
}

impl ChainKVStore {
	/// Create new chain store
	pub fn new(root_path: String) -> Result<ChainKVStore, Error> {
		let db = grin_store::Store::open(format!("{}/{}", root_path, STORE_SUBPATH).as_str())?;
		Ok(ChainKVStore { db: db })
	}
}

impl ChainStore for ChainKVStore {
	fn head(&self) -> Result<Tip, Error> {
		option_to_not_found(self.db.get_ser(&vec![HEAD_PREFIX]))
	}

	fn head_header(&self) -> Result<BlockHeader, Error> {
		self.get_block_header(&try!(self.head()).last_block_h)
	}

	fn save_head(&self, t: &Tip) -> Result<(), Error> {
		self.db
			.batch()
			.put_ser(&vec![HEAD_PREFIX], t)?
			.put_ser(&vec![HEADER_HEAD_PREFIX], t)?
			.write()
	}

	fn save_body_head(&self, t: &Tip) -> Result<(), Error> {
		self.db.put_ser(&vec![HEAD_PREFIX], t)
	}

	fn get_header_head(&self) -> Result<Tip, Error> {
		option_to_not_found(self.db.get_ser(&vec![HEADER_HEAD_PREFIX]))
	}

	fn save_header_head(&self, t: &Tip) -> Result<(), Error> {
		self.db.put_ser(&vec![HEADER_HEAD_PREFIX], t)
	}

	fn get_sync_head(&self) -> Result<Tip, Error> {
		option_to_not_found(self.db.get_ser(&vec![SYNC_HEAD_PREFIX]))
	}

	fn save_sync_head(&self, t: &Tip) -> Result<(), Error> {
		self.db.put_ser(&vec![SYNC_HEAD_PREFIX], t)
	}

	fn init_head(&self) -> Result<(), Error> {
		if self.get_header_head().is_err() {
			let tip = self.head()?;
			self.save_header_head(&tip)?;
		}
		let header_tip = self.get_header_head()?;
		self.save_sync_head(&header_tip)
	}

	// Reset both header_head and sync_head to the current head of the body chain
	fn reset_head(&self) -> Result<(), Error> {
		let tip = self.head()?;
		self.save_header_head(&tip)?;
		self.save_sync_head(&tip)
	}

	fn get_block(&self, h: &Hash) -> Result<Block, Error> {
		option_to_not_found(self.db.get_ser(&to_key(BLOCK_PREFIX, &mut h.to_vec())))
	}

	fn block_exists(&self, h: &Hash) -> Result<bool, Error> {
		self.db.exists(&to_key(BLOCK_PREFIX, &mut h.to_vec()))
	}

	fn get_block_header(&self, h: &Hash) -> Result<BlockHeader, Error> {
		option_to_not_found(
			self.db
				.get_ser(&to_key(BLOCK_HEADER_PREFIX, &mut h.to_vec())),
		)
	}

	/// Save the block and its header
	fn save_block(&self, b: &Block) -> Result<(), Error> {
		let batch = self.db
			.batch()
			.put_ser(&to_key(BLOCK_PREFIX, &mut b.hash().to_vec())[..], b)?
			.put_ser(
				&to_key(BLOCK_HEADER_PREFIX, &mut b.hash().to_vec())[..],
				&b.header,
			)?;
		batch.write()
	}

	/// Delete a full block. Does not delete any record associated with a block
	/// header.
	fn delete_block(&self, bh: &Hash) -> Result<(), Error> {
		self.db.delete(&to_key(BLOCK_PREFIX, &mut bh.to_vec())[..])
	}

	fn is_on_current_chain(&self, header: &BlockHeader) -> Result<(), Error> {
		let header_at_height = self.get_header_by_height(header.height)?;
		if header.hash() == header_at_height.hash() {
			Ok(())
		} else {
			Err(Error::NotFoundErr)
		}
	}

	fn save_block_header(&self, bh: &BlockHeader) -> Result<(), Error> {
		self.db.put_ser(
			&to_key(BLOCK_HEADER_PREFIX, &mut bh.hash().to_vec())[..],
			bh,
		)
	}

	fn get_header_by_height(&self, height: u64) -> Result<BlockHeader, Error> {
		option_to_not_found(self.db.get_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, height)))
			.and_then(|hash| self.get_block_header(&hash))
	}

	fn save_header_height(&self, bh: &BlockHeader) -> Result<(), Error> {
		self.db
			.put_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, bh.height), &bh.hash())
	}

	fn delete_header_by_height(&self, height: u64) -> Result<(), Error> {
		self.db.delete(&u64_to_key(HEADER_HEIGHT_PREFIX, height))
	}

	fn save_output_pos(&self, commit: &Commitment, pos: u64) -> Result<(), Error> {
		self.db.put_ser(
			&to_key(COMMIT_POS_PREFIX, &mut commit.as_ref().to_vec())[..],
			&pos,
		)
	}

	fn get_output_pos(&self, commit: &Commitment) -> Result<u64, Error> {
		option_to_not_found(
			self.db
				.get_ser(&to_key(COMMIT_POS_PREFIX, &mut commit.as_ref().to_vec())),
		)
	}

	fn delete_output_pos(&self, commit: &[u8]) -> Result<(), Error> {
		self.db
			.delete(&to_key(COMMIT_POS_PREFIX, &mut commit.to_vec()))
	}

	fn save_block_marker(&self, bh: &Hash, marker: &(u64, u64)) -> Result<(), Error> {
		self.db
			.put_ser(&to_key(BLOCK_MARKER_PREFIX, &mut bh.to_vec())[..], &marker)
	}

	fn get_block_marker(&self, bh: &Hash) -> Result<(u64, u64), Error> {
		option_to_not_found(
			self.db
				.get_ser(&to_key(BLOCK_MARKER_PREFIX, &mut bh.to_vec())),
		)
	}

	fn delete_block_marker(&self, bh: &Hash) -> Result<(), Error> {
		self.db
			.delete(&to_key(BLOCK_MARKER_PREFIX, &mut bh.to_vec()))
	}

	fn save_block_pmmr_file_metadata(
		&self,
		h: &Hash,
		md: &PMMRFileMetadataCollection,
	) -> Result<(), Error> {
		self.db.put_ser(
			&to_key(BLOCK_PMMR_FILE_METADATA_PREFIX, &mut h.to_vec())[..],
			&md,
		)
	}

	fn get_block_pmmr_file_metadata(&self, h: &Hash) -> Result<PMMRFileMetadataCollection, Error> {
		option_to_not_found(
			self.db
				.get_ser(&to_key(BLOCK_PMMR_FILE_METADATA_PREFIX, &mut h.to_vec())),
		)
	}

	fn delete_block_pmmr_file_metadata(&self, h: &Hash) -> Result<(), Error> {
		self.db
			.delete(&to_key(BLOCK_PMMR_FILE_METADATA_PREFIX, &mut h.to_vec())[..])
	}

	/// Maintain consistency of the "header_by_height" index by traversing back
	/// through the current chain and updating "header_by_height" until we reach
	/// a block_header that is consistent with its height (everything prior to
	/// this will be consistent).
	/// We need to handle the case where we have no index entry for a given
	/// height to account for the case where we just switched to a new fork and
	/// the height jumped beyond current chain height.
	fn setup_height(&self, header: &BlockHeader, old_tip: &Tip) -> Result<(), Error> {
		// remove headers ahead if we backtracked
		for n in header.height..old_tip.height {
			self.delete_header_by_height(n + 1)?;
		}
		self.build_by_height_index(header, false)
	}

	fn build_by_height_index(&self, header: &BlockHeader, force: bool) -> Result<(), Error> {
		self.save_header_height(&header)?;

		if header.height > 0 {
			let mut prev_header = self.get_block_header(&header.previous)?;
			while prev_header.height > 0 {
				if !force {
					if let Ok(_) = self.is_on_current_chain(&prev_header) {
						break;
					}
				}
				self.save_header_height(&prev_header)?;

				prev_header = self.get_block_header(&prev_header.previous)?;
			}
		}
		Ok(())
	}
}

/// An iterator on blocks, from latest to earliest, specialized to return
/// information pertaining to block difficulty calculation (timestamp and
/// previous difficulties). Mostly used by the consensus next difficulty
/// calculation.
pub struct DifficultyIter {
	start: Hash,
	store: Arc<ChainStore>,

	// maintain state for both the "next" header in this iteration
	// and its previous header in the chain ("next next" in the iteration)
	// so we effectively read-ahead as we iterate through the chain back
	// toward the genesis block (while maintaining current state)
	header: Option<BlockHeader>,
	prev_header: Option<BlockHeader>,
}

impl DifficultyIter {
	/// Build a new iterator using the provided chain store and starting from
	/// the provided block hash.
	pub fn from(start: Hash, store: Arc<ChainStore>) -> DifficultyIter {
		DifficultyIter {
			start: start,
			store: store,
			header: None,
			prev_header: None,
		}
	}
}

impl Iterator for DifficultyIter {
	type Item = Result<(u64, Difficulty), TargetError>;

	fn next(&mut self) -> Option<Self::Item> {
		// Get both header and previous_header if this is the initial iteration.
		// Otherwise move prev_header to header and get the next prev_header.
		self.header = if self.header.is_none() {
			self.store.get_block_header(&self.start).ok()
		} else {
			self.prev_header.clone()
		};

		// If we have a header we can do this iteration.
		// Otherwise we are done.
		if let Some(header) = self.header.clone() {
			self.prev_header = self.store.get_block_header(&header.previous).ok();

			let prev_difficulty = self.prev_header
				.clone()
				.map_or(Difficulty::zero(), |x| x.total_difficulty);
			let difficulty = header.total_difficulty - prev_difficulty;

			Some(Ok((header.timestamp.to_timespec().sec as u64, difficulty)))
		} else {
			return None;
		}
	}
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]

extern crate bytes;
#[cfg(target_os = "hermit")]
extern crate hermit_sys;
extern crate rust_tcp_io_perf;

use rust_tcp_io_perf::config;
use rust_tcp_io_perf::connection;
use rust_tcp_io_perf::print_utils;
use std::io::Read;
use std::time::Instant;

fn main() {
	let args = config::parse_config();
	let n_bytes = args.n_bytes;
	let tot_n_bytes = (n_bytes * args.n_rounds) as u64;

	let mut buf = vec![0; n_bytes];
	let mut tot_bytes: u64 = 0;

	let mut stream = connection::server_listen_and_get_first_connection(&args.port);
	connection::setup(&args, &mut stream);

	let start = Instant::now();
	while tot_bytes <= tot_n_bytes {
		let recv = stream.read(&mut buf).unwrap();
		if recv > 0 {
			tot_bytes += recv as u64;
		} else {
			break;
		}
	}
	let end = Instant::now();
	let duration = end.duration_since(start);

	println!("Sent in total {} KBytes", tot_bytes / 1024);
	println!(
		"Available approximated bandwidth: {} Mbit/s",
		(tot_bytes as f64 * 8.0f64) / (1024.0f64 * 1024.0f64 * duration.as_secs_f64())
	);
}
<commit_msg>simplify server, increase the readability<commit_after>#![allow(unused_imports)]

extern crate bytes;
#[cfg(target_os = "hermit")]
extern crate hermit_sys;
extern crate rust_tcp_io_perf;

use rust_tcp_io_perf::config;
use rust_tcp_io_perf::connection;
use rust_tcp_io_perf::print_utils;
use std::io::Read;
use std::time::Instant;

fn main() {
	let args = config::parse_config();
	let n_bytes = args.n_bytes;
	let tot_n_bytes = n_bytes * args.n_rounds;

	let mut buf = vec![0; tot_n_bytes];

	let mut stream = connection::server_listen_and_get_first_connection(&args.port);
	connection::setup(&args, &mut stream);

	let start = Instant::now();
	let tot_bytes = stream.read_to_end(&mut buf).unwrap();
	let end = Instant::now();
	let duration = end.duration_since(start);

	println!("Sent in total {} KBytes", tot_bytes / 1024);
	println!(
		"Available approximated bandwidth: {} Mbit/s",
		(tot_bytes as f64 * 8.0f64) / (1024.0f64 * 1024.0f64 * duration.as_secs_f64())
	);
}
<|endoftext|>


<commit_before>//! The nodes.

use std::collections::HashMap;
use std::fmt;

mod text;
mod value;

pub use self::text::Text;
pub use self::value::Value;

/// Attributes.
pub type Attributes = HashMap<String, Value>;

/// Child nodes.
pub type Children = Vec<Box<Node>>;

/// A node.
pub trait Node: 'static + fmt::Debug + fmt::Display + NodeClone {
    /// Append a child node.
    fn append<T>(&mut self, T)
    where
        Self: Sized,
        T: Node;

    /// Assign an attribute.
    fn assign<T, U>(&mut self, T, U)
    where
        Self: Sized,
        T: Into<String>,
        U: Into<Value>;
}

#[doc(hidden)]
pub trait NodeClone {
    fn clone(&self) -> Box<Node>;
}

impl<T> NodeClone for T where T: Node + Clone {
    #[inline]
    fn clone(&self) -> Box<Node> {
        Box::new(Clone::clone(self))
    }
}

impl Clone for Box<Node>  {
    #[inline]
    fn clone(&self) -> Self {
        NodeClone::clone(&**self)
    }
}

macro_rules! node(
    ($struct_name:ident::$field_name:ident) => (
        impl $struct_name {
            /// Append a node.
            pub fn add<T>(mut self, node: T) -> Self
            where
                T: ::node::Node,
            {
                ::node::Node::append(&mut self, node);
                self
            }

            /// Assign an attribute.
            #[inline]
            pub fn set<T, U>(mut self, name: T, value: U) -> Self
            where
                T: Into<String>,
                U: Into<::node::Value>,
            {
                ::node::Node::assign(&mut self, name, value);
                self
            }
        }

        impl ::node::Node for $struct_name {
            #[inline]
            fn append<T>(&mut self, node: T) where T: ::node::Node {
                self.$field_name.append(node);
            }

            #[inline]
            fn assign<T, U>(&mut self, name: T, value: U)
            where
                T: Into<String>,
                U: Into<::node::Value>,
            {
                self.$field_name.assign(name, value);
            }
        }

        impl ::std::fmt::Display for $struct_name {
            #[inline]
            fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                self.$field_name.fmt(formatter)
            }
        }
    );
);

pub mod element;
<commit_msg>Run rustfmt-nightly<commit_after>//! The nodes.

use std::collections::HashMap;
use std::fmt;

mod text;
mod value;

pub use self::text::Text;
pub use self::value::Value;

/// Attributes.
pub type Attributes = HashMap<String, Value>;

/// Child nodes.
pub type Children = Vec<Box<Node>>;

/// A node.
pub trait Node: 'static + fmt::Debug + fmt::Display + NodeClone {
    /// Append a child node.
    fn append<T>(&mut self, T)
    where
        Self: Sized,
        T: Node;

    /// Assign an attribute.
    fn assign<T, U>(&mut self, T, U)
    where
        Self: Sized,
        T: Into<String>,
        U: Into<Value>;
}

#[doc(hidden)]
pub trait NodeClone {
    fn clone(&self) -> Box<Node>;
}

impl<T> NodeClone for T
where
    T: Node + Clone,
{
    #[inline]
    fn clone(&self) -> Box<Node> {
        Box::new(Clone::clone(self))
    }
}

impl Clone for Box<Node> {
    #[inline]
    fn clone(&self) -> Self {
        NodeClone::clone(&**self)
    }
}

macro_rules! node(
    ($struct_name:ident::$field_name:ident) => (
        impl $struct_name {
            /// Append a node.
            pub fn add<T>(mut self, node: T) -> Self
            where
                T: ::node::Node,
            {
                ::node::Node::append(&mut self, node);
                self
            }

            /// Assign an attribute.
            #[inline]
            pub fn set<T, U>(mut self, name: T, value: U) -> Self
            where
                T: Into<String>,
                U: Into<::node::Value>,
            {
                ::node::Node::assign(&mut self, name, value);
                self
            }
        }

        impl ::node::Node for $struct_name {
            #[inline]
            fn append<T>(&mut self, node: T) where T: ::node::Node {
                self.$field_name.append(node);
            }

            #[inline]
            fn assign<T, U>(&mut self, name: T, value: U)
            where
                T: Into<String>,
                U: Into<::node::Value>,
            {
                self.$field_name.assign(name, value);
            }
        }

        impl ::std::fmt::Display for $struct_name {
            #[inline]
            fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                self.$field_name.fmt(formatter)
            }
        }
    );
);

pub mod element;
<|endoftext|>


<commit_before>use prelude::*;

pub fn get_inode(fs: &mut Filesystem, ino: u64) -> Result<Inode> {
  if let Some(inode) = fs.inode_cache.get(&ino) {
    fs.reused_inos.insert(ino);
    return Ok(inode.clone())
  }

  let inode = try!(read_inode(fs, ino));
  fs.inode_cache.insert(ino, inode.clone());
  fs.cache_queue.push_back(ino);
  try!(refit_inode_cache(fs));
  Ok(inode)
}

pub fn update_inode(fs: &mut Filesystem, inode: &Inode) -> Result<()> {
  use std::collections::hash_map::Entry;

  fs.dirty_inos.insert(inode.ino);
  match fs.inode_cache.entry(inode.ino) {
    Entry::Occupied(mut occupied) => {
      occupied.insert(inode.clone());
      fs.reused_inos.insert(inode.ino);
      return Ok(())
    },
    Entry::Vacant(vacant) => {
      vacant.insert(inode.clone());
      fs.cache_queue.push_back(inode.ino);
    },
  }

  refit_inode_cache(fs)
}

fn refit_inode_cache(fs: &mut Filesystem) -> Result<()> {
  while fs.inode_cache.len() > 10 {
    let mut flushed = false;

    while let Some(used_ino) = fs.cache_queue.pop_front() {
      if fs.reused_inos.remove(&used_ino) {
        try!(flush_ino(fs, used_ino));
        flushed = true;
        break;
      }
    }

    if !flushed {
      let random_ino = *fs.inode_cache.iter().next().unwrap().0;
      try!(flush_ino(fs, random_ino));
    }
  }
  Ok(())
}

pub fn flush_ino(fs: &mut Filesystem, ino: u64) -> Result<()> {
  if let Some(inode) = fs.inode_cache.remove(&ino) {
    fs.reused_inos.remove(&ino);
    if fs.dirty_inos.remove(&ino) {
      return write_inode(fs, &inode);
    }
  }
  Ok(())
}

pub fn set_inode_mode_attr(fs: &mut Filesystem, ino: u64,
  mode: Mode, attr: FileAttr) -> Result<()>
{
  let mut inode = try!(get_inode(fs, ino));
  inode.mode = mode;
  inode.attr = attr;
  update_inode(fs, &mut inode)
}

pub fn truncate_inode_size(fs: &mut Filesystem, ino: u64, new_size: u64) -> Result<()> {
  let mut inode = try!(get_inode(fs, ino));
  if inode.mode.file_type != FileType::Regular {
    return Err(Error::new(format!(
      "Cannot truncate inode {} of type {:?}", ino, inode.mode.file_type)));
  }

  if new_size == 0 {
    dealloc_inode_blocks(fs, &mut inode)
  } else if inode.size < new_size {
    return Err(Error::new(format!(
      "Cannot truncate inode {} with size {} to size {}", ino, inode.size, new_size)));
  } else {
    let first_unused_block = (new_size + fs.block_size() - 1) / fs.block_size();
    try!(truncate_inode_blocks(fs, &mut inode, first_unused_block));
    inode.size = new_size;
    update_inode(fs, &mut inode)
  }
}

pub fn inode_mode_from_linux_mode(mode: u16) -> Result<Mode> {
  decode_inode_mode(mode)
}

pub fn unlink_inode(fs: &mut Filesystem, inode: &mut Inode) -> Result<()> {
  if inode.mode.file_type == FileType::Dir {
    if !try!(is_dir_empty(fs, inode)) {
      return Err(Error::new(
          format!("Cannot unlink non-empty directory inode {}", inode.ino)));
    }

    if inode.links_count != 2 {
      return Err(Error::new(format!(
            "Empty directory {} should have 2 links, but has {}",
            inode.ino, inode.links_count)));
    }
    try!(deinit_dir(fs, inode));
  }

  inode.links_count -= 1;
  if inode.links_count == 0 {
    try!(remove_inode(fs, inode))
  }
  update_inode(fs, inode)
}

pub fn read_inode(fs: &mut Filesystem, ino: u64) -> Result<Inode> {
  let (offset, inode_size) = try!(locate_inode(fs, ino));
  let mut inode_buf = make_buffer(inode_size);
  try!(fs.volume.read(offset, &mut inode_buf[..]));
  decode_inode(&fs.superblock, ino, &inode_buf[..])
}

pub fn write_inode(fs: &mut Filesystem, inode: &Inode) -> Result<()> {
  let (offset, inode_size) = try!(locate_inode(fs, inode.ino));
  let mut inode_buf = make_buffer(inode_size);
  try!(fs.volume.read(offset, &mut inode_buf[..]));
  try!(encode_inode(&fs.superblock, inode, &mut inode_buf[..]));
  fs.volume.write(offset, &inode_buf[..])
}

fn locate_inode(fs: &mut Filesystem, ino: u64) -> Result<(u64, u64)> {
  let (group_idx, local_idx) = get_ino_group(fs, ino);
  let inode_size = fs.superblock.inode_size as u64;
  let inode_table = fs.groups[group_idx as usize].desc.inode_table as u64;
  let offset = inode_table * fs.block_size() + local_idx * inode_size;
  Ok((offset, inode_size))
}

pub fn init_inode(fs: &mut Filesystem, dir_inode: &mut Inode,
  ino: u64, mode: Mode, attr: FileAttr) -> Result<Inode>
{
  let mut inode = Inode {
    ino: ino,
    mode: mode,
    attr: attr,
    size: 0, size_512: 0,
    links_count: 0, flags: 0,
    block: [0; 15],
    file_acl: 0,
  };

  if mode.file_type == FileType::Dir {
    try!(init_dir(fs, dir_inode, &mut inode));
  }
  try!(update_inode(fs, &inode));
  Ok(inode)
}

fn remove_inode(fs: &mut Filesystem, inode: &mut Inode) -> Result<()> {
  try!(dealloc_inode_blocks(fs, inode));
  inode.attr.dtime = 1451303454;
  dealloc_inode(fs, inode.ino)
}
<commit_msg>Make the cache actually work<commit_after>use prelude::*;

pub fn get_inode(fs: &mut Filesystem, ino: u64) -> Result<Inode> {
  if let Some(inode) = fs.inode_cache.get(&ino) {
    fs.reused_inos.insert(ino);
    return Ok(inode.clone())
  }

  let inode = try!(read_inode(fs, ino));
  fs.inode_cache.insert(ino, inode.clone());
  fs.cache_queue.push_back(ino);
  try!(refit_inode_cache(fs));
  Ok(inode)
}

pub fn update_inode(fs: &mut Filesystem, inode: &Inode) -> Result<()> {
  use std::collections::hash_map::Entry;

  fs.dirty_inos.insert(inode.ino);
  match fs.inode_cache.entry(inode.ino) {
    Entry::Occupied(mut occupied) => {
      occupied.insert(inode.clone());
      fs.reused_inos.insert(inode.ino);
      return Ok(())
    },
    Entry::Vacant(vacant) => {
      vacant.insert(inode.clone());
      fs.cache_queue.push_back(inode.ino);
    },
  }

  refit_inode_cache(fs)
}

fn refit_inode_cache(fs: &mut Filesystem) -> Result<()> {
  while fs.inode_cache.len() > 10 {
    let mut flushed = false;

    while let Some(used_ino) = fs.cache_queue.pop_front() {
      if !fs.reused_inos.remove(&used_ino) {
        try!(flush_ino(fs, used_ino));
        flushed = true;
        break;
      } else {
        fs.cache_queue.push_back(used_ino);
      }
    }

    if !flushed {
      let random_ino = *fs.inode_cache.iter().next().unwrap().0;
      try!(flush_ino(fs, random_ino));
    }
  }
  Ok(())
}

pub fn flush_ino(fs: &mut Filesystem, ino: u64) -> Result<()> {
  if let Some(inode) = fs.inode_cache.remove(&ino) {
    fs.reused_inos.remove(&ino);
    if fs.dirty_inos.remove(&ino) {
      return write_inode(fs, &inode);
    }
  }
  Ok(())
}

pub fn set_inode_mode_attr(fs: &mut Filesystem, ino: u64,
  mode: Mode, attr: FileAttr) -> Result<()>
{
  let mut inode = try!(get_inode(fs, ino));
  inode.mode = mode;
  inode.attr = attr;
  update_inode(fs, &mut inode)
}

pub fn truncate_inode_size(fs: &mut Filesystem, ino: u64, new_size: u64) -> Result<()> {
  let mut inode = try!(get_inode(fs, ino));
  if inode.mode.file_type != FileType::Regular {
    return Err(Error::new(format!(
      "Cannot truncate inode {} of type {:?}", ino, inode.mode.file_type)));
  }

  if new_size == 0 {
    dealloc_inode_blocks(fs, &mut inode)
  } else if inode.size < new_size {
    return Err(Error::new(format!(
      "Cannot truncate inode {} with size {} to size {}", ino, inode.size, new_size)));
  } else {
    let first_unused_block = (new_size + fs.block_size() - 1) / fs.block_size();
    try!(truncate_inode_blocks(fs, &mut inode, first_unused_block));
    inode.size = new_size;
    update_inode(fs, &mut inode)
  }
}

pub fn inode_mode_from_linux_mode(mode: u16) -> Result<Mode> {
  decode_inode_mode(mode)
}

pub fn unlink_inode(fs: &mut Filesystem, inode: &mut Inode) -> Result<()> {
  if inode.mode.file_type == FileType::Dir {
    if !try!(is_dir_empty(fs, inode)) {
      return Err(Error::new(
          format!("Cannot unlink non-empty directory inode {}", inode.ino)));
    }

    if inode.links_count != 2 {
      return Err(Error::new(format!(
            "Empty directory {} should have 2 links, but has {}",
            inode.ino, inode.links_count)));
    }
    try!(deinit_dir(fs, inode));
  }

  inode.links_count -= 1;
  if inode.links_count == 0 {
    try!(remove_inode(fs, inode))
  }
  update_inode(fs, inode)
}

pub fn read_inode(fs: &mut Filesystem, ino: u64) -> Result<Inode> {
  let (offset, inode_size) = try!(locate_inode(fs, ino));
  let mut inode_buf = make_buffer(inode_size);
  try!(fs.volume.read(offset, &mut inode_buf[..]));
  decode_inode(&fs.superblock, ino, &inode_buf[..])
}

pub fn write_inode(fs: &mut Filesystem, inode: &Inode) -> Result<()> {
  let (offset, inode_size) = try!(locate_inode(fs, inode.ino));
  let mut inode_buf = make_buffer(inode_size);
  try!(fs.volume.read(offset, &mut inode_buf[..]));
  try!(encode_inode(&fs.superblock, inode, &mut inode_buf[..]));
  fs.volume.write(offset, &inode_buf[..])
}

fn locate_inode(fs: &mut Filesystem, ino: u64) -> Result<(u64, u64)> {
  let (group_idx, local_idx) = get_ino_group(fs, ino);
  let inode_size = fs.superblock.inode_size as u64;
  let inode_table = fs.groups[group_idx as usize].desc.inode_table as u64;
  let offset = inode_table * fs.block_size() + local_idx * inode_size;
  Ok((offset, inode_size))
}

pub fn init_inode(fs: &mut Filesystem, dir_inode: &mut Inode,
  ino: u64, mode: Mode, attr: FileAttr) -> Result<Inode>
{
  let mut inode = Inode {
    ino: ino,
    mode: mode,
    attr: attr,
    size: 0, size_512: 0,
    links_count: 0, flags: 0,
    block: [0; 15],
    file_acl: 0,
  };

  if mode.file_type == FileType::Dir {
    try!(init_dir(fs, dir_inode, &mut inode));
  }
  try!(update_inode(fs, &inode));
  Ok(inode)
}

fn remove_inode(fs: &mut Filesystem, inode: &mut Inode) -> Result<()> {
  try!(dealloc_inode_blocks(fs, inode));
  inode.attr.dtime = 1451303454;
  dealloc_inode(fs, inode.ino)
}
<|endoftext|>


<commit_before>use rustc::ty;
use rustc::ty::layout::Primitive;
use rustc::mir;

use super::*;

use helpers::EvalContextExt as HelperEvalContextExt;

pub trait EvalContextExt<'tcx> {
    fn ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: Scalar,
        left_ty: ty::Ty<'tcx>,
        right: Scalar,
        right_ty: ty::Ty<'tcx>,
    ) -> EvalResult<'tcx, Option<(Scalar, bool)>>;

    fn ptr_int_arithmetic(
        &self,
        bin_op: mir::BinOp,
        left: Pointer,
        right: i128,
        signed: bool,
    ) -> EvalResult<'tcx, (Scalar, bool)>;
}

impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
    fn ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: Scalar,
        left_ty: ty::Ty<'tcx>,
        right: Scalar,
        right_ty: ty::Ty<'tcx>,
    ) -> EvalResult<'tcx, Option<(Scalar, bool)>> {
        use rustc::mir::BinOp::*;
        use rustc::ty::layout::Integer::*;
        let usize = Primitive::Int(match self.memory.pointer_size().bytes() {
            1 => I8,
            2 => I16,
            4 => I32,
            8 => I64,
            16 => I128,
            _ => unreachable!(),
        }, false);
        let isize = Primitive::Int(match self.memory.pointer_size().bytes() {
            1 => I8,
            2 => I16,
            4 => I32,
            8 => I64,
            16 => I128,
            _ => unreachable!(),
        }, true);
        let left_kind = match self.layout_of(left_ty)?.abi {
            ty::layout::Abi::Scalar(ref scalar) => scalar.value,
            _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?,
        };
        let right_kind = match self.layout_of(right_ty)?.abi {
            ty::layout::Abi::Scalar(ref scalar) => scalar.value,
            _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?,
        };
        match bin_op {
            Offset if left_kind == Primitive::Pointer && right_kind == usize => {
                let pointee_ty = left_ty
                    .builtin_deref(true)
                    .expect("Offset called on non-ptr type")
                    .ty;
                let ptr = self.pointer_offset(
                    left.into(),
                    pointee_ty,
                    right.to_bits(self.memory.pointer_size())? as i64,
                )?;
                Ok(Some((ptr, false)))
            }
            // These work on anything
            Eq if left_kind == right_kind => {
                let result = match (left, right) {
                    (Scalar::Bits { .. }, Scalar::Bits { .. }) => {
                        left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())?
                    },
                    (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right,
                    _ => false,
                };
                Ok(Some((Scalar::from_bool(result), false)))
            }
            Ne if left_kind == right_kind => {
                let result = match (left, right) {
                    (Scalar::Bits { .. }, Scalar::Bits { .. }) => {
                        left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())?
                    },
                    (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right,
                    _ => true,
                };
                Ok(Some((Scalar::from_bool(result), false)))
            }
            // These need both pointers to be in the same allocation
            Lt | Le | Gt | Ge | Sub
                if left_kind == right_kind &&
                       (left_kind == Primitive::Pointer || left_kind == usize || left_kind == isize) &&
                       left.is_ptr() && right.is_ptr() => {
                let left = left.to_ptr()?;
                let right = right.to_ptr()?;
                if left.alloc_id == right.alloc_id {
                    let res = match bin_op {
                        Lt => left.offset < right.offset,
                        Le => left.offset <= right.offset,
                        Gt => left.offset > right.offset,
                        Ge => left.offset >= right.offset,
                        Sub => {
                            return self.binary_op(
                                Sub,
                                Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 },
                                self.tcx.types.usize,
                                Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 },
                                self.tcx.types.usize,
                            ).map(Some)
                        }
                        _ => bug!("We already established it has to be one of these operators."),
                    };
                    Ok(Some((Scalar::from_bool(res), false)))
                } else {
                    // Both are pointers, but from different allocations.
                    err!(InvalidPointerMath)
                }
            }
            // These work if one operand is a pointer, the other an integer
            Add | BitAnd | Sub
                if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
                       left.is_ptr() && right.is_bits() => {
                // Cast to i128 is fine as we checked the kind to be ptr-sized
                self.ptr_int_arithmetic(
                    bin_op,
                    left.to_ptr()?,
                    right.to_bits(self.memory.pointer_size())? as i128,
                    left_kind == isize,
                ).map(Some)
            }
            Add | BitAnd
                if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
                       left.is_bits() && right.is_ptr() => {
                // This is a commutative operation, just swap the operands
                self.ptr_int_arithmetic(
                    bin_op,
                    right.to_ptr()?,
                    left.to_bits(self.memory.pointer_size())? as i128,
                    left_kind == isize,
                ).map(Some)
            }
            _ => Ok(None),
        }
    }

    fn ptr_int_arithmetic(
        &self,
        bin_op: mir::BinOp,
        left: Pointer,
        right: i128,
        signed: bool,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        use rustc::mir::BinOp::*;

        fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) {
            (Scalar::Ptr(res), over)
        }

        Ok(match bin_op {
            Sub =>
                // The only way this can overflow is by underflowing, so signdeness of the right operands does not matter
                map_to_primval(left.overflowing_signed_offset(-right, self)),
            Add if signed =>
                map_to_primval(left.overflowing_signed_offset(right, self)),
            Add if !signed =>
                map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)),

            BitAnd if !signed => {
                let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1);
                let right = right as u64;
                if right & base_mask == base_mask {
                    // Case 1: The base address bits are all preserved, i.e., right is all-1 there
                    (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false)
                } else if right & base_mask == 0 {
                    // Case 2: The base address bits are all taken away, i.e., right is all-0 there
                    (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false)
                } else {
                    return err!(ReadPointerAsBytes);
                }
            }

            _ => {
                let msg = format!("unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", bin_op, left, right, if signed { "signed" } else { "unsigned" });
                return err!(Unimplemented(msg));
            }
        })
    }
}
<commit_msg>Comparing non-pointer-size types should be possible<commit_after>use rustc::ty;
use rustc::ty::layout::Primitive;
use rustc::mir;

use super::*;

use helpers::EvalContextExt as HelperEvalContextExt;

pub trait EvalContextExt<'tcx> {
    fn ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: Scalar,
        left_ty: ty::Ty<'tcx>,
        right: Scalar,
        right_ty: ty::Ty<'tcx>,
    ) -> EvalResult<'tcx, Option<(Scalar, bool)>>;

    fn ptr_int_arithmetic(
        &self,
        bin_op: mir::BinOp,
        left: Pointer,
        right: i128,
        signed: bool,
    ) -> EvalResult<'tcx, (Scalar, bool)>;
}

impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
    fn ptr_op(
        &self,
        bin_op: mir::BinOp,
        left: Scalar,
        left_ty: ty::Ty<'tcx>,
        right: Scalar,
        right_ty: ty::Ty<'tcx>,
    ) -> EvalResult<'tcx, Option<(Scalar, bool)>> {
        use rustc::mir::BinOp::*;
        use rustc::ty::layout::Integer::*;
        let usize = Primitive::Int(match self.memory.pointer_size().bytes() {
            1 => I8,
            2 => I16,
            4 => I32,
            8 => I64,
            16 => I128,
            _ => unreachable!(),
        }, false);
        let isize = Primitive::Int(match self.memory.pointer_size().bytes() {
            1 => I8,
            2 => I16,
            4 => I32,
            8 => I64,
            16 => I128,
            _ => unreachable!(),
        }, true);
        let left_layout = self.layout_of(left_ty)?;
        let left_kind = match left_layout.abi {
            ty::layout::Abi::Scalar(ref scalar) => scalar.value,
            _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?,
        };
        let right_layout = self.layout_of(right_ty)?;
        let right_kind = match right_layout.abi {
            ty::layout::Abi::Scalar(ref scalar) => scalar.value,
            _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?,
        };
        match bin_op {
            Offset if left_kind == Primitive::Pointer && right_kind == usize => {
                let pointee_ty = left_ty
                    .builtin_deref(true)
                    .expect("Offset called on non-ptr type")
                    .ty;
                let ptr = self.pointer_offset(
                    left.into(),
                    pointee_ty,
                    right.to_bits(self.memory.pointer_size())? as i64,
                )?;
                Ok(Some((ptr, false)))
            }
            // These work on anything
            Eq if left_kind == right_kind => {
                let result = match (left, right) {
                    (Scalar::Bits { .. }, Scalar::Bits { .. }) => {
                        left.to_bits(left_layout.size)? == right.to_bits(right_layout.size)?
                    },
                    (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right,
                    _ => false,
                };
                Ok(Some((Scalar::from_bool(result), false)))
            }
            Ne if left_kind == right_kind => {
                let result = match (left, right) {
                    (Scalar::Bits { .. }, Scalar::Bits { .. }) => {
                        left.to_bits(left_layout.size)? != right.to_bits(right_layout.size)?
                    },
                    (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right,
                    _ => true,
                };
                Ok(Some((Scalar::from_bool(result), false)))
            }
            // These need both pointers to be in the same allocation
            Lt | Le | Gt | Ge | Sub
                if left_kind == right_kind &&
                       (left_kind == Primitive::Pointer || left_kind == usize || left_kind == isize) &&
                       left.is_ptr() && right.is_ptr() => {
                let left = left.to_ptr()?;
                let right = right.to_ptr()?;
                if left.alloc_id == right.alloc_id {
                    let res = match bin_op {
                        Lt => left.offset < right.offset,
                        Le => left.offset <= right.offset,
                        Gt => left.offset > right.offset,
                        Ge => left.offset >= right.offset,
                        Sub => {
                            return self.binary_op(
                                Sub,
                                Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 },
                                self.tcx.types.usize,
                                Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 },
                                self.tcx.types.usize,
                            ).map(Some)
                        }
                        _ => bug!("We already established it has to be one of these operators."),
                    };
                    Ok(Some((Scalar::from_bool(res), false)))
                } else {
                    // Both are pointers, but from different allocations.
                    err!(InvalidPointerMath)
                }
            }
            // These work if one operand is a pointer, the other an integer
            Add | BitAnd | Sub
                if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
                       left.is_ptr() && right.is_bits() => {
                // Cast to i128 is fine as we checked the kind to be ptr-sized
                self.ptr_int_arithmetic(
                    bin_op,
                    left.to_ptr()?,
                    right.to_bits(self.memory.pointer_size())? as i128,
                    left_kind == isize,
                ).map(Some)
            }
            Add | BitAnd
                if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
                       left.is_bits() && right.is_ptr() => {
                // This is a commutative operation, just swap the operands
                self.ptr_int_arithmetic(
                    bin_op,
                    right.to_ptr()?,
                    left.to_bits(self.memory.pointer_size())? as i128,
                    left_kind == isize,
                ).map(Some)
            }
            _ => Ok(None),
        }
    }

    fn ptr_int_arithmetic(
        &self,
        bin_op: mir::BinOp,
        left: Pointer,
        right: i128,
        signed: bool,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        use rustc::mir::BinOp::*;

        fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) {
            (Scalar::Ptr(res), over)
        }

        Ok(match bin_op {
            Sub =>
                // The only way this can overflow is by underflowing, so signdeness of the right operands does not matter
                map_to_primval(left.overflowing_signed_offset(-right, self)),
            Add if signed =>
                map_to_primval(left.overflowing_signed_offset(right, self)),
            Add if !signed =>
                map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)),

            BitAnd if !signed => {
                let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1);
                let right = right as u64;
                if right & base_mask == base_mask {
                    // Case 1: The base address bits are all preserved, i.e., right is all-1 there
                    (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false)
                } else if right & base_mask == 0 {
                    // Case 2: The base address bits are all taken away, i.e., right is all-0 there
                    (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false)
                } else {
                    return err!(ReadPointerAsBytes);
                }
            }

            _ => {
                let msg = format!("unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", bin_op, left, right, if signed { "signed" } else { "unsigned" });
                return err!(Unimplemented(msg));
            }
        })
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! When serializing or deserializing JSON goes wrong.

use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;

use serde::de;
use serde::ser;

/// This type represents all possible errors that can occur when serializing or
/// deserializing JSON data.
pub struct Error {
    /// This `Box` allows us to keep the size of `Error` as small as possible. A
    /// larger `Error` type was substantially slower due to all the functions
    /// that pass around `Result<T, Error>`.
    err: Box<ErrorImpl>,
}

/// Alias for a `Result` with the error type `serde_json::Error`.
pub type Result<T> = result::Result<T, Error>;

impl Error {
    /// One-based line number at which the error was detected.
    ///
    /// Characters in the first line of the input (before the first newline
    /// character) are in line 1.
    pub fn line(&self) -> usize {
        self.err.line
    }

    /// One-based column number at which the error was detected.
    ///
    /// The first character in the input and any characters immediately
    /// following a newline character are in column 1.
    ///
    /// Note that errors may occur in column 0, for example if a read from an IO
    /// stream fails immediately following a previously read newline character.
    pub fn column(&self) -> usize {
        self.err.column
    }

    /// Categorizes the cause of this error.
    ///
    /// - `Category::Io` - failure to read or write bytes on an IO stream
    /// - `Category::Syntax` - input that is not syntactically valid JSON
    /// - `Category::Data` - input data that is semantically incorrect
    /// - `Category::Eof` - unexpected end of the input data
    pub fn classify(&self) -> Category {
        match self.err.code {
            ErrorCode::Message(_) => Category::Data,
            ErrorCode::Io(_) => Category::Io,
            ErrorCode::EofWhileParsingList |
            ErrorCode::EofWhileParsingObject |
            ErrorCode::EofWhileParsingString |
            ErrorCode::EofWhileParsingValue => Category::Eof,
            ErrorCode::ExpectedColon |
            ErrorCode::ExpectedListCommaOrEnd |
            ErrorCode::ExpectedObjectCommaOrEnd |
            ErrorCode::ExpectedObjectOrArray |
            ErrorCode::ExpectedSomeIdent |
            ErrorCode::ExpectedSomeValue |
            ErrorCode::ExpectedSomeString |
            ErrorCode::InvalidEscape |
            ErrorCode::InvalidNumber |
            ErrorCode::NumberOutOfRange |
            ErrorCode::InvalidUnicodeCodePoint |
            ErrorCode::KeyMustBeAString |
            ErrorCode::LoneLeadingSurrogateInHexEscape |
            ErrorCode::TrailingCharacters |
            ErrorCode::UnexpectedEndOfHexEscape |
            ErrorCode::RecursionLimitExceeded => Category::Syntax,
        }
    }

    /// Returns true if this error was caused by a failure to read or write
    /// bytes on an IO stream.
    pub fn is_io(&self) -> bool {
        self.classify() == Category::Io
    }

    /// Returns true if this error was caused by input that was not
    /// syntactically valid JSON.
    pub fn is_syntax(&self) -> bool {
        self.classify() == Category::Syntax
    }

    /// Returns true if this error was caused by input data that was
    /// semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    pub fn is_data(&self) -> bool {
        self.classify() == Category::Data
    }

    /// Returns true if this error was caused by prematurely reaching the end of
    /// the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    pub fn is_eof(&self) -> bool {
        self.classify() == Category::Eof
    }
}

/// Categorizes the cause of a `serde_json::Error`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
    /// The error was caused by a failure to read or write bytes on an IO
    /// stream.
    Io,

    /// The error was caused by input that was not syntactically valid JSON.
    Syntax,

    /// The error was caused by input data that was semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    Data,

    /// The error was caused by prematurely reaching the end of the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    Eof,
}

impl From<Error> for io::Error {
    /// Convert a `serde_json::Error` into an `io::Error`.
    ///
    /// JSON syntax and data errors are turned into `InvalidData` IO errors.
    /// EOF errors are turned into `UnexpectedEof` IO errors.
    ///
    /// ```rust
    /// use std::io;
    ///
    /// enum MyError {
    ///     Io(io::Error),
    ///     Json(serde_json::Error),
    /// }
    ///
    /// impl From<serde_json::Error> for MyError {
    ///     fn from(err: serde_json::Error) -> MyError {
    ///         use serde_json::error::Category;
    ///         match err.classify() {
    ///             Category::Io => {
    ///                 MyError::Io(err.into())
    ///             }
    ///             Category::Syntax | Category::Data | Category::Eof => {
    ///                 MyError::Json(err)
    ///             }
    ///         }
    ///     }
    /// }
    /// ```
    fn from(j: Error) -> Self {
        if let ErrorCode::Io(err) = j.err.code {
            err
        } else {
            match j.classify() {
                Category::Io => unreachable!(),
                Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j),
                Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j),
            }
        }
    }
}

#[derive(Debug)]
struct ErrorImpl {
    code: ErrorCode,
    line: usize,
    column: usize,
}

// Not public API. Should be pub(crate).
#[doc(hidden)]
#[derive(Debug)]
pub enum ErrorCode {
    /// Catchall for syntax error messages
    Message(String),

    /// Some IO error occurred while serializing or deserializing.
    Io(io::Error),

    /// EOF while parsing a list.
    EofWhileParsingList,

    /// EOF while parsing an object.
    EofWhileParsingObject,

    /// EOF while parsing a string.
    EofWhileParsingString,

    /// EOF while parsing a JSON value.
    EofWhileParsingValue,

    /// Expected this character to be a `':'`.
    ExpectedColon,

    /// Expected this character to be either a `','` or a `']'`.
    ExpectedListCommaOrEnd,

    /// Expected this character to be either a `','` or a `'}'`.
    ExpectedObjectCommaOrEnd,

    /// Expected this character to be either a `'{'` or a `'['`.
    ExpectedObjectOrArray,

    /// Expected to parse either a `true`, `false`, or a `null`.
    ExpectedSomeIdent,

    /// Expected this character to start a JSON value.
    ExpectedSomeValue,

    /// Expected this character to start a JSON string.
    ExpectedSomeString,

    /// Invalid hex escape code.
    InvalidEscape,

    /// Invalid number.
    InvalidNumber,

    /// Number is bigger than the maximum value of its type.
    NumberOutOfRange,

    /// Invalid unicode code point.
    InvalidUnicodeCodePoint,

    /// Object key is not a string.
    KeyMustBeAString,

    /// Lone leading surrogate in hex escape.
    LoneLeadingSurrogateInHexEscape,

    /// JSON has non-whitespace trailing characters after the value.
    TrailingCharacters,

    /// Unexpected end of hex excape.
    UnexpectedEndOfHexEscape,

    /// Encountered nesting of JSON maps and arrays more than 128 layers deep.
    RecursionLimitExceeded,
}

impl Error {
    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: code,
                    line: line,
                    column: column,
                },
            ),
        }
    }

    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn fix_position<F>(self, f: F) -> Self
    where
        F: FnOnce(ErrorCode) -> Error,
    {
        if self.err.line == 0 {
            f(self.err.code)
        } else {
            self
        }
    }
}

impl Display for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCode::Message(ref msg) => f.write_str(msg),
            ErrorCode::Io(ref err) => Display::fmt(err, f),
            ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"),
            ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"),
            ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"),
            ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"),
            ErrorCode::ExpectedColon => f.write_str("expected `:`"),
            ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"),
            ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"),
            ErrorCode::ExpectedObjectOrArray => f.write_str("expected `{` or `[`"),
            ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"),
            ErrorCode::ExpectedSomeValue => f.write_str("expected value"),
            ErrorCode::ExpectedSomeString => f.write_str("expected string"),
            ErrorCode::InvalidEscape => f.write_str("invalid escape"),
            ErrorCode::InvalidNumber => f.write_str("invalid number"),
            ErrorCode::NumberOutOfRange => f.write_str("number out of range"),
            ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
            ErrorCode::KeyMustBeAString => f.write_str("key must be a string"),
            ErrorCode::LoneLeadingSurrogateInHexEscape => {
                f.write_str("lone leading surrogate in hex escape")
            }
            ErrorCode::TrailingCharacters => f.write_str("trailing characters"),
            ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"),
            ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self.err.code {
            ErrorCode::Io(ref err) => error::Error::description(err),
            _ => {
                // If you want a better message, use Display::fmt or to_string().
                "JSON error"
            }
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.err.code {
            ErrorCode::Io(ref err) => Some(err),
            _ => None,
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&*self.err, f)
    }
}

impl Display for ErrorImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.line == 0 {
            Display::fmt(&self.code, f)
        } else {
            write!(
                f,
                "{} at line {} column {}",
                self.code,
                self.line,
                self.column
            )
        }
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&*self.err, f)
    }
}

impl From<ErrorImpl> for Error {
    fn from(error: ErrorImpl) -> Error {
        Error { err: Box::new(error) }
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Io(error),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }
}

impl de::Error for Error {
    fn custom<T: Display>(msg: T) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Message(msg.to_string()),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }
}

impl ser::Error for Error {
    fn custom<T: Display>(msg: T) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Message(msg.to_string()),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }
}
<commit_msg>Remove unused ErrorImpl conversion<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! When serializing or deserializing JSON goes wrong.

use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;

use serde::de;
use serde::ser;

/// This type represents all possible errors that can occur when serializing or
/// deserializing JSON data.
pub struct Error {
    /// This `Box` allows us to keep the size of `Error` as small as possible. A
    /// larger `Error` type was substantially slower due to all the functions
    /// that pass around `Result<T, Error>`.
    err: Box<ErrorImpl>,
}

/// Alias for a `Result` with the error type `serde_json::Error`.
pub type Result<T> = result::Result<T, Error>;

impl Error {
    /// One-based line number at which the error was detected.
    ///
    /// Characters in the first line of the input (before the first newline
    /// character) are in line 1.
    pub fn line(&self) -> usize {
        self.err.line
    }

    /// One-based column number at which the error was detected.
    ///
    /// The first character in the input and any characters immediately
    /// following a newline character are in column 1.
    ///
    /// Note that errors may occur in column 0, for example if a read from an IO
    /// stream fails immediately following a previously read newline character.
    pub fn column(&self) -> usize {
        self.err.column
    }

    /// Categorizes the cause of this error.
    ///
    /// - `Category::Io` - failure to read or write bytes on an IO stream
    /// - `Category::Syntax` - input that is not syntactically valid JSON
    /// - `Category::Data` - input data that is semantically incorrect
    /// - `Category::Eof` - unexpected end of the input data
    pub fn classify(&self) -> Category {
        match self.err.code {
            ErrorCode::Message(_) => Category::Data,
            ErrorCode::Io(_) => Category::Io,
            ErrorCode::EofWhileParsingList |
            ErrorCode::EofWhileParsingObject |
            ErrorCode::EofWhileParsingString |
            ErrorCode::EofWhileParsingValue => Category::Eof,
            ErrorCode::ExpectedColon |
            ErrorCode::ExpectedListCommaOrEnd |
            ErrorCode::ExpectedObjectCommaOrEnd |
            ErrorCode::ExpectedObjectOrArray |
            ErrorCode::ExpectedSomeIdent |
            ErrorCode::ExpectedSomeValue |
            ErrorCode::ExpectedSomeString |
            ErrorCode::InvalidEscape |
            ErrorCode::InvalidNumber |
            ErrorCode::NumberOutOfRange |
            ErrorCode::InvalidUnicodeCodePoint |
            ErrorCode::KeyMustBeAString |
            ErrorCode::LoneLeadingSurrogateInHexEscape |
            ErrorCode::TrailingCharacters |
            ErrorCode::UnexpectedEndOfHexEscape |
            ErrorCode::RecursionLimitExceeded => Category::Syntax,
        }
    }

    /// Returns true if this error was caused by a failure to read or write
    /// bytes on an IO stream.
    pub fn is_io(&self) -> bool {
        self.classify() == Category::Io
    }

    /// Returns true if this error was caused by input that was not
    /// syntactically valid JSON.
    pub fn is_syntax(&self) -> bool {
        self.classify() == Category::Syntax
    }

    /// Returns true if this error was caused by input data that was
    /// semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    pub fn is_data(&self) -> bool {
        self.classify() == Category::Data
    }

    /// Returns true if this error was caused by prematurely reaching the end of
    /// the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    pub fn is_eof(&self) -> bool {
        self.classify() == Category::Eof
    }
}

/// Categorizes the cause of a `serde_json::Error`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
    /// The error was caused by a failure to read or write bytes on an IO
    /// stream.
    Io,

    /// The error was caused by input that was not syntactically valid JSON.
    Syntax,

    /// The error was caused by input data that was semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    Data,

    /// The error was caused by prematurely reaching the end of the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    Eof,
}

impl From<Error> for io::Error {
    /// Convert a `serde_json::Error` into an `io::Error`.
    ///
    /// JSON syntax and data errors are turned into `InvalidData` IO errors.
    /// EOF errors are turned into `UnexpectedEof` IO errors.
    ///
    /// ```rust
    /// use std::io;
    ///
    /// enum MyError {
    ///     Io(io::Error),
    ///     Json(serde_json::Error),
    /// }
    ///
    /// impl From<serde_json::Error> for MyError {
    ///     fn from(err: serde_json::Error) -> MyError {
    ///         use serde_json::error::Category;
    ///         match err.classify() {
    ///             Category::Io => {
    ///                 MyError::Io(err.into())
    ///             }
    ///             Category::Syntax | Category::Data | Category::Eof => {
    ///                 MyError::Json(err)
    ///             }
    ///         }
    ///     }
    /// }
    /// ```
    fn from(j: Error) -> Self {
        if let ErrorCode::Io(err) = j.err.code {
            err
        } else {
            match j.classify() {
                Category::Io => unreachable!(),
                Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j),
                Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j),
            }
        }
    }
}

#[derive(Debug)]
struct ErrorImpl {
    code: ErrorCode,
    line: usize,
    column: usize,
}

// Not public API. Should be pub(crate).
#[doc(hidden)]
#[derive(Debug)]
pub enum ErrorCode {
    /// Catchall for syntax error messages
    Message(String),

    /// Some IO error occurred while serializing or deserializing.
    Io(io::Error),

    /// EOF while parsing a list.
    EofWhileParsingList,

    /// EOF while parsing an object.
    EofWhileParsingObject,

    /// EOF while parsing a string.
    EofWhileParsingString,

    /// EOF while parsing a JSON value.
    EofWhileParsingValue,

    /// Expected this character to be a `':'`.
    ExpectedColon,

    /// Expected this character to be either a `','` or a `']'`.
    ExpectedListCommaOrEnd,

    /// Expected this character to be either a `','` or a `'}'`.
    ExpectedObjectCommaOrEnd,

    /// Expected this character to be either a `'{'` or a `'['`.
    ExpectedObjectOrArray,

    /// Expected to parse either a `true`, `false`, or a `null`.
    ExpectedSomeIdent,

    /// Expected this character to start a JSON value.
    ExpectedSomeValue,

    /// Expected this character to start a JSON string.
    ExpectedSomeString,

    /// Invalid hex escape code.
    InvalidEscape,

    /// Invalid number.
    InvalidNumber,

    /// Number is bigger than the maximum value of its type.
    NumberOutOfRange,

    /// Invalid unicode code point.
    InvalidUnicodeCodePoint,

    /// Object key is not a string.
    KeyMustBeAString,

    /// Lone leading surrogate in hex escape.
    LoneLeadingSurrogateInHexEscape,

    /// JSON has non-whitespace trailing characters after the value.
    TrailingCharacters,

    /// Unexpected end of hex excape.
    UnexpectedEndOfHexEscape,

    /// Encountered nesting of JSON maps and arrays more than 128 layers deep.
    RecursionLimitExceeded,
}

impl Error {
    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: code,
                    line: line,
                    column: column,
                },
            ),
        }
    }

    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn fix_position<F>(self, f: F) -> Self
    where
        F: FnOnce(ErrorCode) -> Error,
    {
        if self.err.line == 0 {
            f(self.err.code)
        } else {
            self
        }
    }
}

impl Display for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCode::Message(ref msg) => f.write_str(msg),
            ErrorCode::Io(ref err) => Display::fmt(err, f),
            ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"),
            ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"),
            ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"),
            ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"),
            ErrorCode::ExpectedColon => f.write_str("expected `:`"),
            ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"),
            ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"),
            ErrorCode::ExpectedObjectOrArray => f.write_str("expected `{` or `[`"),
            ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"),
            ErrorCode::ExpectedSomeValue => f.write_str("expected value"),
            ErrorCode::ExpectedSomeString => f.write_str("expected string"),
            ErrorCode::InvalidEscape => f.write_str("invalid escape"),
            ErrorCode::InvalidNumber => f.write_str("invalid number"),
            ErrorCode::NumberOutOfRange => f.write_str("number out of range"),
            ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
            ErrorCode::KeyMustBeAString => f.write_str("key must be a string"),
            ErrorCode::LoneLeadingSurrogateInHexEscape => {
                f.write_str("lone leading surrogate in hex escape")
            }
            ErrorCode::TrailingCharacters => f.write_str("trailing characters"),
            ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"),
            ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self.err.code {
            ErrorCode::Io(ref err) => error::Error::description(err),
            _ => {
                // If you want a better message, use Display::fmt or to_string().
                "JSON error"
            }
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.err.code {
            ErrorCode::Io(ref err) => Some(err),
            _ => None,
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&*self.err, f)
    }
}

impl Display for ErrorImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.line == 0 {
            Display::fmt(&self.code, f)
        } else {
            write!(
                f,
                "{} at line {} column {}",
                self.code,
                self.line,
                self.column
            )
        }
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&*self.err, f)
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Io(error),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }
}

impl de::Error for Error {
    fn custom<T: Display>(msg: T) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Message(msg.to_string()),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }
}

impl ser::Error for Error {
    fn custom<T: Display>(msg: T) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Message(msg.to_string()),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }
}
<|endoftext|>


<commit_before>//! This module focuses on handling errors generated when using Ardite in a
//! graceful manner.

#[cfg(test)]
use regex::Regex;
use std::io::Error as IOError;
use std::error::Error as ErrorTrait;
use serde_json::error::Error as JSONError;
use serde_yaml::error::Error as YAMLError;

/// The code of an error. Designed to easily map to [HTTP status codes][1].
///
/// [1]: http://www.restapitutorial.com/httpstatuscodes.html
#[derive(PartialEq, Debug)]
pub enum ErrorCode {
  /// A bad syntax was used. Maps to 400.
  BadRequest = 400,
  /// Permissions do not allow this to happen. Maps to 403.
  Forbidden = 403,
  /// Resource was not found. Maps to 404.
  NotFound = 404,
  /// The requested resource is not acceptable. Maps to 406.
  NotAcceptable = 406,
  /// Present data made the request fail. Maps to 409.
  Conflict = 409,
  /// There was an invalid range. Maps to 416.
  BadRange = 416,
  /// Something bad happened inside a driver. Maps to 500.
  Internal = 500,
  /// The feature has not been implemented. Maps to 501.
  NotImplemented = 501
}

/// Any error generated by Ardite or it‘s drivers should be output using this
/// type. This allows for a comprehensive display of the error when a service
/// reports it to the user.
// TODO: Remove `pub` when `impl`ing the standard `Error` trait.
#[derive(PartialEq, Debug)]
pub struct Error {
  /// A specific error code which describes the error.
  code: ErrorCode,
  /// A message providing more detail beyond the error code.
  message: String,
  /// A hint to the user on what to do next to try and avoid the error
  /// happening again. This is optional.
  hint: Option<String>
}

impl Error {
  /// Easily create a new error.
  pub fn new<S>(code: ErrorCode, message: S, hint: Option<S>) -> Self where S: Into<String> {
    Error {
      code: code,
      message: message.into(),
      hint: hint.map(|string| string.into())
    }
  }

  /// Convenience function for saying a thing failed validation.
  pub fn validation<S1, S2>(message: S1, hint: S2) -> Self where S1: Into<String>, S2: Into<String> {
    Error {
      code: ErrorCode::BadRequest,
      message: message.into(),
      hint: Some(hint.into())
    }
  }

  /// Convenience function for saying there was an internal error.
  pub fn internal<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::Internal,
      message: message.into(),
      hint: None
    }
  }

  /// Convenience function for creating an unimplemented error with a plain
  /// message describing what is unimplemented.
  pub fn unimplemented<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::NotImplemented,
      message: message.into(),
      hint: None
    }
  }

  /// Special assertion for error messages. Takes a regular expression string
  /// argument which will automatically be constructed into a regualr
  /// expression. Only available in testing environments. Panics if the regular
  /// expression doesn’t match the error message string.
  #[cfg(test)]
  pub fn assert_message(&self, regex_str: &str) {
    if !Regex::new(regex_str).unwrap().is_match(&self.message) {
      panic!("Error message \"{}\" does not match regex /{}/", self.message, regex_str);
    }
  }
}

impl From<IOError> for Error {
  fn from(error: IOError) -> Self {
    Error {
      code: ErrorCode::Internal,
      message: error.description().to_string(),
      hint: None
    }
  }
}

impl From<JSONError> for Error {
  fn from(error: JSONError) -> Self {
    match &error {
      &JSONError::Syntax(_, line, column) => {
        Error {
          code: ErrorCode::BadRequest,
          message: error.description().to_string(),
          hint: Some(format!("Fix your JSON syntax around line {} column {}.", line, column))
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_string(),
          hint: None
        }
      }
    }
  }
}

impl From<YAMLError> for Error {
  fn from(error: YAMLError) -> Self {
    match &error {
      &YAMLError::Custom(ref message) => {
        Error {
          code: ErrorCode::BadRequest,
          message: message.clone(),
          hint: Some("Fix your YAML syntax.".to_string())
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_string(),
          hint: None
        }
      }
    }
  }
}
<commit_msg>style: nicer hint suggestions<commit_after>//! This module focuses on handling errors generated when using Ardite in a
//! graceful manner.

#[cfg(test)]
use regex::Regex;
use std::io::Error as IOError;
use std::error::Error as ErrorTrait;
use serde_json::error::Error as JSONError;
use serde_yaml::error::Error as YAMLError;

/// The code of an error. Designed to easily map to [HTTP status codes][1].
///
/// [1]: http://www.restapitutorial.com/httpstatuscodes.html
#[derive(PartialEq, Debug)]
pub enum ErrorCode {
  /// A bad syntax was used. Maps to 400.
  BadRequest = 400,
  /// Permissions do not allow this to happen. Maps to 403.
  Forbidden = 403,
  /// Resource was not found. Maps to 404.
  NotFound = 404,
  /// The requested resource is not acceptable. Maps to 406.
  NotAcceptable = 406,
  /// Present data made the request fail. Maps to 409.
  Conflict = 409,
  /// There was an invalid range. Maps to 416.
  BadRange = 416,
  /// Something bad happened inside a driver. Maps to 500.
  Internal = 500,
  /// The feature has not been implemented. Maps to 501.
  NotImplemented = 501
}

/// Any error generated by Ardite or it‘s drivers should be output using this
/// type. This allows for a comprehensive display of the error when a service
/// reports it to the user.
// TODO: Remove `pub` when `impl`ing the standard `Error` trait.
#[derive(PartialEq, Debug)]
pub struct Error {
  /// A specific error code which describes the error.
  code: ErrorCode,
  /// A message providing more detail beyond the error code.
  message: String,
  /// A hint to the user on what to do next to try and avoid the error
  /// happening again. This is optional.
  hint: Option<String>
}

impl Error {
  /// Easily create a new error.
  pub fn new<S>(code: ErrorCode, message: S, hint: Option<S>) -> Self where S: Into<String> {
    Error {
      code: code,
      message: message.into(),
      hint: hint.map(|string| string.into())
    }
  }

  /// Convenience function for saying a thing failed validation.
  pub fn validation<S1, S2>(message: S1, hint: S2) -> Self where S1: Into<String>, S2: Into<String> {
    Error {
      code: ErrorCode::BadRequest,
      message: message.into(),
      hint: Some(hint.into())
    }
  }

  /// Convenience function for saying there was an internal error.
  pub fn internal<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::Internal,
      message: message.into(),
      hint: None
    }
  }

  /// Convenience function for creating an unimplemented error with a plain
  /// message describing what is unimplemented.
  pub fn unimplemented<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::NotImplemented,
      message: message.into(),
      hint: None
    }
  }

  /// Special assertion for error messages. Takes a regular expression string
  /// argument which will automatically be constructed into a regualr
  /// expression. Only available in testing environments. Panics if the regular
  /// expression doesn’t match the error message string.
  #[cfg(test)]
  pub fn assert_message(&self, regex_str: &str) {
    if !Regex::new(regex_str).unwrap().is_match(&self.message) {
      panic!("Error message \"{}\" does not match regex /{}/", self.message, regex_str);
    }
  }
}

impl From<IOError> for Error {
  fn from(error: IOError) -> Self {
    Error {
      code: ErrorCode::Internal,
      message: error.description().to_string(),
      hint: None
    }
  }
}

impl From<JSONError> for Error {
  fn from(error: JSONError) -> Self {
    match &error {
      &JSONError::Syntax(_, line, column) => {
        Error {
          code: ErrorCode::BadRequest,
          message: error.description().to_string(),
          hint: Some(format!("Max sure your JSON syntax is correct around line {} column {}.", line, column))
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_string(),
          hint: None
        }
      }
    }
  }
}

impl From<YAMLError> for Error {
  fn from(error: YAMLError) -> Self {
    match &error {
      &YAMLError::Custom(ref message) => {
        Error {
          code: ErrorCode::BadRequest,
          message: message.clone(),
          hint: Some("Make sure your YAML syntax is correct.".to_string())
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_string(),
          hint: None
        }
      }
    }
  }
}
<|endoftext|>