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

//! Base types that the block chain pipeline requires.

use chrono::prelude::{DateTime, Utc};
use std::sync::Arc;

use crate::core::core::hash::{Hash, Hashed, ZERO_HASH};
use crate::core::core::{Block, BlockHeader, HeaderVersion};
use crate::core::pow::Difficulty;
use crate::core::ser::{self, PMMRIndexHashable, Readable, Reader, Writeable, Writer};
use crate::error::{Error, ErrorKind};
use crate::util::secp::pedersen::Commitment;
use crate::util::RwLock;

bitflags! {
/// Options for block validation
	pub struct Options: u32 {
		/// No flags
		const NONE = 0b0000_0000;
		/// Runs without checking the Proof of Work, mostly to make testing easier.
		const SKIP_POW = 0b0000_0001;
		/// Adds block while in syncing mode.
		const SYNC = 0b0000_0010;
		/// Block validation on a block we mined ourselves
		const MINE = 0b0000_0100;
	}
}

/// Various status sync can be in, whether it's fast sync or archival.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
#[allow(missing_docs)]
pub enum SyncStatus {
	/// Initial State (we do not yet know if we are/should be syncing)
	Initial,
	/// Not syncing
	NoSync,
	/// Not enough peers to do anything yet, boolean indicates whether
	/// we should wait at all or ignore and start ASAP
	AwaitingPeers(bool),
	/// Downloading block headers
	HeaderSync {
		current_height: u64,
		highest_height: u64,
	},
	/// Downloading the various txhashsets
	TxHashsetDownload {
		start_time: DateTime<Utc>,
		prev_update_time: DateTime<Utc>,
		update_time: DateTime<Utc>,
		prev_downloaded_size: u64,
		downloaded_size: u64,
		total_size: u64,
	},
	/// Setting up before validation
	TxHashsetSetup,
	/// Validating the kernels
	TxHashsetKernelsValidation {
		kernels: u64,
		kernels_total: u64,
	},
	/// Validating the range proofs
	TxHashsetRangeProofsValidation {
		rproofs: u64,
		rproofs_total: u64,
	},
	/// Finalizing the new state
	TxHashsetSave,
	/// State sync finalized
	TxHashsetDone,
	/// Downloading blocks
	BodySync {
		current_height: u64,
		highest_height: u64,
	},
	Shutdown,
}

/// Current sync state. Encapsulates the current SyncStatus.
pub struct SyncState {
	current: RwLock<SyncStatus>,
	sync_error: Arc<RwLock<Option<Error>>>,
}

impl SyncState {
	/// Return a new SyncState initialize to NoSync
	pub fn new() -> SyncState {
		SyncState {
			current: RwLock::new(SyncStatus::Initial),
			sync_error: Arc::new(RwLock::new(None)),
		}
	}

	/// Whether the current state matches any active syncing operation.
	/// Note: This includes our "initial" state.
	pub fn is_syncing(&self) -> bool {
		*self.current.read() != SyncStatus::NoSync
	}

	/// Current syncing status
	pub fn status(&self) -> SyncStatus {
		*self.current.read()
	}

	/// Update the syncing status
	pub fn update(&self, new_status: SyncStatus) {
		if self.status() == new_status {
			return;
		}

		let mut status = self.current.write();

		debug!("sync_state: sync_status: {:?} -> {:?}", *status, new_status,);

		*status = new_status;
	}

	/// Update txhashset downloading progress
	pub fn update_txhashset_download(&self, new_status: SyncStatus) -> bool {
		if let SyncStatus::TxHashsetDownload { .. } = new_status {
			let mut status = self.current.write();
			*status = new_status;
			true
		} else {
			false
		}
	}

	/// Communicate sync error
	pub fn set_sync_error(&self, error: Error) {
		*self.sync_error.write() = Some(error);
	}

	/// Get sync error
	pub fn sync_error(&self) -> Arc<RwLock<Option<Error>>> {
		Arc::clone(&self.sync_error)
	}

	/// Clear sync error
	pub fn clear_sync_error(&self) {
		*self.sync_error.write() = None;
	}
}

impl TxHashsetWriteStatus for SyncState {
	fn on_setup(&self) {
		self.update(SyncStatus::TxHashsetSetup);
	}

	fn on_validation_kernels(&self, kernels: u64, kernels_total: u64) {
		self.update(SyncStatus::TxHashsetKernelsValidation {
			kernels,
			kernels_total,
		});
	}

	fn on_validation_rproofs(&self, rproofs: u64, rproofs_total: u64) {
		self.update(SyncStatus::TxHashsetRangeProofsValidation {
			rproofs,
			rproofs_total,
		});
	}

	fn on_save(&self) {
		self.update(SyncStatus::TxHashsetSave);
	}

	fn on_done(&self) {
		self.update(SyncStatus::TxHashsetDone);
	}
}

/// A helper for the various txhashset MMR roots.
#[derive(Debug)]
pub struct TxHashSetRoots {
	/// Output roots
	pub output_roots: OutputRoots,
	/// Range Proof root
	pub rproof_root: Hash,
	/// Kernel root
	pub kernel_root: Hash,
}

impl TxHashSetRoots {
	/// Accessor for the output PMMR root (rules here are block height dependent).
	/// We assume the header version is consistent with the block height, validated
	/// as part of pipe::validate_header().
	pub fn output_root(&self, header: &BlockHeader) -> Hash {
		self.output_roots.root(header)
	}

	/// Validate roots against the provided block header.
	pub fn validate(&self, header: &BlockHeader) -> Result<(), Error> {
		debug!(
			"validate roots: {} at {}, {} vs. {} (original: {}, merged: {})",
			header.hash(),
			header.height,
			header.output_root,
			self.output_root(header),
			self.output_roots.pmmr_root,
			self.output_roots.merged_root(header),
		);

		if header.output_root != self.output_root(header)
			|| header.range_proof_root != self.rproof_root
			|| header.kernel_root != self.kernel_root
		{
			Err(ErrorKind::InvalidRoot.into())
		} else {
			Ok(())
		}
	}
}

/// A helper for the various output roots.
#[derive(Debug)]
pub struct OutputRoots {
	/// The output PMMR root
	pub pmmr_root: Hash,
	/// The bitmap accumulator root
	pub bitmap_root: Hash,
}

impl OutputRoots {
	/// The root of our output PMMR. The rules here are block height specific.
	/// We use the merged root here for header version 3 and later.
	/// We assume the header version is consistent with the block height, validated
	/// as part of pipe::validate_header().
	pub fn root(&self, header: &BlockHeader) -> Hash {
		if header.version < HeaderVersion(3) {
			self.output_root()
		} else {
			self.merged_root(header)
		}
	}

	/// The root of the underlying output PMMR.
	fn output_root(&self) -> Hash {
		self.pmmr_root
	}

	/// Hash the root of the output PMMR and the root of the bitmap accumulator
	/// together with the size of the output PMMR (for consistency with existing PMMR impl).
	/// H(pmmr_size | pmmr_root | bitmap_root)
	fn merged_root(&self, header: &BlockHeader) -> Hash {
		(self.pmmr_root, self.bitmap_root).hash_with_index(header.output_mmr_size)
	}
}

/// Minimal struct representing a known MMR position and associated block height.
#[derive(Debug)]
pub struct CommitPos {
	/// MMR position
	pub pos: u64,
	/// Block height
	pub height: u64,
}

impl Readable for CommitPos {
	fn read(reader: &mut dyn Reader) -> Result<CommitPos, ser::Error> {
		let pos = reader.read_u64()?;
		let height = reader.read_u64()?;
		Ok(CommitPos { pos, height })
	}
}

impl Writeable for CommitPos {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		writer.write_u64(self.pos)?;
		writer.write_u64(self.height)?;
		Ok(())
	}
}

/// The tip of a fork. A handle to the fork ancestry from its leaf in the
/// blockchain tree. References the max height and the latest and previous
/// blocks
/// for convenience and the total difficulty.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Tip {
	/// Height of the tip (max height of the fork)
	pub height: u64,
	/// Last block pushed to the fork
	pub last_block_h: Hash,
	/// Previous block
	pub prev_block_h: Hash,
	/// Total difficulty accumulated on that fork
	pub total_difficulty: Difficulty,
}

impl Tip {
	/// Creates a new tip based on provided header.
	pub fn from_header(header: &BlockHeader) -> Tip {
		Tip {
			height: header.height,
			last_block_h: header.hash(),
			prev_block_h: header.prev_hash,
			total_difficulty: header.total_difficulty(),
		}
	}
}

impl Hashed for Tip {
	/// The hash of the underlying block.
	fn hash(&self) -> Hash {
		self.last_block_h
	}
}

impl Default for Tip {
	fn default() -> Self {
		Tip {
			height: 0,
			last_block_h: ZERO_HASH,
			prev_block_h: ZERO_HASH,
			total_difficulty: Difficulty::min(),
		}
	}
}

/// Serialization of a tip, required to save to datastore.
impl ser::Writeable for Tip {
	fn write<W: ser::Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		writer.write_u64(self.height)?;
		writer.write_fixed_bytes(&self.last_block_h)?;
		writer.write_fixed_bytes(&self.prev_block_h)?;
		self.total_difficulty.write(writer)
	}
}

impl ser::Readable for Tip {
	fn read(reader: &mut dyn ser::Reader) -> Result<Tip, ser::Error> {
		let height = reader.read_u64()?;
		let last = Hash::read(reader)?;
		let prev = Hash::read(reader)?;
		let diff = Difficulty::read(reader)?;
		Ok(Tip {
			height: height,
			last_block_h: last,
			prev_block_h: prev,
			total_difficulty: diff,
		})
	}
}

/// Bridge between the chain pipeline and the rest of the system. Handles
/// downstream processing of valid blocks by the rest of the system, most
/// importantly the broadcasting of blocks to our peers.
pub trait ChainAdapter {
	/// The blockchain pipeline has accepted this block as valid and added
	/// it to our chain.
	fn block_accepted(&self, block: &Block, status: BlockStatus, opts: Options);
}

/// Inform the caller of the current status of a txhashset write operation,
/// as it can take quite a while to process. Each function is called in the
/// order defined below and can be used to provide some feedback to the
/// caller. Functions taking arguments can be called repeatedly to update
/// those values as the processing progresses.
pub trait TxHashsetWriteStatus {
	/// First setup of the txhashset
	fn on_setup(&self);
	/// Starting kernel validation
	fn on_validation_kernels(&self, kernels: u64, kernel_total: u64);
	/// Starting rproof validation
	fn on_validation_rproofs(&self, rproofs: u64, rproof_total: u64);
	/// Starting to save the txhashset and related data
	fn on_save(&self);
	/// Done writing a new txhashset
	fn on_done(&self);
}

/// Do-nothing implementation of TxHashsetWriteStatus
pub struct NoStatus;

impl TxHashsetWriteStatus for NoStatus {
	fn on_setup(&self) {}
	fn on_validation_kernels(&self, _ks: u64, _kts: u64) {}
	fn on_validation_rproofs(&self, _rs: u64, _rt: u64) {}
	fn on_save(&self) {}
	fn on_done(&self) {}
}

/// Dummy adapter used as a placeholder for real implementations
pub struct NoopAdapter {}

impl ChainAdapter for NoopAdapter {
	fn block_accepted(&self, _b: &Block, _status: BlockStatus, _opts: Options) {}
}

/// Status of an accepted block.
#[derive(Debug, Clone, PartialEq)]
pub enum BlockStatus {
	/// Block is the "next" block, updating the chain head.
	Next,
	/// Block does not update the chain head and is a fork.
	Fork,
	/// Block updates the chain head via a (potentially disruptive) "reorg".
	/// Previous block was not our previous chain head.
	Reorg(u64),
}
<commit_msg>cleanup unused import (#3238)<commit_after>// Copyright 2020 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.

//! Base types that the block chain pipeline requires.

use chrono::prelude::{DateTime, Utc};
use std::sync::Arc;

use crate::core::core::hash::{Hash, Hashed, ZERO_HASH};
use crate::core::core::{Block, BlockHeader, HeaderVersion};
use crate::core::pow::Difficulty;
use crate::core::ser::{self, PMMRIndexHashable, Readable, Reader, Writeable, Writer};
use crate::error::{Error, ErrorKind};
use crate::util::RwLock;

bitflags! {
/// Options for block validation
	pub struct Options: u32 {
		/// No flags
		const NONE = 0b0000_0000;
		/// Runs without checking the Proof of Work, mostly to make testing easier.
		const SKIP_POW = 0b0000_0001;
		/// Adds block while in syncing mode.
		const SYNC = 0b0000_0010;
		/// Block validation on a block we mined ourselves
		const MINE = 0b0000_0100;
	}
}

/// Various status sync can be in, whether it's fast sync or archival.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
#[allow(missing_docs)]
pub enum SyncStatus {
	/// Initial State (we do not yet know if we are/should be syncing)
	Initial,
	/// Not syncing
	NoSync,
	/// Not enough peers to do anything yet, boolean indicates whether
	/// we should wait at all or ignore and start ASAP
	AwaitingPeers(bool),
	/// Downloading block headers
	HeaderSync {
		current_height: u64,
		highest_height: u64,
	},
	/// Downloading the various txhashsets
	TxHashsetDownload {
		start_time: DateTime<Utc>,
		prev_update_time: DateTime<Utc>,
		update_time: DateTime<Utc>,
		prev_downloaded_size: u64,
		downloaded_size: u64,
		total_size: u64,
	},
	/// Setting up before validation
	TxHashsetSetup,
	/// Validating the kernels
	TxHashsetKernelsValidation {
		kernels: u64,
		kernels_total: u64,
	},
	/// Validating the range proofs
	TxHashsetRangeProofsValidation {
		rproofs: u64,
		rproofs_total: u64,
	},
	/// Finalizing the new state
	TxHashsetSave,
	/// State sync finalized
	TxHashsetDone,
	/// Downloading blocks
	BodySync {
		current_height: u64,
		highest_height: u64,
	},
	Shutdown,
}

/// Current sync state. Encapsulates the current SyncStatus.
pub struct SyncState {
	current: RwLock<SyncStatus>,
	sync_error: Arc<RwLock<Option<Error>>>,
}

impl SyncState {
	/// Return a new SyncState initialize to NoSync
	pub fn new() -> SyncState {
		SyncState {
			current: RwLock::new(SyncStatus::Initial),
			sync_error: Arc::new(RwLock::new(None)),
		}
	}

	/// Whether the current state matches any active syncing operation.
	/// Note: This includes our "initial" state.
	pub fn is_syncing(&self) -> bool {
		*self.current.read() != SyncStatus::NoSync
	}

	/// Current syncing status
	pub fn status(&self) -> SyncStatus {
		*self.current.read()
	}

	/// Update the syncing status
	pub fn update(&self, new_status: SyncStatus) {
		if self.status() == new_status {
			return;
		}

		let mut status = self.current.write();

		debug!("sync_state: sync_status: {:?} -> {:?}", *status, new_status,);

		*status = new_status;
	}

	/// Update txhashset downloading progress
	pub fn update_txhashset_download(&self, new_status: SyncStatus) -> bool {
		if let SyncStatus::TxHashsetDownload { .. } = new_status {
			let mut status = self.current.write();
			*status = new_status;
			true
		} else {
			false
		}
	}

	/// Communicate sync error
	pub fn set_sync_error(&self, error: Error) {
		*self.sync_error.write() = Some(error);
	}

	/// Get sync error
	pub fn sync_error(&self) -> Arc<RwLock<Option<Error>>> {
		Arc::clone(&self.sync_error)
	}

	/// Clear sync error
	pub fn clear_sync_error(&self) {
		*self.sync_error.write() = None;
	}
}

impl TxHashsetWriteStatus for SyncState {
	fn on_setup(&self) {
		self.update(SyncStatus::TxHashsetSetup);
	}

	fn on_validation_kernels(&self, kernels: u64, kernels_total: u64) {
		self.update(SyncStatus::TxHashsetKernelsValidation {
			kernels,
			kernels_total,
		});
	}

	fn on_validation_rproofs(&self, rproofs: u64, rproofs_total: u64) {
		self.update(SyncStatus::TxHashsetRangeProofsValidation {
			rproofs,
			rproofs_total,
		});
	}

	fn on_save(&self) {
		self.update(SyncStatus::TxHashsetSave);
	}

	fn on_done(&self) {
		self.update(SyncStatus::TxHashsetDone);
	}
}

/// A helper for the various txhashset MMR roots.
#[derive(Debug)]
pub struct TxHashSetRoots {
	/// Output roots
	pub output_roots: OutputRoots,
	/// Range Proof root
	pub rproof_root: Hash,
	/// Kernel root
	pub kernel_root: Hash,
}

impl TxHashSetRoots {
	/// Accessor for the output PMMR root (rules here are block height dependent).
	/// We assume the header version is consistent with the block height, validated
	/// as part of pipe::validate_header().
	pub fn output_root(&self, header: &BlockHeader) -> Hash {
		self.output_roots.root(header)
	}

	/// Validate roots against the provided block header.
	pub fn validate(&self, header: &BlockHeader) -> Result<(), Error> {
		debug!(
			"validate roots: {} at {}, {} vs. {} (original: {}, merged: {})",
			header.hash(),
			header.height,
			header.output_root,
			self.output_root(header),
			self.output_roots.pmmr_root,
			self.output_roots.merged_root(header),
		);

		if header.output_root != self.output_root(header)
			|| header.range_proof_root != self.rproof_root
			|| header.kernel_root != self.kernel_root
		{
			Err(ErrorKind::InvalidRoot.into())
		} else {
			Ok(())
		}
	}
}

/// A helper for the various output roots.
#[derive(Debug)]
pub struct OutputRoots {
	/// The output PMMR root
	pub pmmr_root: Hash,
	/// The bitmap accumulator root
	pub bitmap_root: Hash,
}

impl OutputRoots {
	/// The root of our output PMMR. The rules here are block height specific.
	/// We use the merged root here for header version 3 and later.
	/// We assume the header version is consistent with the block height, validated
	/// as part of pipe::validate_header().
	pub fn root(&self, header: &BlockHeader) -> Hash {
		if header.version < HeaderVersion(3) {
			self.output_root()
		} else {
			self.merged_root(header)
		}
	}

	/// The root of the underlying output PMMR.
	fn output_root(&self) -> Hash {
		self.pmmr_root
	}

	/// Hash the root of the output PMMR and the root of the bitmap accumulator
	/// together with the size of the output PMMR (for consistency with existing PMMR impl).
	/// H(pmmr_size | pmmr_root | bitmap_root)
	fn merged_root(&self, header: &BlockHeader) -> Hash {
		(self.pmmr_root, self.bitmap_root).hash_with_index(header.output_mmr_size)
	}
}

/// Minimal struct representing a known MMR position and associated block height.
#[derive(Debug)]
pub struct CommitPos {
	/// MMR position
	pub pos: u64,
	/// Block height
	pub height: u64,
}

impl Readable for CommitPos {
	fn read(reader: &mut dyn Reader) -> Result<CommitPos, ser::Error> {
		let pos = reader.read_u64()?;
		let height = reader.read_u64()?;
		Ok(CommitPos { pos, height })
	}
}

impl Writeable for CommitPos {
	fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		writer.write_u64(self.pos)?;
		writer.write_u64(self.height)?;
		Ok(())
	}
}

/// The tip of a fork. A handle to the fork ancestry from its leaf in the
/// blockchain tree. References the max height and the latest and previous
/// blocks
/// for convenience and the total difficulty.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Tip {
	/// Height of the tip (max height of the fork)
	pub height: u64,
	/// Last block pushed to the fork
	pub last_block_h: Hash,
	/// Previous block
	pub prev_block_h: Hash,
	/// Total difficulty accumulated on that fork
	pub total_difficulty: Difficulty,
}

impl Tip {
	/// Creates a new tip based on provided header.
	pub fn from_header(header: &BlockHeader) -> Tip {
		Tip {
			height: header.height,
			last_block_h: header.hash(),
			prev_block_h: header.prev_hash,
			total_difficulty: header.total_difficulty(),
		}
	}
}

impl Hashed for Tip {
	/// The hash of the underlying block.
	fn hash(&self) -> Hash {
		self.last_block_h
	}
}

impl Default for Tip {
	fn default() -> Self {
		Tip {
			height: 0,
			last_block_h: ZERO_HASH,
			prev_block_h: ZERO_HASH,
			total_difficulty: Difficulty::min(),
		}
	}
}

/// Serialization of a tip, required to save to datastore.
impl ser::Writeable for Tip {
	fn write<W: ser::Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
		writer.write_u64(self.height)?;
		writer.write_fixed_bytes(&self.last_block_h)?;
		writer.write_fixed_bytes(&self.prev_block_h)?;
		self.total_difficulty.write(writer)
	}
}

impl ser::Readable for Tip {
	fn read(reader: &mut dyn ser::Reader) -> Result<Tip, ser::Error> {
		let height = reader.read_u64()?;
		let last = Hash::read(reader)?;
		let prev = Hash::read(reader)?;
		let diff = Difficulty::read(reader)?;
		Ok(Tip {
			height: height,
			last_block_h: last,
			prev_block_h: prev,
			total_difficulty: diff,
		})
	}
}

/// Bridge between the chain pipeline and the rest of the system. Handles
/// downstream processing of valid blocks by the rest of the system, most
/// importantly the broadcasting of blocks to our peers.
pub trait ChainAdapter {
	/// The blockchain pipeline has accepted this block as valid and added
	/// it to our chain.
	fn block_accepted(&self, block: &Block, status: BlockStatus, opts: Options);
}

/// Inform the caller of the current status of a txhashset write operation,
/// as it can take quite a while to process. Each function is called in the
/// order defined below and can be used to provide some feedback to the
/// caller. Functions taking arguments can be called repeatedly to update
/// those values as the processing progresses.
pub trait TxHashsetWriteStatus {
	/// First setup of the txhashset
	fn on_setup(&self);
	/// Starting kernel validation
	fn on_validation_kernels(&self, kernels: u64, kernel_total: u64);
	/// Starting rproof validation
	fn on_validation_rproofs(&self, rproofs: u64, rproof_total: u64);
	/// Starting to save the txhashset and related data
	fn on_save(&self);
	/// Done writing a new txhashset
	fn on_done(&self);
}

/// Do-nothing implementation of TxHashsetWriteStatus
pub struct NoStatus;

impl TxHashsetWriteStatus for NoStatus {
	fn on_setup(&self) {}
	fn on_validation_kernels(&self, _ks: u64, _kts: u64) {}
	fn on_validation_rproofs(&self, _rs: u64, _rt: u64) {}
	fn on_save(&self) {}
	fn on_done(&self) {}
}

/// Dummy adapter used as a placeholder for real implementations
pub struct NoopAdapter {}

impl ChainAdapter for NoopAdapter {
	fn block_accepted(&self, _b: &Block, _status: BlockStatus, _opts: Options) {}
}

/// Status of an accepted block.
#[derive(Debug, Clone, PartialEq)]
pub enum BlockStatus {
	/// Block is the "next" block, updating the chain head.
	Next,
	/// Block does not update the chain head and is a fork.
	Fork,
	/// Block updates the chain head via a (potentially disruptive) "reorg".
	/// Previous block was not our previous chain head.
	Reorg(u64),
}
<|endoftext|>


<commit_before>pub trait Summarizable {
    fn summary(&self) -> String;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Add struct NewsArticle and implement Summarizable trait for it<commit_after>pub trait Summarizable {
    fn summary(&self) -> String;
}

pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summarizable for NewsArticle {
    fn summary(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>use common::util::*;

static UTIL_NAME: &'static str = "cat";

#[test]
fn test_output_multi_files_print_all_chars() {
    let (_, mut ucmd) = testing(UTIL_NAME);
    ucmd.arg("alpha.txt")
        .arg("256.txt")
        .arg("-A")
        .arg("-n")
        .succeeds()
        .stdout_only("     1\tabcde$\n     2\tfghij$\n     3\tklmno$\n     4\tpqrst$\n     \
                5\tuvwxyz$\n     6\t^@^A^B^C^D^E^F^G^H^I$\n     \
                7\t^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\\^]^^^_ \
                !\"#$%&\'()*+,-./0123456789:;\
                <=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?M-^@M-^AM-^\
                BM-^CM-^DM-^EM-^FM-^GM-^HM-^IM-^JM-^KM-^LM-^MM-^NM-^OM-^PM-^QM-^RM-^SM-^TM-^UM-^V\
                M-^WM-^XM-^YM-^ZM-^[M-^\\M-^]M-^^M-^_M- \
                M-!M-\"M-#M-$M-%M-&M-\'M-(M-)M-*M-+M-,M--M-.M-/M-0M-1M-2M-3M-4M-5M-6M-7M-8M-9M-:\
                M-;M-<M-=M->M-?M-@M-AM-BM-CM-DM-EM-FM-GM-HM-IM-JM-KM-LM-MM-NM-OM-PM-QM-RM-SM-TM-U\
                M-VM-WM-XM-YM-ZM-[M-\\M-]M-^M-_M-`M-aM-bM-cM-dM-eM-fM-gM-hM-iM-jM-kM-lM-mM-nM-oM-\
                pM-qM-rM-sM-tM-uM-vM-wM-xM-yM-zM-{M-|M-}M-~M-^?");
}

#[test]
fn test_stdin_show_nonprinting() {
    for same_param in vec!["-v", "--show-nonprinting"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&vec![same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("\t^@");
    }
}

#[test]
fn test_stdin_show_tabs() {
    for same_param in vec!["-T", "--show-tabs"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&vec![same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("^I\0");
    }
}

#[test]
fn test_stdin_show_ends() {
    for same_param in vec!["-E", "--show-ends"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&vec![same_param,"-"])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("\t\0$");
    }
}

#[test]
fn test_stdin_show_all() {
    for same_param in vec!["-A", "--show-all"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&vec![same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("^I^@$");
    }
}

#[test]
fn test_stdin_nonprinting_and_endofline() {
    let (_, mut ucmd) = testing(UTIL_NAME);
    ucmd.args(&vec!["-e"])
        .pipe_in("\t\0\n")
        .succeeds()
        .stdout_only("\t^@$\n");
}

#[test]
fn test_stdin_nonprinting_and_tabs() {
    let (_, mut ucmd) = testing(UTIL_NAME);
    ucmd.args(&vec!["-t"])
        .pipe_in("\t\0\n")
        .succeeds()
        .stdout_only("^I^@\n");
}

#[test]
fn test_stdin_squeeze_blank() {
    for same_param in vec!["-s", "--squeeze-blank"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.arg(same_param)
            .pipe_in("\n\na\n\n\n\n\nb\n\n\n".as_bytes())
            .succeeds()
            .stdout_only("\na\n\nb\n\n");
    }
}

#[test]
fn test_stdin_number_non_blank() {
    for same_param in vec!["-b", "--number-nonblank"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.arg(same_param)
            .arg("-")
            .pipe_in("\na\nb\n\n\nc".as_bytes())
            .succeeds()
            .stdout_only("\n     1\ta\n     2\tb\n\n\n     3\tc");
    }
}

#[test]
fn test_non_blank_overrides_number() {
    for same_param in vec!["-b", "--number-nonblank"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&vec![same_param, "-"])
            .pipe_in("\na\nb\n\n\nc".as_bytes())
            .succeeds()
            .stdout_only("\n     1\ta\n     2\tb\n\n\n     3\tc");
    }
}

#[test]
fn test_squeeze_blank_before_numbering() {
    for same_param in vec!["-s", "--squeeze-blank"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&vec![same_param, "-n", "-"])
            .pipe_in("a\n\n\nb")
            .succeeds()
            .stdout_only("     1\ta\n     2\t\n     3\tb");
    }
}
<commit_msg>tests: cat minor refactor for dryness<commit_after>use common::util::*;

static UTIL_NAME: &'static str = "cat";

#[test]
fn test_output_multi_files_print_all_chars() {
    let (_, mut ucmd) = testing(UTIL_NAME);
    ucmd.args(&["alpha.txt", "256.txt", "-A", "-n"])
        .succeeds()
        .stdout_only("     1\tabcde$\n     2\tfghij$\n     3\tklmno$\n     4\tpqrst$\n     \
                5\tuvwxyz$\n     6\t^@^A^B^C^D^E^F^G^H^I$\n     \
                7\t^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\\^]^^^_ \
                !\"#$%&\'()*+,-./0123456789:;\
                <=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?M-^@M-^AM-^\
                BM-^CM-^DM-^EM-^FM-^GM-^HM-^IM-^JM-^KM-^LM-^MM-^NM-^OM-^PM-^QM-^RM-^SM-^TM-^UM-^V\
                M-^WM-^XM-^YM-^ZM-^[M-^\\M-^]M-^^M-^_M- \
                M-!M-\"M-#M-$M-%M-&M-\'M-(M-)M-*M-+M-,M--M-.M-/M-0M-1M-2M-3M-4M-5M-6M-7M-8M-9M-:\
                M-;M-<M-=M->M-?M-@M-AM-BM-CM-DM-EM-FM-GM-HM-IM-JM-KM-LM-MM-NM-OM-PM-QM-RM-SM-TM-U\
                M-VM-WM-XM-YM-ZM-[M-\\M-]M-^M-_M-`M-aM-bM-cM-dM-eM-fM-gM-hM-iM-jM-kM-lM-mM-nM-oM-\
                pM-qM-rM-sM-tM-uM-vM-wM-xM-yM-zM-{M-|M-}M-~M-^?");
}

#[test]
fn test_stdin_show_nonprinting() {
    for same_param in vec!["-v", "--show-nonprinting"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&vec![same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("\t^@");
    }
}

#[test]
fn test_stdin_show_tabs() {
    for same_param in vec!["-T", "--show-tabs"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&[same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("^I\0");
    }
}

#[test]
fn test_stdin_show_ends() {
    for same_param in vec!["-E", "--show-ends"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&[same_param,"-"])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("\t\0$");
    }
}

#[test]
fn test_stdin_show_all() {
    for same_param in vec!["-A", "--show-all"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&[same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("^I^@$");
    }
}

#[test]
fn test_stdin_nonprinting_and_endofline() {
    let (_, mut ucmd) = testing(UTIL_NAME);
    ucmd.args(&["-e"])
        .pipe_in("\t\0\n")
        .succeeds()
        .stdout_only("\t^@$\n");
}

#[test]
fn test_stdin_nonprinting_and_tabs() {
    let (_, mut ucmd) = testing(UTIL_NAME);
    ucmd.args(&["-t"])
        .pipe_in("\t\0\n")
        .succeeds()
        .stdout_only("^I^@\n");
}

#[test]
fn test_stdin_squeeze_blank() {
    for same_param in vec!["-s", "--squeeze-blank"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.arg(same_param)
            .pipe_in("\n\na\n\n\n\n\nb\n\n\n")
            .succeeds()
            .stdout_only("\na\n\nb\n\n");
    }
}

#[test]
fn test_stdin_number_non_blank() {
    for same_param in vec!["-b", "--number-nonblank"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.arg(same_param)
            .arg("-")
            .pipe_in("\na\nb\n\n\nc")
            .succeeds()
            .stdout_only("\n     1\ta\n     2\tb\n\n\n     3\tc");
    }
}

#[test]
fn test_non_blank_overrides_number() {
    for same_param in vec!["-b", "--number-nonblank"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&[same_param, "-"])
            .pipe_in("\na\nb\n\n\nc")
            .succeeds()
            .stdout_only("\n     1\ta\n     2\tb\n\n\n     3\tc");
    }
}

#[test]
fn test_squeeze_blank_before_numbering() {
    for same_param in vec!["-s", "--squeeze-blank"] {
        let (_, mut ucmd) = testing(UTIL_NAME);
        ucmd.args(&[same_param, "-n", "-"])
            .pipe_in("a\n\n\nb")
            .succeeds()
            .stdout_only("     1\ta\n     2\t\n     3\tb");
    }
}
<|endoftext|>


<commit_before>use expression::Expression;
use super::{UpdateTarget, IncompleteUpdateStatement, IncompleteInsertStatement, SelectStatement};
use super::delete_statement::DeleteStatement;

/// Creates an update statement. Helpers for updating a single row can be
/// generated by
/// [`#[changeset_for]`](https://github.com/sgrif/diesel/tree/master/diesel_codegen#changeset_fortable_name).
///
/// # Example
///
/// # Examples
///
/// ### Deleting a single record:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # #[cfg(feature = "postgres")]
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// let updated_row = diesel::update(users.filter(id.eq(1)))
///     .set(name.eq("James"))
///     .get_result(&connection);
/// // On backends that support it, you can call `get_result` instead of `execute`
/// // to have `RETURNING *` automatically appended to the query.
/// assert_eq!(Ok((1, "James".to_string())), updated_row);
/// # }
/// # #[cfg(not(feature = "postgres"))]
/// # fn main() {}
/// ```
pub fn update<T: UpdateTarget>(source: T) -> IncompleteUpdateStatement<T> {
    IncompleteUpdateStatement::new(source)
}

/// Creates a delete statement. Will delete the records in the given set.
/// Because this function has a very generic name, it is not exported by
/// default.
///
/// # Examples
///
/// ### Deleting a single record:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     delete();
/// # }
/// #
/// # fn delete() -> QueryResult<()> {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection);
/// let old_count = get_count();
/// try!(diesel::delete(users.filter(id.eq(1))).execute(&connection));
/// assert_eq!(old_count.map(|count| count - 1), get_count());
/// # Ok(())
/// # }
/// ```
///
/// ### Deleting a whole table:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     delete();
/// # }
/// #
/// # fn delete() -> QueryResult<()> {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection);
/// try!(diesel::delete(users).execute(&connection));
/// assert_eq!(Ok(0), get_count());
/// # Ok(())
/// # }
/// ```
pub fn delete<T: UpdateTarget>(source: T) -> DeleteStatement<T> {
    DeleteStatement::new(source)
}

/// Creates an insert statement. Will add the given data to a table. This
/// function is not exported by default. As with other commands, the resulting
/// query can return the inserted rows if you choose.
pub fn insert<T>(records: T) -> IncompleteInsertStatement<T> {
    IncompleteInsertStatement::new(records)
}

/// Creates a bare select statement, with no from clause. Primarily used for
/// testing diesel itself, but likely useful for third party crates as well. The
/// given expressions must be selectable from anywhere.
pub fn select<T>(expression: T) -> SelectStatement<T::SqlType, T, ()> where
    T: Expression,
{
    SelectStatement::simple(expression, ())
}
<commit_msg>documentation fix of function diesel::update<commit_after>use expression::Expression;
use super::{UpdateTarget, IncompleteUpdateStatement, IncompleteInsertStatement, SelectStatement};
use super::delete_statement::DeleteStatement;

/// Creates an update statement. Helpers for updating a single row can be
/// generated by
/// [`#[changeset_for]`](https://github.com/sgrif/diesel/tree/master/diesel_codegen#changeset_fortable_name).
///
/// # Examples
///
/// ### Updating a single record:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # #[cfg(feature = "postgres")]
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// let updated_row = diesel::update(users.filter(id.eq(1)))
///     .set(name.eq("James"))
///     .get_result(&connection);
/// // On backends that support it, you can call `get_result` instead of `execute`
/// // to have `RETURNING *` automatically appended to the query.
/// assert_eq!(Ok((1, "James".to_string())), updated_row);
/// # }
/// # #[cfg(not(feature = "postgres"))]
/// # fn main() {}
/// ```
pub fn update<T: UpdateTarget>(source: T) -> IncompleteUpdateStatement<T> {
    IncompleteUpdateStatement::new(source)
}

/// Creates a delete statement. Will delete the records in the given set.
/// Because this function has a very generic name, it is not exported by
/// default.
///
/// # Examples
///
/// ### Deleting a single record:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     delete();
/// # }
/// #
/// # fn delete() -> QueryResult<()> {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection);
/// let old_count = get_count();
/// try!(diesel::delete(users.filter(id.eq(1))).execute(&connection));
/// assert_eq!(old_count.map(|count| count - 1), get_count());
/// # Ok(())
/// # }
/// ```
///
/// ### Deleting a whole table:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     delete();
/// # }
/// #
/// # fn delete() -> QueryResult<()> {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection);
/// try!(diesel::delete(users).execute(&connection));
/// assert_eq!(Ok(0), get_count());
/// # Ok(())
/// # }
/// ```
pub fn delete<T: UpdateTarget>(source: T) -> DeleteStatement<T> {
    DeleteStatement::new(source)
}

/// Creates an insert statement. Will add the given data to a table. This
/// function is not exported by default. As with other commands, the resulting
/// query can return the inserted rows if you choose.
pub fn insert<T>(records: T) -> IncompleteInsertStatement<T> {
    IncompleteInsertStatement::new(records)
}

/// Creates a bare select statement, with no from clause. Primarily used for
/// testing diesel itself, but likely useful for third party crates as well. The
/// given expressions must be selectable from anywhere.
pub fn select<T>(expression: T) -> SelectStatement<T::SqlType, T, ()> where
    T: Expression,
{
    SelectStatement::simple(expression, ())
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser;
use media_queries::CSSErrorReporterTest;
use selectors::parser::*;
use std::borrow::ToOwned;
use std::sync::Arc;
use string_cache::Atom;
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands};
use style::stylesheets::{CSSRule, StyleRule, Origin, Stylesheet};

#[test]
fn test_parse_stylesheet() {
    let css = r"
        @namespace url(http://www.w3.org/1999/xhtml);
        /* FIXME: only if scripting is enabled */
        input[type=hidden i] { display: none !important; }
        html , body /**/ { display: block; }
        #d1 > .ok { background: blue; }
    ";
    let url = url!("about::test");
    let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent,
                                          Box::new(CSSErrorReporterTest));
    assert_eq!(stylesheet, Stylesheet {
        origin: Origin::UserAgent,
        media: None,
        rules: vec![
            CSSRule::Namespace(None, ns!(html)),
            CSSRule::Style(StyleRule {
                selectors: vec![
                    Selector {
                        compound_selectors: Arc::new(CompoundSelector {
                            simple_selectors: vec![
                                SimpleSelector::Namespace(ns!(html)),
                                SimpleSelector::LocalName(LocalName {
                                    name: atom!("input"),
                                    lower_name: atom!("input"),
                                }),
                                SimpleSelector::AttrEqual(AttrSelector {
                                    name: atom!("type"),
                                    lower_name: atom!("type"),
                                    namespace: NamespaceConstraint::Specific(ns!()),
                                }, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
                            ],
                            next: None,
                        }),
                        pseudo_element: None,
                        specificity: (0 << 20) + (1 << 10) + (1 << 0),
                    },
                ],
                declarations: PropertyDeclarationBlock {
                    normal: Arc::new(vec![]),
                    important: Arc::new(vec![
                        PropertyDeclaration::Display(DeclaredValue::Value(
                            longhands::display::SpecifiedValue::none)),
                    ]),
                },
            }),
            CSSRule::Style(StyleRule {
                selectors: vec![
                    Selector {
                        compound_selectors: Arc::new(CompoundSelector {
                            simple_selectors: vec![
                                SimpleSelector::Namespace(ns!(html)),
                                SimpleSelector::LocalName(LocalName {
                                    name: atom!("html"),
                                    lower_name: atom!("html"),
                                }),
                            ],
                            next: None,
                        }),
                        pseudo_element: None,
                        specificity: (0 << 20) + (0 << 10) + (1 << 0),
                    },
                    Selector {
                        compound_selectors: Arc::new(CompoundSelector {
                            simple_selectors: vec![
                                SimpleSelector::Namespace(ns!(html)),
                                SimpleSelector::LocalName(LocalName {
                                    name: atom!("body"),
                                    lower_name: atom!("body"),
                                }),
                            ],
                            next: None,
                        }),
                        pseudo_element: None,
                        specificity: (0 << 20) + (0 << 10) + (1 << 0),
                    },
                ],
                declarations: PropertyDeclarationBlock {
                    normal: Arc::new(vec![
                        PropertyDeclaration::Display(DeclaredValue::Value(
                            longhands::display::SpecifiedValue::block)),
                    ]),
                    important: Arc::new(vec![]),
                },
            }),
            CSSRule::Style(StyleRule {
                selectors: vec![
                    Selector {
                        compound_selectors: Arc::new(CompoundSelector {
                            simple_selectors: vec![
                                SimpleSelector::Class(Atom::from("ok")),
                            ],
                            next: Some((Arc::new(CompoundSelector {
                                simple_selectors: vec![
                                    SimpleSelector::ID(Atom::from("d1")),
                                ],
                                next: None,
                            }), Combinator::Child)),
                        }),
                        pseudo_element: None,
                        specificity: (1 << 20) + (1 << 10) + (0 << 0),
                    },
                ],
                declarations: PropertyDeclarationBlock {
                    normal: Arc::new(vec![
                        PropertyDeclaration::BackgroundClip(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundOrigin(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundSize(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundColor(DeclaredValue::Value(
                            longhands::background_color::SpecifiedValue {
                                authored: Some("blue".to_owned()),
                                parsed: cssparser::Color::RGBA(cssparser::RGBA {
                                    red: 0., green: 0., blue: 1., alpha: 1.
                                }),
                            }
                        )),
                    ]),
                    important: Arc::new(vec![]),
                },
            }),
        ],
    });
}
<commit_msg>Auto merge of #9028 - iszak:issue-8842, r=SimonSapin<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::{self, Parser, SourcePosition};
use media_queries::CSSErrorReporterTest;
use selectors::parser::*;
use std::borrow::ToOwned;
use std::sync::Arc;
use std::sync::Mutex;
use string_cache::Atom;
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands};
use style::stylesheets::{CSSRule, StyleRule, Origin, Stylesheet};
use style::error_reporting::ParseErrorReporter;

#[test]
fn test_parse_stylesheet() {
    let css = r"
        @namespace url(http://www.w3.org/1999/xhtml);
        /* FIXME: only if scripting is enabled */
        input[type=hidden i] { display: none !important; }
        html , body /**/ { display: block; }
        #d1 > .ok { background: blue; }
    ";
    let url = url!("about::test");
    let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent,
                                          Box::new(CSSErrorReporterTest));
    assert_eq!(stylesheet, Stylesheet {
        origin: Origin::UserAgent,
        media: None,
        rules: vec![
            CSSRule::Namespace(None, ns!(html)),
            CSSRule::Style(StyleRule {
                selectors: vec![
                    Selector {
                        compound_selectors: Arc::new(CompoundSelector {
                            simple_selectors: vec![
                                SimpleSelector::Namespace(ns!(html)),
                                SimpleSelector::LocalName(LocalName {
                                    name: atom!("input"),
                                    lower_name: atom!("input"),
                                }),
                                SimpleSelector::AttrEqual(AttrSelector {
                                    name: atom!("type"),
                                    lower_name: atom!("type"),
                                    namespace: NamespaceConstraint::Specific(ns!()),
                                }, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
                            ],
                            next: None,
                        }),
                        pseudo_element: None,
                        specificity: (0 << 20) + (1 << 10) + (1 << 0),
                    },
                ],
                declarations: PropertyDeclarationBlock {
                    normal: Arc::new(vec![]),
                    important: Arc::new(vec![
                        PropertyDeclaration::Display(DeclaredValue::Value(
                            longhands::display::SpecifiedValue::none)),
                    ]),
                },
            }),
            CSSRule::Style(StyleRule {
                selectors: vec![
                    Selector {
                        compound_selectors: Arc::new(CompoundSelector {
                            simple_selectors: vec![
                                SimpleSelector::Namespace(ns!(html)),
                                SimpleSelector::LocalName(LocalName {
                                    name: atom!("html"),
                                    lower_name: atom!("html"),
                                }),
                            ],
                            next: None,
                        }),
                        pseudo_element: None,
                        specificity: (0 << 20) + (0 << 10) + (1 << 0),
                    },
                    Selector {
                        compound_selectors: Arc::new(CompoundSelector {
                            simple_selectors: vec![
                                SimpleSelector::Namespace(ns!(html)),
                                SimpleSelector::LocalName(LocalName {
                                    name: atom!("body"),
                                    lower_name: atom!("body"),
                                }),
                            ],
                            next: None,
                        }),
                        pseudo_element: None,
                        specificity: (0 << 20) + (0 << 10) + (1 << 0),
                    },
                ],
                declarations: PropertyDeclarationBlock {
                    normal: Arc::new(vec![
                        PropertyDeclaration::Display(DeclaredValue::Value(
                            longhands::display::SpecifiedValue::block)),
                    ]),
                    important: Arc::new(vec![]),
                },
            }),
            CSSRule::Style(StyleRule {
                selectors: vec![
                    Selector {
                        compound_selectors: Arc::new(CompoundSelector {
                            simple_selectors: vec![
                                SimpleSelector::Class(Atom::from("ok")),
                            ],
                            next: Some((Arc::new(CompoundSelector {
                                simple_selectors: vec![
                                    SimpleSelector::ID(Atom::from("d1")),
                                ],
                                next: None,
                            }), Combinator::Child)),
                        }),
                        pseudo_element: None,
                        specificity: (1 << 20) + (1 << 10) + (0 << 0),
                    },
                ],
                declarations: PropertyDeclarationBlock {
                    normal: Arc::new(vec![
                        PropertyDeclaration::BackgroundClip(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundOrigin(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundSize(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial),
                        PropertyDeclaration::BackgroundColor(DeclaredValue::Value(
                            longhands::background_color::SpecifiedValue {
                                authored: Some("blue".to_owned()),
                                parsed: cssparser::Color::RGBA(cssparser::RGBA {
                                    red: 0., green: 0., blue: 1., alpha: 1.
                                }),
                            }
                        )),
                    ]),
                    important: Arc::new(vec![]),
                },
            }),
        ],
    });
}

struct CSSError {
    pub line: usize,
    pub column: usize,
    pub message: String
}

struct CSSInvalidErrorReporterTest {
    pub errors: Arc<Mutex<Vec<CSSError>>>
}

impl CSSInvalidErrorReporterTest {
    pub fn new() -> CSSInvalidErrorReporterTest {
        return CSSInvalidErrorReporterTest{
            errors: Arc::new(Mutex::new(Vec::new()))
        }
    }
}

impl ParseErrorReporter for CSSInvalidErrorReporterTest {
    fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str) {
        let location = input.source_location(position);

        let errors = self.errors.clone();
        let mut errors = errors.lock().unwrap();

        errors.push(
            CSSError{
                line: location.line,
                column: location.column,
                message: message.to_owned()
            }
        );
    }

    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
        return Box::new(
            CSSInvalidErrorReporterTest{
                errors: self.errors.clone()
            }
        );
    }
}

#[test]
fn test_report_error_stylesheet() {
    let css = r"
    div {
        background-color: red;
        display: invalid;
        invalid: true;
    }
    ";
    let url = url!("about::test");
    let error_reporter = Box::new(CSSInvalidErrorReporterTest::new());

    let errors = error_reporter.errors.clone();

    Stylesheet::from_str(css, url, Origin::UserAgent, error_reporter);

    let mut errors = errors.lock().unwrap();

    let error = errors.pop().unwrap();
    assert_eq!("Unsupported property declaration: 'invalid: true;'", error.message);
    assert_eq!(5, error.line);
    assert_eq!(9, error.column);

    let error = errors.pop().unwrap();
    assert_eq!("Unsupported property declaration: 'display: invalid;'", error.message);
    assert_eq!(4, error.line);
    assert_eq!(9, error.column);
}
<|endoftext|>


<commit_before>//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the
//! case of the source (e.g. `my-field`, `MY_FIELD`).
//!
//! Manually vendored from serde_derive/internals
//! <https://github.com/serde-rs/serde/blob/4eb580790dd6c96089b92942a5f481b21df4feaf/serde_derive/src/internals/case.rs>
#![allow(dead_code)]
#![allow(clippy::upper_case_acronyms)]

// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;

use std::str::FromStr;

use self::RenameRule::*;

/// The different possible ways to change case of fields in a struct, or variants in an enum.
#[derive(Copy, Clone, PartialEq)]
pub enum RenameRule {
    /// Don't apply a default rename rule.
    None,
    /// Rename direct children to "lowercase" style.
    LowerCase,
    /// Rename direct children to "UPPERCASE" style.
    UPPERCASE,
    /// Rename direct children to "PascalCase" style, as typically used for
    /// enum variants.
    PascalCase,
    /// Rename direct children to "camelCase" style.
    CamelCase,
    /// Rename direct children to "snake_case" style, as commonly used for
    /// fields.
    SnakeCase,
    /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly
    /// used for constants.
    ScreamingSnakeCase,
    /// Rename direct children to "kebab-case" style.
    KebabCase,
    /// Rename direct children to "SCREAMING-KEBAB-CASE" style.
    ScreamingKebabCase,
}

impl RenameRule {
    /// Apply a renaming rule to an enum variant, returning the version expected in the source.
    pub fn apply_to_variant(&self, variant: &str) -> String {
        match *self {
            None | PascalCase => variant.to_owned(),
            LowerCase => variant.to_ascii_lowercase(),
            UPPERCASE => variant.to_ascii_uppercase(),
            CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
            SnakeCase => {
                let mut snake = String::new();
                for (i, ch) in variant.char_indices() {
                    if i > 0 && ch.is_uppercase() {
                        snake.push('_');
                    }
                    snake.push(ch.to_ascii_lowercase());
                }
                snake
            }
            ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
            KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
            ScreamingKebabCase => ScreamingSnakeCase
                .apply_to_variant(variant)
                .replace('_', "-"),
        }
    }

    /// Apply a renaming rule to a struct field, returning the version expected in the source.
    pub fn apply_to_field(&self, field: &str) -> String {
        match *self {
            None | LowerCase | SnakeCase => field.to_owned(),
            UPPERCASE => field.to_ascii_uppercase(),
            PascalCase => {
                let mut pascal = String::new();
                let mut capitalize = true;
                for ch in field.chars() {
                    if ch == '_' {
                        capitalize = true;
                    } else if capitalize {
                        pascal.push(ch.to_ascii_uppercase());
                        capitalize = false;
                    } else {
                        pascal.push(ch);
                    }
                }
                pascal
            }
            CamelCase => {
                let pascal = PascalCase.apply_to_field(field);
                pascal[..1].to_ascii_lowercase() + &pascal[1..]
            }
            ScreamingSnakeCase => field.to_ascii_uppercase(),
            KebabCase => field.replace('_', "-"),
            ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
        }
    }
}

impl FromStr for RenameRule {
    type Err = ();

    fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
        match rename_all_str {
            "lowercase" => Ok(LowerCase),
            "UPPERCASE" => Ok(UPPERCASE),
            "PascalCase" => Ok(PascalCase),
            "camelCase" => Ok(CamelCase),
            "snake_case" => Ok(SnakeCase),
            "SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
            "kebab-case" => Ok(KebabCase),
            "SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
            _ => Err(()),
        }
    }
}

#[test]
fn rename_variants() {
    for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
        (
            "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
        ),
        (
            "VeryTasty",
            "verytasty",
            "VERYTASTY",
            "veryTasty",
            "very_tasty",
            "VERY_TASTY",
            "very-tasty",
            "VERY-TASTY",
        ),
        ("A", "a", "A", "a", "a", "A", "a", "A"),
        ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
    ] {
        assert_eq!(None.apply_to_variant(original), original);
        assert_eq!(LowerCase.apply_to_variant(original), lower);
        assert_eq!(UPPERCASE.apply_to_variant(original), upper);
        assert_eq!(PascalCase.apply_to_variant(original), original);
        assert_eq!(CamelCase.apply_to_variant(original), camel);
        assert_eq!(SnakeCase.apply_to_variant(original), snake);
        assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
        assert_eq!(KebabCase.apply_to_variant(original), kebab);
        assert_eq!(
            ScreamingKebabCase.apply_to_variant(original),
            screaming_kebab
        );
    }
}

#[test]
fn rename_fields() {
    for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
        (
            "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
        ),
        (
            "very_tasty",
            "VERY_TASTY",
            "VeryTasty",
            "veryTasty",
            "VERY_TASTY",
            "very-tasty",
            "VERY-TASTY",
        ),
        ("a", "A", "A", "a", "A", "a", "A"),
        ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
    ] {
        assert_eq!(None.apply_to_field(original), original);
        assert_eq!(UPPERCASE.apply_to_field(original), upper);
        assert_eq!(PascalCase.apply_to_field(original), pascal);
        assert_eq!(CamelCase.apply_to_field(original), camel);
        assert_eq!(SnakeCase.apply_to_field(original), original);
        assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
        assert_eq!(KebabCase.apply_to_field(original), kebab);
        assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
    }
}
<commit_msg>shared: Fix to_uppercase use in serde_case<commit_after>//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the
//! case of the source (e.g. `my-field`, `MY_FIELD`).
//!
//! Manually vendored from serde_derive/internals
//! <https://github.com/serde-rs/serde/blob/4eb580790dd6c96089b92942a5f481b21df4feaf/serde_derive/src/internals/case.rs>
#![allow(dead_code)]
#![allow(clippy::upper_case_acronyms)]

// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;

use std::str::FromStr;

use self::RenameRule::*;

/// The different possible ways to change case of fields in a struct, or variants in an enum.
#[derive(Copy, Clone, PartialEq)]
pub enum RenameRule {
    /// Don't apply a default rename rule.
    None,
    /// Rename direct children to "lowercase" style.
    LowerCase,
    /// Rename direct children to "UPPERCASE" style.
    UPPERCASE,
    /// Rename direct children to "PascalCase" style, as typically used for
    /// enum variants.
    PascalCase,
    /// Rename direct children to "camelCase" style.
    CamelCase,
    /// Rename direct children to "snake_case" style, as commonly used for
    /// fields.
    SnakeCase,
    /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly
    /// used for constants.
    ScreamingSnakeCase,
    /// Rename direct children to "kebab-case" style.
    KebabCase,
    /// Rename direct children to "SCREAMING-KEBAB-CASE" style.
    ScreamingKebabCase,
}

impl RenameRule {
    /// Apply a renaming rule to an enum variant, returning the version expected in the source.
    pub fn apply_to_variant(&self, variant: &str) -> String {
        match *self {
            None | PascalCase => variant.to_owned(),
            LowerCase => variant.to_ascii_lowercase(),
            UPPERCASE => variant.to_ascii_uppercase(),
            CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
            SnakeCase => {
                let mut snake = String::new();
                for (i, ch) in variant.char_indices() {
                    if i > 0 && ch.is_ascii_uppercase() {
                        snake.push('_');
                    }
                    snake.push(ch.to_ascii_lowercase());
                }
                snake
            }
            ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
            KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
            ScreamingKebabCase => ScreamingSnakeCase
                .apply_to_variant(variant)
                .replace('_', "-"),
        }
    }

    /// Apply a renaming rule to a struct field, returning the version expected in the source.
    pub fn apply_to_field(&self, field: &str) -> String {
        match *self {
            None | LowerCase | SnakeCase => field.to_owned(),
            UPPERCASE => field.to_ascii_uppercase(),
            PascalCase => {
                let mut pascal = String::new();
                let mut capitalize = true;
                for ch in field.chars() {
                    if ch == '_' {
                        capitalize = true;
                    } else if capitalize {
                        pascal.push(ch.to_ascii_uppercase());
                        capitalize = false;
                    } else {
                        pascal.push(ch);
                    }
                }
                pascal
            }
            CamelCase => {
                let pascal = PascalCase.apply_to_field(field);
                pascal[..1].to_ascii_lowercase() + &pascal[1..]
            }
            ScreamingSnakeCase => field.to_ascii_uppercase(),
            KebabCase => field.replace('_', "-"),
            ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
        }
    }
}

impl FromStr for RenameRule {
    type Err = ();

    fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
        match rename_all_str {
            "lowercase" => Ok(LowerCase),
            "UPPERCASE" => Ok(UPPERCASE),
            "PascalCase" => Ok(PascalCase),
            "camelCase" => Ok(CamelCase),
            "snake_case" => Ok(SnakeCase),
            "SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
            "kebab-case" => Ok(KebabCase),
            "SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
            _ => Err(()),
        }
    }
}

#[test]
fn rename_variants() {
    for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
        (
            "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
        ),
        (
            "VeryTasty",
            "verytasty",
            "VERYTASTY",
            "veryTasty",
            "very_tasty",
            "VERY_TASTY",
            "very-tasty",
            "VERY-TASTY",
        ),
        ("A", "a", "A", "a", "a", "A", "a", "A"),
        ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
    ] {
        assert_eq!(None.apply_to_variant(original), original);
        assert_eq!(LowerCase.apply_to_variant(original), lower);
        assert_eq!(UPPERCASE.apply_to_variant(original), upper);
        assert_eq!(PascalCase.apply_to_variant(original), original);
        assert_eq!(CamelCase.apply_to_variant(original), camel);
        assert_eq!(SnakeCase.apply_to_variant(original), snake);
        assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
        assert_eq!(KebabCase.apply_to_variant(original), kebab);
        assert_eq!(
            ScreamingKebabCase.apply_to_variant(original),
            screaming_kebab
        );
    }
}

#[test]
fn rename_fields() {
    for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
        (
            "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
        ),
        (
            "very_tasty",
            "VERY_TASTY",
            "VeryTasty",
            "veryTasty",
            "VERY_TASTY",
            "very-tasty",
            "VERY-TASTY",
        ),
        ("a", "A", "A", "a", "A", "a", "A"),
        ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
    ] {
        assert_eq!(None.apply_to_field(original), original);
        assert_eq!(UPPERCASE.apply_to_field(original), upper);
        assert_eq!(PascalCase.apply_to_field(original), pascal);
        assert_eq!(CamelCase.apply_to_field(original), camel);
        assert_eq!(SnakeCase.apply_to_field(original), original);
        assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
        assert_eq!(KebabCase.apply_to_field(original), kebab);
        assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
    }
}
<|endoftext|>


<commit_before>extern crate ratel;

pub use ratel::*;
pub use ratel::grammar::*;
pub use ratel::tokenizer::*;
pub use ratel::lexicon::Token;
pub use ratel::lexicon::ReservedKind;
pub use ratel::lexicon::Token::*;
pub use ratel::owned_slice::OwnedSlice;

fn test_token(input: &str, expected: Token) -> bool {
    let mut tokenizer = Tokenizer::new(&input);
    let tok = tokenizer.get_token().unwrap();
    if tok != expected {
        println!("\n{:?}\n", tok);
    }
    tok == expected
}

macro_rules! assert_token {
    ($string:expr, $token:expr, $descr:expr) => {
        assert_eq!(test_token($string, $token), true, $descr);
    }
}

#[test]
fn test_tokenizer_chars() {
    assert_token!(";", Token::Semicolon, "read a Token::Semicolon");
    assert_token!(":", Token::Colon, "read a Token::Colon");
    assert_token!(",", Token::Comma, "read a Token::Comma");
    assert_token!("(", Token::ParenOpen, "read a Token::ParenOpen");
    assert_token!(")", Token::ParenClose, "read a Token::ParenClose");
    assert_token!("[", Token::BracketOpen, "read a Token::BracketOpen");
    assert_token!("]", Token::BracketClose, "read a Token::BracketClose");
    assert_token!("{", Token::BraceOpen, "read a Token::BraceOpen");
    assert_token!("}", Token::BraceClose, "read a Token::BraceClose");
}

#[test]
fn test_tokenizer_control_statements() {
    assert_token!("break", Token::Break, "read a Token::Break");
    assert_token!("do", Token::Do, "read a Token::Do");
    assert_token!("case", Token::Case, "read a Token::Case");
    assert_token!("else", Token::Else, "read a Token::Else");
    assert_token!("catch", Token::Catch, "read a Token::Catch");
    assert_token!("export", Token::Export, "read a Token::Export");
    assert_token!("class", Token::Class, "read a Token::Class");
    assert_token!("extends", Token::Extends, "read a Token::Extends");
    assert_token!("return", Token::Return, "read a Token::Return");
    assert_token!("while", Token::While, "read a Token::While");
    assert_token!("finally", Token::Finally, "read a Token::Finally");
    assert_token!("super", Token::Super, "read a Token::Super");
    assert_token!("with", Token::With, "read a Token::With");
    assert_token!("continue", Token::Continue, "read a Token::Continue");
    assert_token!("for", Token::For, "read a Token::For");
    assert_token!("switch", Token::Switch, "read a Token::Switch");
    assert_token!("yield", Token::Yield, "read a Token::Yield");
    assert_token!("debugger", Token::Debugger, "read a Token::Debugger");
    assert_token!("function", Token::Function, "read a Token::Function");
    assert_token!("this", Token::This, "read a Token::This");
    assert_token!("default", Token::Default, "read a Token::Default");
    assert_token!("if", Token::If, "read a Token::If");
    assert_token!("throw", Token::Throw, "read a Token::Throw");
    assert_token!("import", Token::Import, "read a Token::Import");
    assert_token!("try", Token::Try, "read a Token::Try");
}

#[test]
fn test_tokenizer_operators() {
    assert_token!("=>", Token::Operator(OperatorType::FatArrow), "OperatorType::FatArrow");
    assert_token!(".", Token::Operator(OperatorType::Accessor), "OperatorType::Accessor");
    assert_token!("new", Token::Operator(OperatorType::New), "OperatorType::New");
    assert_token!("++", Token::Operator(OperatorType::Increment), "OperatorType::Increment");
    assert_token!("--", Token::Operator(OperatorType::Decrement), "OperatorType::Decrement");
    assert_token!("!", Token::Operator(OperatorType::LogicalNot), "OperatorType::LogicalNot");
    assert_token!("~", Token::Operator(OperatorType::BitwiseNot), "OperatorType::BitwiseNot");
    assert_token!("typeof", Token::Operator(OperatorType::Typeof), "OperatorType::Typeof");
    assert_token!("void", Token::Operator(OperatorType::Void), "OperatorType::Void");
    assert_token!("delete", Token::Operator(OperatorType::Delete), "OperatorType::Delete");
    assert_token!("*", Token::Operator(OperatorType::Multiplication), "OperatorType::Multiplication");
    assert_token!("/", Token::Operator(OperatorType::Division), "OperatorType::Division");
    assert_token!("%", Token::Operator(OperatorType::Remainder), "OperatorType::Remainder");
    assert_token!("**", Token::Operator(OperatorType::Exponent), "OperatorType::Exponent");
    assert_token!("+", Token::Operator(OperatorType::Addition), "OperatorType::Addition");
    assert_token!("-", Token::Operator(OperatorType::Substraction), "OperatorType::Substraction");
    assert_token!("<<", Token::Operator(OperatorType::BitShiftLeft), "OperatorType::BitShiftLeft");
    assert_token!(">>", Token::Operator(OperatorType::BitShiftRight), "OperatorType::BitShiftRight");
    assert_token!(">>>", Token::Operator(OperatorType::UBitShiftRight), "OperatorType::UBitShiftRight");
    assert_token!("<", Token::Operator(OperatorType::Lesser), "OperatorType::Lesser");
    assert_token!("<=", Token::Operator(OperatorType::LesserEquals), "OperatorType::LesserEquals");
    assert_token!(">", Token::Operator(OperatorType::Greater), "OperatorType::Greater");
    assert_token!(">=", Token::Operator(OperatorType::GreaterEquals), "OperatorType::GreaterEquals");
    assert_token!("instanceof", Token::Operator(OperatorType::Instanceof), "OperatorType::Instanceof");
    assert_token!("in", Token::Operator(OperatorType::In), "OperatorType::In");
    assert_token!("===", Token::Operator(OperatorType::StrictEquality), "OperatorType::StrictEquality");
    assert_token!("!==", Token::Operator(OperatorType::StrictInequality), "OperatorType::StrictInequality");
    assert_token!("==", Token::Operator(OperatorType::Equality), "OperatorType::Equality");
    assert_token!("!=", Token::Operator(OperatorType::Inequality), "OperatorType::Inequality");
    assert_token!("&", Token::Operator(OperatorType::BitwiseAnd), "OperatorType::BitwiseAnd");
    assert_token!("^", Token::Operator(OperatorType::BitwiseXor), "OperatorType::BitwiseXor");
    assert_token!("|", Token::Operator(OperatorType::BitwiseOr), "OperatorType::BitwiseOr");
    assert_token!("&&", Token::Operator(OperatorType::LogicalAnd), "OperatorType::LogicalAnd");
    assert_token!("||", Token::Operator(OperatorType::LogicalOr), "OperatorType::LogicalOr");
    assert_token!("?", Token::Operator(OperatorType::Conditional), "OperatorType::Conditional");
    assert_token!("=", Token::Operator(OperatorType::Assign), "OperatorType::Assign");
    assert_token!("+=", Token::Operator(OperatorType::AddAssign), "OperatorType::AddAssign");
    assert_token!("-=", Token::Operator(OperatorType::SubstractAssign), "OperatorType::SubstractAssign");
    assert_token!("**=", Token::Operator(OperatorType::ExponentAssign), "OperatorType::ExponentAssign");
    assert_token!("*=", Token::Operator(OperatorType::MultiplyAssign), "OperatorType::MultiplyAssign");
    assert_token!("/=", Token::Operator(OperatorType::DivideAssign), "OperatorType::DivideAssign");
    assert_token!("%=", Token::Operator(OperatorType::RemainderAssign), "OperatorType::RemainderAssign");
    assert_token!("<<=", Token::Operator(OperatorType::BSLAssign), "OperatorType::BSLAssign");
    assert_token!(">>=", Token::Operator(OperatorType::BSRAssign), "OperatorType::BSRAssign");
    assert_token!(">>>=", Token::Operator(OperatorType::UBSRAssign), "OperatorType::UBSRAssign");
    assert_token!("&=", Token::Operator(OperatorType::BitAndAssign), "OperatorType::BitAndAssign");
    assert_token!("^=", Token::Operator(OperatorType::BitXorAssign), "OperatorType::BitXorAssign");
    assert_token!("|=", Token::Operator(OperatorType::BitOrAssign), "OperatorType::BitOrAssign");
    assert_token!("...", Token::Operator(OperatorType::Spread), "OperatorType::Spread");
}

#[test]
fn test_tokenizer_literals() {
    assert_token!("undefined", Token::Literal(Value::Undefined), "Token::Value::Undefined");
    assert_token!("null", Token::Literal(Value::Null), "Token::Value::Null");
    assert_token!("true", Token::Literal(Value::True), "Token::Value::True");
    assert_token!("false", Token::Literal(Value::False), "Token::Value::False");

    assert_token!("'foo'", Token::Literal(Value::String("'foo'".into())), "Token::Value::String");
    assert_token!("\"foo\"", Token::Literal(Value::String("\"foo\"".into())), "Token::Value::String");

    assert_token!("2.2", Token::Literal(Value::Number("2.2".into())), "Token::Value::Number");
    assert_token!("2", Token::Literal(Value::Number("2".into())), "Token::Value::Number");

    assert_token!("0xff", Token::Literal(Value::Integer(255)), "Token::Value::Integer");
    assert_token!("0XFF", Token::Literal(Value::Integer(255)), "Token::Value::Integer");
    assert_token!("0b01001011", Token::Literal(Value::Integer(75)), "Token::Value::Integer");
    assert_token!("0B01001011", Token::Literal(Value::Integer(75)), "Token::Value::Integer");
    assert_token!("0o113", Token::Literal(Value::Integer(75)), "Token::Value::Integer");
    assert_token!("0O113", Token::Literal(Value::Integer(75)), "Token::Value::Integer");
}

#[test]
fn test_tokenizer_reserved() {
    assert_token!("enum", Token::Reserved(ReservedKind::Enum), "ReservedKind::Enum");
    assert_token!("implements", Token::Reserved(ReservedKind::Implements), "ReservedKind::Implements");
    assert_token!("package", Token::Reserved(ReservedKind::Package), "ReservedKind::Package");
    assert_token!("protected", Token::Reserved(ReservedKind::Protected), "ReservedKind::Protected");
    assert_token!("interface", Token::Reserved(ReservedKind::Interface), "ReservedKind::Interface");
    assert_token!("private", Token::Reserved(ReservedKind::Private), "ReservedKind::Private");
    assert_token!("public", Token::Reserved(ReservedKind::Public), "ReservedKind::Public");
}

#[test]
fn test_tokenizer_whitespace() {
    assert_token!("", Token::EndOfProgram, "empty string");
    assert_token!("  ", Token::EndOfProgram, "whitespaces");
    assert_token!("\n\n\n  ", Token::EndOfProgram, "newlines");
    assert_token!("//Comment\n//Comment", Token::EndOfProgram, "single-line comment");
    assert_token!("/**\n  * Comment\n  */", Token::EndOfProgram, "multi-line comment");
}
<commit_msg>Simplify the tests a bit<commit_after>extern crate ratel;

pub use ratel::*;
pub use ratel::grammar::*;
pub use ratel::tokenizer::*;
pub use ratel::lexicon::Token;
pub use ratel::lexicon::Token::*;
pub use ratel::lexicon::ReservedKind;
pub use ratel::owned_slice::OwnedSlice;

fn test_token(input: &str, expected: Token) -> bool {
    let mut tokenizer = Tokenizer::new(&input);
    let tok = tokenizer.get_token().unwrap();
    if tok != expected {
        println!("\n{:?}\n", tok);
    }
    tok == expected
}

macro_rules! assert_token {
    ($string:expr, $token:expr, $descr:expr) => {
        assert_eq!(test_token($string, $token), true, $descr);
    }
}

#[test]
fn test_tokenizer_chars() {
    assert_token!(";", Semicolon, "read a Semicolon");
    assert_token!(":", Colon, "read a Colon");
    assert_token!(",", Comma, "read a Comma");
    assert_token!("(", ParenOpen, "read a ParenOpen");
    assert_token!(")", ParenClose, "read a ParenClose");
    assert_token!("[", BracketOpen, "read a BracketOpen");
    assert_token!("]", BracketClose, "read a BracketClose");
    assert_token!("{", BraceOpen, "read a BraceOpen");
    assert_token!("}", BraceClose, "read a BraceClose");
}

#[test]
fn test_tokenizer_control_statements() {
    assert_token!("break", Break, "read a Break");
    assert_token!("do", Do, "read a Do");
    assert_token!("case", Case, "read a Case");
    assert_token!("else", Else, "read a Else");
    assert_token!("catch", Catch, "read a Catch");
    assert_token!("export", Export, "read a Export");
    assert_token!("class", Class, "read a Class");
    assert_token!("extends", Extends, "read a Extends");
    assert_token!("return", Return, "read a Return");
    assert_token!("while", While, "read a While");
    assert_token!("finally", Finally, "read a Finally");
    assert_token!("super", Super, "read a Super");
    assert_token!("with", With, "read a With");
    assert_token!("continue", Continue, "read a Continue");
    assert_token!("for", For, "read a For");
    assert_token!("switch", Switch, "read a Switch");
    assert_token!("yield", Yield, "read a Yield");
    assert_token!("debugger", Debugger, "read a Debugger");
    assert_token!("function", Function, "read a Function");
    assert_token!("this", This, "read a This");
    assert_token!("default", Default, "read a Default");
    assert_token!("if", If, "read a If");
    assert_token!("throw", Throw, "read a Throw");
    assert_token!("import", Import, "read a Import");
    assert_token!("try", Try, "read a Try");
}

#[test]
fn test_tokenizer_operators() {
    assert_token!("=>", Operator(OperatorType::FatArrow), "OperatorType::FatArrow");
    assert_token!(".", Operator(OperatorType::Accessor), "OperatorType::Accessor");
    assert_token!("new", Operator(OperatorType::New), "OperatorType::New");
    assert_token!("++", Operator(OperatorType::Increment), "OperatorType::Increment");
    assert_token!("--", Operator(OperatorType::Decrement), "OperatorType::Decrement");
    assert_token!("!", Operator(OperatorType::LogicalNot), "OperatorType::LogicalNot");
    assert_token!("~", Operator(OperatorType::BitwiseNot), "OperatorType::BitwiseNot");
    assert_token!("typeof", Operator(OperatorType::Typeof), "OperatorType::Typeof");
    assert_token!("void", Operator(OperatorType::Void), "OperatorType::Void");
    assert_token!("delete", Operator(OperatorType::Delete), "OperatorType::Delete");
    assert_token!("*", Operator(OperatorType::Multiplication), "OperatorType::Multiplication");
    assert_token!("/", Operator(OperatorType::Division), "OperatorType::Division");
    assert_token!("%", Operator(OperatorType::Remainder), "OperatorType::Remainder");
    assert_token!("**", Operator(OperatorType::Exponent), "OperatorType::Exponent");
    assert_token!("+", Operator(OperatorType::Addition), "OperatorType::Addition");
    assert_token!("-", Operator(OperatorType::Substraction), "OperatorType::Substraction");
    assert_token!("<<", Operator(OperatorType::BitShiftLeft), "OperatorType::BitShiftLeft");
    assert_token!(">>", Operator(OperatorType::BitShiftRight), "OperatorType::BitShiftRight");
    assert_token!(">>>", Operator(OperatorType::UBitShiftRight), "OperatorType::UBitShiftRight");
    assert_token!("<", Operator(OperatorType::Lesser), "OperatorType::Lesser");
    assert_token!("<=", Operator(OperatorType::LesserEquals), "OperatorType::LesserEquals");
    assert_token!(">", Operator(OperatorType::Greater), "OperatorType::Greater");
    assert_token!(">=", Operator(OperatorType::GreaterEquals), "OperatorType::GreaterEquals");
    assert_token!("instanceof", Operator(OperatorType::Instanceof), "OperatorType::Instanceof");
    assert_token!("in", Operator(OperatorType::In), "OperatorType::In");
    assert_token!("===", Operator(OperatorType::StrictEquality), "OperatorType::StrictEquality");
    assert_token!("!==", Operator(OperatorType::StrictInequality), "OperatorType::StrictInequality");
    assert_token!("==", Operator(OperatorType::Equality), "OperatorType::Equality");
    assert_token!("!=", Operator(OperatorType::Inequality), "OperatorType::Inequality");
    assert_token!("&", Operator(OperatorType::BitwiseAnd), "OperatorType::BitwiseAnd");
    assert_token!("^", Operator(OperatorType::BitwiseXor), "OperatorType::BitwiseXor");
    assert_token!("|", Operator(OperatorType::BitwiseOr), "OperatorType::BitwiseOr");
    assert_token!("&&", Operator(OperatorType::LogicalAnd), "OperatorType::LogicalAnd");
    assert_token!("||", Operator(OperatorType::LogicalOr), "OperatorType::LogicalOr");
    assert_token!("?", Operator(OperatorType::Conditional), "OperatorType::Conditional");
    assert_token!("=", Operator(OperatorType::Assign), "OperatorType::Assign");
    assert_token!("+=", Operator(OperatorType::AddAssign), "OperatorType::AddAssign");
    assert_token!("-=", Operator(OperatorType::SubstractAssign), "OperatorType::SubstractAssign");
    assert_token!("**=", Operator(OperatorType::ExponentAssign), "OperatorType::ExponentAssign");
    assert_token!("*=", Operator(OperatorType::MultiplyAssign), "OperatorType::MultiplyAssign");
    assert_token!("/=", Operator(OperatorType::DivideAssign), "OperatorType::DivideAssign");
    assert_token!("%=", Operator(OperatorType::RemainderAssign), "OperatorType::RemainderAssign");
    assert_token!("<<=", Operator(OperatorType::BSLAssign), "OperatorType::BSLAssign");
    assert_token!(">>=", Operator(OperatorType::BSRAssign), "OperatorType::BSRAssign");
    assert_token!(">>>=", Operator(OperatorType::UBSRAssign), "OperatorType::UBSRAssign");
    assert_token!("&=", Operator(OperatorType::BitAndAssign), "OperatorType::BitAndAssign");
    assert_token!("^=", Operator(OperatorType::BitXorAssign), "OperatorType::BitXorAssign");
    assert_token!("|=", Operator(OperatorType::BitOrAssign), "OperatorType::BitOrAssign");
    assert_token!("...", Operator(OperatorType::Spread), "OperatorType::Spread");
}

#[test]
fn test_tokenizer_literals() {
    assert_token!("undefined", Literal(Value::Undefined), "Value::Undefined");
    assert_token!("null", Literal(Value::Null), "Value::Null");
    assert_token!("true", Literal(Value::True), "Value::True");
    assert_token!("false", Literal(Value::False), "Value::False");

    assert_token!("'foo'", Literal(Value::String("'foo'".into())), "Value::String");
    assert_token!("\"foo\"", Literal(Value::String("\"foo\"".into())), "Value::String");

    assert_token!("2.2", Literal(Value::Number("2.2".into())), "Value::Number");
    assert_token!("2", Literal(Value::Number("2".into())), "Value::Number");

    assert_token!("0xff", Literal(Value::Integer(255)), "Value::Integer");
    assert_token!("0XFF", Literal(Value::Integer(255)), "Value::Integer");
    assert_token!("0b01001011", Literal(Value::Integer(75)), "Value::Integer");
    assert_token!("0B01001011", Literal(Value::Integer(75)), "Value::Integer");
    assert_token!("0o113", Literal(Value::Integer(75)), "Value::Integer");
    assert_token!("0O113", Literal(Value::Integer(75)), "Value::Integer");
}

#[test]
fn test_tokenizer_reserved() {
    assert_token!("enum", Reserved(ReservedKind::Enum), "ReservedKind::Enum");
    assert_token!("implements", Reserved(ReservedKind::Implements), "ReservedKind::Implements");
    assert_token!("package", Reserved(ReservedKind::Package), "ReservedKind::Package");
    assert_token!("protected", Reserved(ReservedKind::Protected), "ReservedKind::Protected");
    assert_token!("interface", Reserved(ReservedKind::Interface), "ReservedKind::Interface");
    assert_token!("private", Reserved(ReservedKind::Private), "ReservedKind::Private");
    assert_token!("public", Reserved(ReservedKind::Public), "ReservedKind::Public");
}

#[test]
fn test_tokenizer_whitespace() {
    assert_token!("", EndOfProgram, "empty string");
    assert_token!("  ", EndOfProgram, "whitespaces");
    assert_token!("\n\n\n  ", EndOfProgram, "newlines");
    assert_token!("//Comment\n//Comment", EndOfProgram, "single-line comment");
    assert_token!("/**\n  * Comment\n  */", EndOfProgram, "multi-line comment");
}
<|endoftext|>


<commit_before>// Manages a single participant in the epoch scheme. This is where all
// of the actual epoch management logic happens!

use std::mem;
use std::cell::UnsafeCell;
use std::sync::atomic::{self, AtomicUsize, AtomicBool};
use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, SeqCst};

use mem::epoch::{Atomic, Guard, garbage, global};
use mem::epoch::participants::ParticipantNode;

/// Thread-local data for epoch participation.
pub struct Participant {
    /// The local epoch.
    epoch: AtomicUsize,

    /// Number of pending uses of `epoch::pin()`; keeping a count allows for
    /// reentrant use of epoch management.
    in_critical: AtomicUsize,

    /// Thread-local garbage tracking
    garbage: UnsafeCell<garbage::Local>,

    /// Is the thread still active? Becomes `false` when the thread exits. This
    /// is ultimately used to free `Participant` records.
    pub active: AtomicBool,

    /// The participant list is coded intrusively; here's the `next` pointer.
    pub next: Atomic<ParticipantNode>,
}

unsafe impl Sync for Participant {}

impl Participant {
    pub fn new() -> Participant {
        Participant {
            epoch: AtomicUsize::new(0),
            in_critical: AtomicUsize::new(0),
            active: AtomicBool::new(true),
            garbage: UnsafeCell::new(garbage::Local::new()),
            next: Atomic::null(),
        }
    }

    /// Enter a critical section.
    ///
    /// This method is reentrant, allowing for nested critical sections.
    pub fn enter(&self) {
        let new_count = self.in_critical.load(Relaxed) + 1;
        self.in_critical.store(new_count, Relaxed);
        if new_count > 1 { return }

        atomic::fence(SeqCst);

        let global_epoch = global::get().epoch.load(Relaxed);
        if global_epoch != self.epoch.load(Relaxed) {
            self.epoch.store(global_epoch, Relaxed);
            unsafe { (*self.garbage.get()).collect(); }
        }
    }

    /// Exit the current (nested) critical section.
    pub fn exit(&self) {
        let new_count = self.in_critical.load(Relaxed) - 1;
        self.in_critical.store(
            new_count,
            if new_count > 1 { Relaxed } else { Release });
    }

    /// Begin the reclamation process for a piece of data.
    pub unsafe fn reclaim<T>(&self, data: *mut T) {
        (*self.garbage.get()).reclaim(data);
    }

    /// Attempt to collect garbage by moving the global epoch forward.
    ///
    /// Returns `true` on success.
    pub fn try_collect(&self, guard: &Guard) -> bool {
        let cur_epoch = global::get().epoch.load(SeqCst);

        for p in global::get().participants.iter(guard) {
            if p.in_critical.load(Relaxed) > 0 && p.epoch.load(Relaxed) != cur_epoch {
                return false
            }
        }

        let new_epoch = cur_epoch.wrapping_add(1);
        atomic::fence(Acquire);
        if global::get().epoch.compare_and_swap(cur_epoch, new_epoch, SeqCst) != cur_epoch {
            return false
        }

        self.epoch.store(new_epoch, Relaxed);

        unsafe {
            global::get().garbage[new_epoch.wrapping_add(1) % 3].collect();
        }

        true
    }

    /// Move the current thread-local garbage into the global garbage bags.
    pub fn migrate_garbage(&self) {
        let cur_epoch = self.epoch.load(Relaxed);
        let local = unsafe { mem::replace(&mut *self.garbage.get(), garbage::Local::new()) };
        global::get().garbage[cur_epoch.wrapping_sub(1) % 3].insert(local.old);
        global::get().garbage[cur_epoch % 3].insert(local.cur);
        global::get().garbage[global::get().epoch.load(Relaxed) % 3].insert(local.new);
    }

    /// How much garbage is this participant currently storing?
    pub fn garbage_size(&self) -> usize {
        unsafe { (*self.garbage.get()).size() }
    }
}
<commit_msg>Relax mem ordering more when exiting a crit. sect.<commit_after>// Manages a single participant in the epoch scheme. This is where all
// of the actual epoch management logic happens!

use std::mem;
use std::cell::UnsafeCell;
use std::sync::atomic::{self, AtomicUsize, AtomicBool};
use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, SeqCst};

use mem::epoch::{Atomic, Guard, garbage, global};
use mem::epoch::participants::ParticipantNode;

/// Thread-local data for epoch participation.
pub struct Participant {
    /// The local epoch.
    epoch: AtomicUsize,

    /// Number of pending uses of `epoch::pin()`; keeping a count allows for
    /// reentrant use of epoch management.
    in_critical: AtomicUsize,

    /// Thread-local garbage tracking
    garbage: UnsafeCell<garbage::Local>,

    /// Is the thread still active? Becomes `false` when the thread exits. This
    /// is ultimately used to free `Participant` records.
    pub active: AtomicBool,

    /// The participant list is coded intrusively; here's the `next` pointer.
    pub next: Atomic<ParticipantNode>,
}

unsafe impl Sync for Participant {}

impl Participant {
    pub fn new() -> Participant {
        Participant {
            epoch: AtomicUsize::new(0),
            in_critical: AtomicUsize::new(0),
            active: AtomicBool::new(true),
            garbage: UnsafeCell::new(garbage::Local::new()),
            next: Atomic::null(),
        }
    }

    /// Enter a critical section.
    ///
    /// This method is reentrant, allowing for nested critical sections.
    pub fn enter(&self) {
        let new_count = self.in_critical.load(Relaxed) + 1;
        self.in_critical.store(new_count, Relaxed);
        if new_count > 1 { return }

        atomic::fence(SeqCst);

        let global_epoch = global::get().epoch.load(Relaxed);
        if global_epoch != self.epoch.load(Relaxed) {
            self.epoch.store(global_epoch, Relaxed);
            unsafe { (*self.garbage.get()).collect(); }
        }
    }

    /// Exit the current (nested) critical section.
    pub fn exit(&self) {
        let new_count = self.in_critical.load(Relaxed) - 1;
        self.in_critical.store(
            new_count,
            if new_count > 0 { Relaxed } else { Release });
    }

    /// Begin the reclamation process for a piece of data.
    pub unsafe fn reclaim<T>(&self, data: *mut T) {
        (*self.garbage.get()).reclaim(data);
    }

    /// Attempt to collect garbage by moving the global epoch forward.
    ///
    /// Returns `true` on success.
    pub fn try_collect(&self, guard: &Guard) -> bool {
        let cur_epoch = global::get().epoch.load(SeqCst);

        for p in global::get().participants.iter(guard) {
            if p.in_critical.load(Relaxed) > 0 && p.epoch.load(Relaxed) != cur_epoch {
                return false
            }
        }

        let new_epoch = cur_epoch.wrapping_add(1);
        atomic::fence(Acquire);
        if global::get().epoch.compare_and_swap(cur_epoch, new_epoch, SeqCst) != cur_epoch {
            return false
        }

        self.epoch.store(new_epoch, Relaxed);

        unsafe {
            global::get().garbage[new_epoch.wrapping_add(1) % 3].collect();
        }

        true
    }

    /// Move the current thread-local garbage into the global garbage bags.
    pub fn migrate_garbage(&self) {
        let cur_epoch = self.epoch.load(Relaxed);
        let local = unsafe { mem::replace(&mut *self.garbage.get(), garbage::Local::new()) };
        global::get().garbage[cur_epoch.wrapping_sub(1) % 3].insert(local.old);
        global::get().garbage[cur_epoch % 3].insert(local.cur);
        global::get().garbage[global::get().epoch.load(Relaxed) % 3].insert(local.new);
    }

    /// How much garbage is this participant currently storing?
    pub fn garbage_size(&self) -> usize {
        unsafe { (*self.garbage.get()).size() }
    }
}
<|endoftext|>


<commit_before><commit_msg>done, I really need find something to write<commit_after>fn remove_element<T>(a: Vec<T>, k: T) -> Vec<T>
where
    T: PartialEq + Clone,
{
    let mut result = vec![];
    for i in a {
        if i != k {
            result.push(i);
        }
    }
    result
}

fn main() {
    let test_case = vec![1, 2, 3, 4, 5, 6, 7];
    println!("{:?}", remove_element(test_case, 4));
}
<|endoftext|>