<commit_before>extern crate rayon;

use self::rayon::prelude::*;

use std::sync::{
    Arc,
    RwLock,
};
use super::attestation_validation::{
    AttestationValidationContext,
    AttestationValidationError,
};
use super::types::{
    AttestationRecord,
    AttesterMap,
    Block,
    ProposerMap,
};
use super::ssz_helpers::attestation_ssz_splitter::{
    split_one_attestation,
    split_all_attestations,
    AttestationSplitError,
};
use super::ssz_helpers::ssz_block::{
    SszBlock,
    SszBlockError,
};
use super::db::{
    ClientDB,
    DBError,
};
use super::db::stores::{
    BlockStore,
    PoWChainStore,
    ValidatorStore,
};
use super::ssz::{
    Decodable,
    DecodeError,
};
use super::types::Hash256;

#[derive(Debug, PartialEq)]
pub enum BlockStatus {
    NewBlock,
    KnownBlock,
}

#[derive(Debug, PartialEq)]
pub enum SszBlockValidationError {
    FutureSlot,
    SlotAlreadyFinalized,
    UnknownPoWChainRef,
    UnknownParentHash,
    BadAttestationSsz,
    AttestationValidationError(AttestationValidationError),
    AttestationSignatureFailed,
    ProposerAttestationHasObliqueHashes,
    NoProposerSignature,
    BadProposerMap,
    RwLockPoisoned,
    DBError(String),
}

/// The context against which a block should be validated.
pub struct BlockValidationContext<T>
    where T: ClientDB + Sized
{
    /// The slot as determined by the system time.
    pub present_slot: u64,
    /// The cycle_length as determined by the chain configuration.
    pub cycle_length: u8,
    /// The last justified slot as per the client's view of the canonical chain.
    pub last_justified_slot: u64,
    /// The last justified block hash as per the client's view of the canonical chain.
    pub last_justified_block_hash: Hash256,
    /// The last finalized slot as per the client's view of the canonical chain.
    pub last_finalized_slot: u64,
    /// A vec of the hashes of the blocks preceeding the present slot.
    pub parent_hashes: Arc<Vec<Hash256>>,
    /// A map of slots to a block proposer validation index.
    pub proposer_map: Arc<ProposerMap>,
    /// A map of (slot, shard_id) to the attestation set of validation indices.
    pub attester_map: Arc<AttesterMap>,
    /// The store containing block information.
    pub block_store: Arc<BlockStore<T>>,
    /// The store containing validator information.
    pub validator_store: Arc<ValidatorStore<T>>,
    /// The store containing information about the proof-of-work chain.
    pub pow_store: Arc<PoWChainStore<T>>,
}

impl<T> BlockValidationContext<T>
    where T: ClientDB
{
    /// Validate some SszBlock against a block validation context. An SszBlock varies from a Block in
    /// that is a read-only structure that reads directly from encoded SSZ.
    ///
    /// The reason to validate an SzzBlock is to avoid decoding it in its entirety if there is
    /// a suspicion that the block might be invalid. Such a suspicion should be applied to
    /// all blocks coming from the network.
    ///
    /// This function will determine if the block is new, already known or invalid (either
    /// intrinsically or due to some application error.)
    ///
    /// Note: this function does not implement randao_reveal checking as it is not in the
    /// specification.
    #[allow(dead_code)]
    pub fn validate_ssz_block(&self, b: &SszBlock)
        -> Result<(BlockStatus, Option<Block>), SszBlockValidationError>
        where T: ClientDB + Sized
    {

        /*
         * If this block is already known, return immediately and indicate the the block is
         * known. Don't attempt to deserialize the block.
         */
        let block_hash = &b.block_hash();
        if self.block_store.block_exists(&block_hash)? {
            return Ok((BlockStatus::KnownBlock, None));
        }

        /*
         * If the block slot corresponds to a slot in the future, return immediately with an error.
         *
         * It is up to the calling fn to determine what should be done with "future" blocks (e.g.,
         * cache or discard).
         */
        let block_slot = b.slot_number();
        if block_slot > self.present_slot {
            return Err(SszBlockValidationError::FutureSlot);
        }

        /*
         * If the block is unknown (assumed unknown because we checked the db earlier in this
         * function) and it comes from a slot that is already finalized, drop the block.
         *
         * If a slot is finalized, there's no point in considering any other blocks for that slot.
         */
        if block_slot <= self.last_finalized_slot {
            return Err(SszBlockValidationError::SlotAlreadyFinalized);
        }

        /*
         * If the PoW chain hash is not known to us, drop it.
         *
         * We only accept blocks that reference a known PoW hash.
         *
         * Note: it is not clear what a "known" PoW chain ref is. Likely it means the block hash is
         * "sufficienty deep in the canonical PoW chain". This should be clarified as the spec
         * crystallizes.
         */
        let pow_chain_ref = b.pow_chain_ref();
        if !self.pow_store.block_hash_exists(b.pow_chain_ref())? {
            return Err(SszBlockValidationError::UnknownPoWChainRef);
        }

        /*
         * Store a slice of the serialized attestations from the block SSZ.
         */
        let attestations_ssz = &b.attestations();

        /*
         * Get a slice of the first serialized attestation (the 0'th) and decode it into
         * a full AttestationRecord object.
         *
         * The first attestation must be validated separately as it must contain a signature of the
         * proposer of the previous block (this is checked later in this function).
         */
        let (first_attestation_ssz, next_index) = split_one_attestation(
            &attestations_ssz,
            0)?;
        let (first_attestation, _) = AttestationRecord::ssz_decode(
            &first_attestation_ssz, 0)?;

        /*
         * The first attestation may not have oblique hashes.
         *
         * The presence of oblique hashes in the first attestation would indicate that the proposer
         * of the previous block is attesting to some other block than the one they produced.
         */
        if first_attestation.oblique_parent_hashes.len() > 0 {
            return Err(SszBlockValidationError::ProposerAttestationHasObliqueHashes);
        }

        /*
         * Read the parent hash from the block we are validating then attempt to load
         * that parent block ssz from the database.
         *
         * If that parent doesn't exist in the database or is invalid, reject the block.
         *
         * Also, read the slot from the parent block for later use.
         */
        let parent_hash = b.parent_hash();
        let parent_slot = match self.block_store.get_serialized_block(&parent_hash)? {
            None => return Err(SszBlockValidationError::UnknownParentHash),
            Some(ssz) => {
                let parent_block = SszBlock::from_slice(&ssz[..])?;
                parent_block.slot_number()
            }
        };

        /*
         * Generate the context in which attestations will be validated.
         */
        let attestation_validation_context = Arc::new(AttestationValidationContext {
            block_slot,
            cycle_length: self.cycle_length,
            last_justified_slot: self.last_justified_slot,
            parent_hashes: self.parent_hashes.clone(),
            block_store: self.block_store.clone(),
            validator_store: self.validator_store.clone(),
            attester_map: self.attester_map.clone(),
        });

        /*
         * Validate this first attestation.
         */
        let attestation_voters = attestation_validation_context
            .validate_attestation(&first_attestation)?;

        /*
         * Attempt to read load the parent block proposer from the proposer map. Return with an
         * error if it fails.
         *
         * If the signature of proposer for the parent slot was not present in the first (0'th)
         * attestation of this block, reject the block.
         */
        let parent_block_proposer = self.proposer_map.get(&parent_slot)
            .ok_or(SszBlockValidationError::BadProposerMap)?;
        if !attestation_voters.contains(&parent_block_proposer) {
            return Err(SszBlockValidationError::NoProposerSignature);
        }

        /*
         * Split the remaining attestations into a vector of slices, each containing
         * a single serialized attestation record.
         */
        let other_attestations = split_all_attestations(attestations_ssz,
                                                        next_index)?;

        /*
         * Verify each other AttestationRecord.
         *
         * This uses the `rayon` library to do "sometimes" parallelization. Put simply,
         * if there are some spare threads, the verification of attestation records will happen
         * concurrently.
         *
         * There is a thread-safe `failure` variable which is set whenever an attestation fails
         * validation. This is so all attestation validation is halted if a single bad attestation
         * is found.
         */
        let failure: RwLock<Option<SszBlockValidationError>> = RwLock::new(None);
        let mut deserialized_attestations: Vec<AttestationRecord> = other_attestations
            .par_iter()
            .filter_map(|attestation_ssz| {
                /*
                 * If some thread has set the `failure` variable to `Some(error)` the abandon
                 * attestation serialization and validation.
                 */
                if let Some(_) = *failure.read().unwrap() {
                    return None;
                }
                /*
                 * If there has not been a failure yet, attempt to serialize and validate the
                 * attestation.
                 */
                match AttestationRecord::ssz_decode(&attestation_ssz, 0) {
                    /*
                     * Deserialization failed, therefore the block is invalid.
                     */
                    Err(e) => {
                        let mut failure = failure.write().unwrap();
                        *failure = Some(SszBlockValidationError::from(e));
                        None
                    }
                    /*
                     * Deserialization succeeded and the attestation should be validated.
                     */
                    Ok((attestation, _)) => {
                        match attestation_validation_context.validate_attestation(&attestation) {
                            /*
                             * Attestation validation failed with some error.
                             */
                            Err(e) => {
                                let mut failure = failure.write().unwrap();
                                *failure = Some(SszBlockValidationError::from(e));
                                None
                            }
                            /*
                             * Attestation validation succeded.
                             */
                            Ok(_) => Some(attestation)
                        }
                    }
                }
            })
            .collect();

        match failure.into_inner() {
            Err(_) => return Err(SszBlockValidationError::RwLockPoisoned),
            Ok(failure) => {
                match failure {
                    Some(error) => return Err(error),
                    _ => ()
                }

            }
        }

        /*
         * Add the first attestation to the vec of deserialized attestations at
         * index 0.
         */
        deserialized_attestations.insert(0, first_attestation);

        /*
         * If we have reached this point, the block is a new valid block that is worthy of
         * processing.
         */
        let block = Block {
            parent_hash: Hash256::from(parent_hash),
            slot_number: block_slot,
            randao_reveal: Hash256::from(b.randao_reveal()),
            attestations: deserialized_attestations,
            pow_chain_ref: Hash256::from(pow_chain_ref),
            active_state_root: Hash256::from(b.act_state_root()),
            crystallized_state_root: Hash256::from(b.cry_state_root()),
        };
        Ok((BlockStatus::NewBlock, Some(block)))
    }
}

impl From<DBError> for SszBlockValidationError {
    fn from(e: DBError) -> Self {
        SszBlockValidationError::DBError(e.message)
    }
}

impl From<AttestationSplitError> for SszBlockValidationError {
    fn from(e: AttestationSplitError) -> Self {
        match e {
            AttestationSplitError::TooShort =>
                SszBlockValidationError::BadAttestationSsz
        }
    }
}

impl From<SszBlockError> for SszBlockValidationError {
    fn from(e: SszBlockError) -> Self {
        match e {
            SszBlockError::TooShort =>
                SszBlockValidationError::DBError("Bad parent block in db.".to_string()),
            SszBlockError::TooLong =>
                SszBlockValidationError::DBError("Bad parent block in db.".to_string()),
        }
    }
}

impl From<DecodeError> for SszBlockValidationError {
    fn from(e: DecodeError) -> Self {
        match e {
            DecodeError::TooShort =>
                SszBlockValidationError::BadAttestationSsz,
            DecodeError::TooLong =>
                SszBlockValidationError::BadAttestationSsz,
        }
    }
}

impl From<AttestationValidationError> for SszBlockValidationError {
    fn from(e: AttestationValidationError) -> Self {
        SszBlockValidationError::AttestationValidationError(e)
    }
}

/*
 * Tests for block validation are contained in the root directory "tests" directory (AKA
 * "integration tests directory").
 */
<commit_msg>Add comment regarding tightening block val.<commit_after>extern crate rayon;

use self::rayon::prelude::*;

use std::sync::{
    Arc,
    RwLock,
};
use super::attestation_validation::{
    AttestationValidationContext,
    AttestationValidationError,
};
use super::types::{
    AttestationRecord,
    AttesterMap,
    Block,
    ProposerMap,
};
use super::ssz_helpers::attestation_ssz_splitter::{
    split_one_attestation,
    split_all_attestations,
    AttestationSplitError,
};
use super::ssz_helpers::ssz_block::{
    SszBlock,
    SszBlockError,
};
use super::db::{
    ClientDB,
    DBError,
};
use super::db::stores::{
    BlockStore,
    PoWChainStore,
    ValidatorStore,
};
use super::ssz::{
    Decodable,
    DecodeError,
};
use super::types::Hash256;

#[derive(Debug, PartialEq)]
pub enum BlockStatus {
    NewBlock,
    KnownBlock,
}

#[derive(Debug, PartialEq)]
pub enum SszBlockValidationError {
    FutureSlot,
    SlotAlreadyFinalized,
    UnknownPoWChainRef,
    UnknownParentHash,
    BadAttestationSsz,
    AttestationValidationError(AttestationValidationError),
    AttestationSignatureFailed,
    ProposerAttestationHasObliqueHashes,
    NoProposerSignature,
    BadProposerMap,
    RwLockPoisoned,
    DBError(String),
}

/// The context against which a block should be validated.
pub struct BlockValidationContext<T>
    where T: ClientDB + Sized
{
    /// The slot as determined by the system time.
    pub present_slot: u64,
    /// The cycle_length as determined by the chain configuration.
    pub cycle_length: u8,
    /// The last justified slot as per the client's view of the canonical chain.
    pub last_justified_slot: u64,
    /// The last justified block hash as per the client's view of the canonical chain.
    pub last_justified_block_hash: Hash256,
    /// The last finalized slot as per the client's view of the canonical chain.
    pub last_finalized_slot: u64,
    /// A vec of the hashes of the blocks preceeding the present slot.
    pub parent_hashes: Arc<Vec<Hash256>>,
    /// A map of slots to a block proposer validation index.
    pub proposer_map: Arc<ProposerMap>,
    /// A map of (slot, shard_id) to the attestation set of validation indices.
    pub attester_map: Arc<AttesterMap>,
    /// The store containing block information.
    pub block_store: Arc<BlockStore<T>>,
    /// The store containing validator information.
    pub validator_store: Arc<ValidatorStore<T>>,
    /// The store containing information about the proof-of-work chain.
    pub pow_store: Arc<PoWChainStore<T>>,
}

impl<T> BlockValidationContext<T>
    where T: ClientDB
{
    /// Validate some SszBlock against a block validation context. An SszBlock varies from a Block in
    /// that is a read-only structure that reads directly from encoded SSZ.
    ///
    /// The reason to validate an SzzBlock is to avoid decoding it in its entirety if there is
    /// a suspicion that the block might be invalid. Such a suspicion should be applied to
    /// all blocks coming from the network.
    ///
    /// This function will determine if the block is new, already known or invalid (either
    /// intrinsically or due to some application error.)
    ///
    /// Note: this function does not implement randao_reveal checking as it is not in the
    /// specification.
    #[allow(dead_code)]
    pub fn validate_ssz_block(&self, b: &SszBlock)
        -> Result<(BlockStatus, Option<Block>), SszBlockValidationError>
        where T: ClientDB + Sized
    {

        /*
         * If this block is already known, return immediately and indicate the the block is
         * known. Don't attempt to deserialize the block.
         */
        let block_hash = &b.block_hash();
        if self.block_store.block_exists(&block_hash)? {
            return Ok((BlockStatus::KnownBlock, None));
        }

        /*
         * If the block slot corresponds to a slot in the future, return immediately with an error.
         *
         * It is up to the calling fn to determine what should be done with "future" blocks (e.g.,
         * cache or discard).
         */
        let block_slot = b.slot_number();
        if block_slot > self.present_slot {
            return Err(SszBlockValidationError::FutureSlot);
        }

        /*
         * If the block is unknown (assumed unknown because we checked the db earlier in this
         * function) and it comes from a slot that is already finalized, drop the block.
         *
         * If a slot is finalized, there's no point in considering any other blocks for that slot.
         *
         * TODO: We can more strongly throw away blocks based on the `last_finalized_block` related
         * to this `last_finalized_slot`. Namely, any block in a future slot must include the
         * `last_finalized_block` in it's chain.
         */
        if block_slot <= self.last_finalized_slot {
            return Err(SszBlockValidationError::SlotAlreadyFinalized);
        }

        /*
         * If the PoW chain hash is not known to us, drop it.
         *
         * We only accept blocks that reference a known PoW hash.
         *
         * Note: it is not clear what a "known" PoW chain ref is. Likely it means the block hash is
         * "sufficienty deep in the canonical PoW chain". This should be clarified as the spec
         * crystallizes.
         */
        let pow_chain_ref = b.pow_chain_ref();
        if !self.pow_store.block_hash_exists(b.pow_chain_ref())? {
            return Err(SszBlockValidationError::UnknownPoWChainRef);
        }

        /*
         * Store a slice of the serialized attestations from the block SSZ.
         */
        let attestations_ssz = &b.attestations();

        /*
         * Get a slice of the first serialized attestation (the 0'th) and decode it into
         * a full AttestationRecord object.
         *
         * The first attestation must be validated separately as it must contain a signature of the
         * proposer of the previous block (this is checked later in this function).
         */
        let (first_attestation_ssz, next_index) = split_one_attestation(
            &attestations_ssz,
            0)?;
        let (first_attestation, _) = AttestationRecord::ssz_decode(
            &first_attestation_ssz, 0)?;

        /*
         * The first attestation may not have oblique hashes.
         *
         * The presence of oblique hashes in the first attestation would indicate that the proposer
         * of the previous block is attesting to some other block than the one they produced.
         */
        if first_attestation.oblique_parent_hashes.len() > 0 {
            return Err(SszBlockValidationError::ProposerAttestationHasObliqueHashes);
        }

        /*
         * Read the parent hash from the block we are validating then attempt to load
         * that parent block ssz from the database.
         *
         * If that parent doesn't exist in the database or is invalid, reject the block.
         *
         * Also, read the slot from the parent block for later use.
         */
        let parent_hash = b.parent_hash();
        let parent_slot = match self.block_store.get_serialized_block(&parent_hash)? {
            None => return Err(SszBlockValidationError::UnknownParentHash),
            Some(ssz) => {
                let parent_block = SszBlock::from_slice(&ssz[..])?;
                parent_block.slot_number()
            }
        };

        /*
         * Generate the context in which attestations will be validated.
         */
        let attestation_validation_context = Arc::new(AttestationValidationContext {
            block_slot,
            cycle_length: self.cycle_length,
            last_justified_slot: self.last_justified_slot,
            parent_hashes: self.parent_hashes.clone(),
            block_store: self.block_store.clone(),
            validator_store: self.validator_store.clone(),
            attester_map: self.attester_map.clone(),
        });

        /*
         * Validate this first attestation.
         */
        let attestation_voters = attestation_validation_context
            .validate_attestation(&first_attestation)?;

        /*
         * Attempt to read load the parent block proposer from the proposer map. Return with an
         * error if it fails.
         *
         * If the signature of proposer for the parent slot was not present in the first (0'th)
         * attestation of this block, reject the block.
         */
        let parent_block_proposer = self.proposer_map.get(&parent_slot)
            .ok_or(SszBlockValidationError::BadProposerMap)?;
        if !attestation_voters.contains(&parent_block_proposer) {
            return Err(SszBlockValidationError::NoProposerSignature);
        }

        /*
         * Split the remaining attestations into a vector of slices, each containing
         * a single serialized attestation record.
         */
        let other_attestations = split_all_attestations(attestations_ssz,
                                                        next_index)?;

        /*
         * Verify each other AttestationRecord.
         *
         * This uses the `rayon` library to do "sometimes" parallelization. Put simply,
         * if there are some spare threads, the verification of attestation records will happen
         * concurrently.
         *
         * There is a thread-safe `failure` variable which is set whenever an attestation fails
         * validation. This is so all attestation validation is halted if a single bad attestation
         * is found.
         */
        let failure: RwLock<Option<SszBlockValidationError>> = RwLock::new(None);
        let mut deserialized_attestations: Vec<AttestationRecord> = other_attestations
            .par_iter()
            .filter_map(|attestation_ssz| {
                /*
                 * If some thread has set the `failure` variable to `Some(error)` the abandon
                 * attestation serialization and validation.
                 */
                if let Some(_) = *failure.read().unwrap() {
                    return None;
                }
                /*
                 * If there has not been a failure yet, attempt to serialize and validate the
                 * attestation.
                 */
                match AttestationRecord::ssz_decode(&attestation_ssz, 0) {
                    /*
                     * Deserialization failed, therefore the block is invalid.
                     */
                    Err(e) => {
                        let mut failure = failure.write().unwrap();
                        *failure = Some(SszBlockValidationError::from(e));
                        None
                    }
                    /*
                     * Deserialization succeeded and the attestation should be validated.
                     */
                    Ok((attestation, _)) => {
                        match attestation_validation_context.validate_attestation(&attestation) {
                            /*
                             * Attestation validation failed with some error.
                             */
                            Err(e) => {
                                let mut failure = failure.write().unwrap();
                                *failure = Some(SszBlockValidationError::from(e));
                                None
                            }
                            /*
                             * Attestation validation succeded.
                             */
                            Ok(_) => Some(attestation)
                        }
                    }
                }
            })
            .collect();

        match failure.into_inner() {
            Err(_) => return Err(SszBlockValidationError::RwLockPoisoned),
            Ok(failure) => {
                match failure {
                    Some(error) => return Err(error),
                    _ => ()
                }

            }
        }

        /*
         * Add the first attestation to the vec of deserialized attestations at
         * index 0.
         */
        deserialized_attestations.insert(0, first_attestation);

        /*
         * If we have reached this point, the block is a new valid block that is worthy of
         * processing.
         */
        let block = Block {
            parent_hash: Hash256::from(parent_hash),
            slot_number: block_slot,
            randao_reveal: Hash256::from(b.randao_reveal()),
            attestations: deserialized_attestations,
            pow_chain_ref: Hash256::from(pow_chain_ref),
            active_state_root: Hash256::from(b.act_state_root()),
            crystallized_state_root: Hash256::from(b.cry_state_root()),
        };
        Ok((BlockStatus::NewBlock, Some(block)))
    }
}

impl From<DBError> for SszBlockValidationError {
    fn from(e: DBError) -> Self {
        SszBlockValidationError::DBError(e.message)
    }
}

impl From<AttestationSplitError> for SszBlockValidationError {
    fn from(e: AttestationSplitError) -> Self {
        match e {
            AttestationSplitError::TooShort =>
                SszBlockValidationError::BadAttestationSsz
        }
    }
}

impl From<SszBlockError> for SszBlockValidationError {
    fn from(e: SszBlockError) -> Self {
        match e {
            SszBlockError::TooShort =>
                SszBlockValidationError::DBError("Bad parent block in db.".to_string()),
            SszBlockError::TooLong =>
                SszBlockValidationError::DBError("Bad parent block in db.".to_string()),
        }
    }
}

impl From<DecodeError> for SszBlockValidationError {
    fn from(e: DecodeError) -> Self {
        match e {
            DecodeError::TooShort =>
                SszBlockValidationError::BadAttestationSsz,
            DecodeError::TooLong =>
                SszBlockValidationError::BadAttestationSsz,
        }
    }
}

impl From<AttestationValidationError> for SszBlockValidationError {
    fn from(e: AttestationValidationError) -> Self {
        SszBlockValidationError::AttestationValidationError(e)
    }
}

/*
 * Tests for block validation are contained in the root directory "tests" directory (AKA
 * "integration tests directory").
 */
<|endoftext|>


<commit_before>use libc;
use glib::translate::*;
use itertools::Itertools;

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum XmlSpace {
    Default,
    Preserve
}

/// Implements `xml:space` handling per the SVG spec
///
/// Normalizes a string as it comes out of the XML parser's handler
/// for character data according to the SVG rules in
/// https://www.w3.org/TR/SVG/text.html#WhiteSpace
pub fn xml_space_normalize(mode: XmlSpace, s: &str) -> String {
    match mode {
        XmlSpace::Default => normalize_default(s),
        XmlSpace::Preserve => normalize_preserve(s)
    }
}

// From https://www.w3.org/TR/SVG/text.html#WhiteSpace
//
// When xml:space="default", the SVG user agent will do the following
// using a copy of the original character data content. First, it will
// remove all newline characters. Then it will convert all tab
// characters into space characters. Then, it will strip off all
// leading and trailing space characters. Then, all contiguous space
// characters will be consolidated.
fn normalize_default(s: &str) -> String {
    s.trim()
        .chars()
        .filter(|ch| *ch != '\n')
        .map(|ch| match ch {
            '\t' => ' ',
            c => c,
        })
        .coalesce(|current, next| match (current, next) {
            (' ', ' ') | (' ', '\t') => Ok(' '),
            (_, _) => Err((current, next)),
        })
        .collect::<String>()
}

// From https://www.w3.org/TR/SVG/text.html#WhiteSpace
//
// When xml:space="preserve", the SVG user agent will do the following
// using a copy of the original character data content. It will
// convert all newline and tab characters into space characters. Then,
// it will draw all space characters, including leading, trailing and
// multiple contiguous space characters. Thus, when drawn with
// xml:space="preserve", the string "a   b" (three spaces between "a"
// and "b") will produce a larger separation between "a" and "b" than
// "a b" (one space between "a" and "b").
fn normalize_preserve(s: &str) -> String {
    s.chars()
        .map(|ch| {
            match ch {
                '\n' | '\t' => ' ',

                c => c
            }
        })
        .collect()
}

#[no_mangle]
pub extern fn rsvg_xml_space_normalize(mode: XmlSpace, s: *const libc::c_char) -> *const libc::c_char {
    let rs = unsafe { String::from_glib_none (s) };

    xml_space_normalize(mode, &rs).to_glib_full()
}

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

    #[test]
    fn xml_space_default() {
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\n    WS example\n    indented lines\n  "),
                   "WS example indented lines");
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\n  \t  \tWS \t\t\texample\n  \t  indented lines\t\t  \n  "),
                   "WS example indented lines");
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\n  \t  \tWS \t\t\texample\n  \t  duplicate letters\t\t  \n  "),
                   "WS example duplicate letters");
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\nWS example\nnon-indented lines\n  "),
                   "WS examplenon-indented lines");
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\nWS example\tnon-indented lines\n  "),
                   "WS example non-indented lines");
    }

    #[test]
    fn xml_space_preserve() {
        assert_eq!(xml_space_normalize(XmlSpace::Preserve, "\n    WS example\n    indented lines\n  "),
                   "     WS example     indented lines   ");
        assert_eq!(xml_space_normalize(XmlSpace::Preserve, "\n  \t  \tWS \t\t\texample\n  \t  indented lines\t\t  \n  "),
                   "       WS    example      indented lines       ");
        assert_eq!(xml_space_normalize(XmlSpace::Preserve, "\n  \t  \tWS \t\t\texample\n  \t  duplicate letters\t\t  \n  "),
                   "       WS    example      duplicate letters       ");
    }
}
<commit_msg>normalize_default(): No need to coalesce (space, tab)<commit_after>use libc;
use glib::translate::*;
use itertools::Itertools;

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum XmlSpace {
    Default,
    Preserve
}

/// Implements `xml:space` handling per the SVG spec
///
/// Normalizes a string as it comes out of the XML parser's handler
/// for character data according to the SVG rules in
/// https://www.w3.org/TR/SVG/text.html#WhiteSpace
pub fn xml_space_normalize(mode: XmlSpace, s: &str) -> String {
    match mode {
        XmlSpace::Default => normalize_default(s),
        XmlSpace::Preserve => normalize_preserve(s)
    }
}

// From https://www.w3.org/TR/SVG/text.html#WhiteSpace
//
// When xml:space="default", the SVG user agent will do the following
// using a copy of the original character data content. First, it will
// remove all newline characters. Then it will convert all tab
// characters into space characters. Then, it will strip off all
// leading and trailing space characters. Then, all contiguous space
// characters will be consolidated.
fn normalize_default(s: &str) -> String {
    s.trim()
        .chars()
        .filter(|ch| *ch != '\n')
        .map(|ch| match ch {
            '\t' => ' ',
            c => c,
        })
        .coalesce(|current, next| match (current, next) {
            (' ', ' ') => Ok(' '),
            (_, _) => Err((current, next)),
        })
        .collect::<String>()
}

// From https://www.w3.org/TR/SVG/text.html#WhiteSpace
//
// When xml:space="preserve", the SVG user agent will do the following
// using a copy of the original character data content. It will
// convert all newline and tab characters into space characters. Then,
// it will draw all space characters, including leading, trailing and
// multiple contiguous space characters. Thus, when drawn with
// xml:space="preserve", the string "a   b" (three spaces between "a"
// and "b") will produce a larger separation between "a" and "b" than
// "a b" (one space between "a" and "b").
fn normalize_preserve(s: &str) -> String {
    s.chars()
        .map(|ch| {
            match ch {
                '\n' | '\t' => ' ',

                c => c
            }
        })
        .collect()
}

#[no_mangle]
pub extern fn rsvg_xml_space_normalize(mode: XmlSpace, s: *const libc::c_char) -> *const libc::c_char {
    let rs = unsafe { String::from_glib_none (s) };

    xml_space_normalize(mode, &rs).to_glib_full()
}

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

    #[test]
    fn xml_space_default() {
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\n    WS example\n    indented lines\n  "),
                   "WS example indented lines");
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\n  \t  \tWS \t\t\texample\n  \t  indented lines\t\t  \n  "),
                   "WS example indented lines");
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\n  \t  \tWS \t\t\texample\n  \t  duplicate letters\t\t  \n  "),
                   "WS example duplicate letters");
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\nWS example\nnon-indented lines\n  "),
                   "WS examplenon-indented lines");
        assert_eq!(xml_space_normalize(XmlSpace::Default, "\nWS example\tnon-indented lines\n  "),
                   "WS example non-indented lines");
    }

    #[test]
    fn xml_space_preserve() {
        assert_eq!(xml_space_normalize(XmlSpace::Preserve, "\n    WS example\n    indented lines\n  "),
                   "     WS example     indented lines   ");
        assert_eq!(xml_space_normalize(XmlSpace::Preserve, "\n  \t  \tWS \t\t\texample\n  \t  indented lines\t\t  \n  "),
                   "       WS    example      indented lines       ");
        assert_eq!(xml_space_normalize(XmlSpace::Preserve, "\n  \t  \tWS \t\t\texample\n  \t  duplicate letters\t\t  \n  "),
                   "       WS    example      duplicate letters       ");
    }
}
<|endoftext|>


<commit_before>//! Support for nested invocations of proc-macro-hack expression macros.
//!
//! By default, macros defined through proc-macro-hack do not support nested
//! invocations, i.e. the code emitted by a proc-macro-hack macro invocation
//! cannot contain recursive calls to the same proc-macro-hack macro nor calls
//! to any other proc-macro-hack macros.
//!
//! This crate provides opt-in support for such nested invocations.
//!
//! To make a macro callable recursively, add a dependency on this crate from
//! your declaration crate and update the `#[proc_macro_hack]` re-export as
//! follows.
//!
//! ```rust
//! // Before
//! # const IGNORE: &str = stringify! {
//! #[proc_macro_hack]
//! pub use demo_hack_impl::add_one;
//! # }
//! ```
//!
//! ```rust
//! // After
//! # const IGNORE: &str = stringify! {
//! #[proc_macro_hack(support_nested)]
//! pub use demo_hack_impl::add_one;
//! # }
//! ```
//!
//! No change is required within your definition crate, only to the re-export in
//! the declaration crate.
//!
//! # Limitations
//!
//! - Nested invocations are preprocessed by a TT-muncher, so the caller's crate
//!   will be required to contain `#![recursion_limit = "..."]` if there are
//!   lengthy macro invocations.
//!
//! - Only up to 64 nested invocations are supported.

#![no_std]

include!(concat!(env!("OUT_DIR"), "/count.rs"));

#[doc(hidden)]
#[macro_export]
macro_rules! dispatch {
    (() $($bang:tt)*) => {
        $crate::count!($($bang)*)
    };
    ((($($first:tt)*) $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    (([$($first:tt)*] $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    (({$($first:tt)*} $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    ((! $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($rest)*) $($bang)* !)
    };
    (($first:tt $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($rest)*) $($bang)*)
    };
}
<commit_msg>Include '!=' in the count of bangs in proc-macro-nested<commit_after>//! Support for nested invocations of proc-macro-hack expression macros.
//!
//! By default, macros defined through proc-macro-hack do not support nested
//! invocations, i.e. the code emitted by a proc-macro-hack macro invocation
//! cannot contain recursive calls to the same proc-macro-hack macro nor calls
//! to any other proc-macro-hack macros.
//!
//! This crate provides opt-in support for such nested invocations.
//!
//! To make a macro callable recursively, add a dependency on this crate from
//! your declaration crate and update the `#[proc_macro_hack]` re-export as
//! follows.
//!
//! ```rust
//! // Before
//! # const IGNORE: &str = stringify! {
//! #[proc_macro_hack]
//! pub use demo_hack_impl::add_one;
//! # }
//! ```
//!
//! ```rust
//! // After
//! # const IGNORE: &str = stringify! {
//! #[proc_macro_hack(support_nested)]
//! pub use demo_hack_impl::add_one;
//! # }
//! ```
//!
//! No change is required within your definition crate, only to the re-export in
//! the declaration crate.
//!
//! # Limitations
//!
//! - Nested invocations are preprocessed by a TT-muncher, so the caller's crate
//!   will be required to contain `#![recursion_limit = "..."]` if there are
//!   lengthy macro invocations.
//!
//! - Only up to 64 nested invocations are supported.

#![no_std]

include!(concat!(env!("OUT_DIR"), "/count.rs"));

#[doc(hidden)]
#[macro_export]
macro_rules! dispatch {
    (() $($bang:tt)*) => {
        $crate::count!($($bang)*)
    };
    ((($($first:tt)*) $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    (([$($first:tt)*] $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    (({$($first:tt)*} $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    ((! $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($rest)*) $($bang)* !)
    };
    ((!= $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($rest)*) $($bang)* !)
    };
    (($first:tt $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($rest)*) $($bang)*)
    };
}
<|endoftext|>


<commit_before>// Daniel Shiffman
// http://natureofcode.com

// Daniel Shiffman, Nature of Code

// A basic implementation of John Conway's Game of Life CA
// how could this be improved to use object oriented programming?
// think of it as similar to our particle system, with a "cell" class
// to describe each individual cell and a "cellular automata" class
// to describe a collection of cells

// Cells wrap around

use nannou::prelude::*;

fn main() {
    nannou::app(model).update(update).run();
}

struct Gol {
    w: usize,
    columns: usize,
    rows: usize,
    board: Vec<Vec<i32>>,
}

impl Gol {
    fn new(rect: Rect) -> Self {
        let w = 8;
        let columns = rect.w() as usize / w;
        let rows = rect.h() as usize / w;
        let board = vec![vec![0; rows]; columns];

        let mut gol = Gol {
            w,
            columns,
            rows,
            board,
        };

        gol.init();

        gol
    }

    fn init(&mut self) {
        for i in 0..self.columns {
            for j in 0..self.rows {
                self.board[i][j] = if random::<bool>() { 1 } else { 0 };
            }
        }
    }

    // The process of creating the new generation
    fn generate(&mut self) {
        let mut next = vec![vec![0; self.rows]; self.columns];

        // Loop through every spot in our 2D array and check spots neighbors
        for x in 0..self.columns {
            for y in 0..self.rows {
                // Add up all the states in a 3x3 surrounding grid
                let mut neighbors = 0;
                for i in 0..3 {
                    for j in 0..3 {
                        neighbors += self.board[(x + (i - 1) + self.columns) % self.columns]
                            [(y + (j - 1) + self.rows) % self.rows];
                    }
                }

                // A little trick to subtract the current call's state since
                // we added it in the above loop
                neighbors -= self.board[x][y];

                // Rules of Life
                if self.board[x][y] == 1 && neighbors < 2 {
                    next[x][y] = 0; // Loneliness
                } else if self.board[x][y] == 1 && neighbors > 3 {
                    next[x][y] = 0; // Over Population
                } else if self.board[x][y] == 0 && neighbors == 3 {
                    next[x][y] = 1; // Reproduction
                } else {
                    next[x][y] = self.board[x][y]; // Stasis
                }
            }
        }
        // Next is now our board
        self.board = next;
    }

    // This is the easy part, just draw the cells fill white if 1, black if 0
    fn display(&self, draw: &app::Draw, rect: &Rect) {
        for i in 0..self.columns {
            for j in 0..self.rows {
                let mut fill = 1.0;
                if self.board[i][j] == 1 {
                    fill = 0.0;
                }
                let offset = self.w as f32 / 2.0;
                draw.rect()
                    .x_y(
                        offset + (i * self.w) as f32 - rect.right() as f32,
                        offset + (j * self.w) as f32 - rect.top() as f32,
                    )
                    .w_h(self.w as f32, self.w as f32)
                    .gray(fill)
                    .stroke(BLACK);
            }
        }
    }
}

struct Model {
    gol: Gol,
}

fn model(app: &App) -> Model {
    let rect = Rect::from_w_h(400.0, 400.0);
    app.new_window()
        .size(rect.w() as u32, rect.h() as u32)
        .mouse_pressed(mouse_pressed)
        .view(view)
        .build()
        .unwrap();

    let gol = Gol::new(rect);
    Model { gol }
}

fn mouse_pressed(_app: &App, m: &mut Model, _button: MouseButton) {
    // Reset board when mouse is pressed
    m.gol.init();
}

fn update(_app: &App, m: &mut Model, _update: Update) {
    m.gol.generate();
}

fn view(app: &App, m: &Model, frame: Frame) {
    // Begin drawing
    let draw = app.draw();
    draw.background().color(WHITE);

    m.gol.display(&draw, &app.window_rect());

    // Write the result of our drawing to the window's frame.
    draw.to_frame(app, &frame).unwrap();
}
<commit_msg>Fix integer underflow panic in game of life wrap around example<commit_after>// Daniel Shiffman
// http://natureofcode.com

// Daniel Shiffman, Nature of Code

// A basic implementation of John Conway's Game of Life CA
// how could this be improved to use object oriented programming?
// think of it as similar to our particle system, with a "cell" class
// to describe each individual cell and a "cellular automata" class
// to describe a collection of cells

// Cells wrap around

use nannou::prelude::*;

fn main() {
    nannou::app(model).update(update).run();
}

struct Gol {
    w: usize,
    columns: usize,
    rows: usize,
    board: Vec<Vec<i32>>,
}

impl Gol {
    fn new(rect: Rect) -> Self {
        let w = 8;
        let columns = rect.w() as usize / w;
        let rows = rect.h() as usize / w;
        let board = vec![vec![0; rows]; columns];

        let mut gol = Gol {
            w,
            columns,
            rows,
            board,
        };

        gol.init();

        gol
    }

    fn init(&mut self) {
        for i in 0..self.columns {
            for j in 0..self.rows {
                self.board[i][j] = if random::<bool>() { 1 } else { 0 };
            }
        }
    }

    // The process of creating the new generation
    fn generate(&mut self) {
        let mut next = vec![vec![0; self.rows]; self.columns];

        // Loop through every spot in our 2D array and check spots neighbors
        for x in 0..self.columns {
            for y in 0..self.rows {
                // Add up all the states in a 3x3 surrounding grid
                let mut neighbors = 0;
                for i in 0..3i32 {
                    for j in 0..3i32 {
                        let cols = self.columns as i32;
                        let rows = self.rows as i32;
                        let board_x = (x as i32 + (i - 1) + cols) % cols;
                        let board_y = (y as i32 + (j - 1) + rows) % rows;
                        neighbors += self.board[board_x as usize][board_y as usize];
                    }
                }

                // A little trick to subtract the current call's state since
                // we added it in the above loop
                neighbors -= self.board[x][y];

                // Rules of Life
                if self.board[x][y] == 1 && neighbors < 2 {
                    next[x][y] = 0; // Loneliness
                } else if self.board[x][y] == 1 && neighbors > 3 {
                    next[x][y] = 0; // Over Population
                } else if self.board[x][y] == 0 && neighbors == 3 {
                    next[x][y] = 1; // Reproduction
                } else {
                    next[x][y] = self.board[x][y]; // Stasis
                }
            }
        }
        // Next is now our board
        self.board = next;
    }

    // This is the easy part, just draw the cells fill white if 1, black if 0
    fn display(&self, draw: &app::Draw, rect: &Rect) {
        for i in 0..self.columns {
            for j in 0..self.rows {
                let mut fill = 1.0;
                if self.board[i][j] == 1 {
                    fill = 0.0;
                }
                let offset = self.w as f32 / 2.0;
                draw.rect()
                    .x_y(
                        offset + (i * self.w) as f32 - rect.right() as f32,
                        offset + (j * self.w) as f32 - rect.top() as f32,
                    )
                    .w_h(self.w as f32, self.w as f32)
                    .gray(fill)
                    .stroke(BLACK);
            }
        }
    }
}

struct Model {
    gol: Gol,
}

fn model(app: &App) -> Model {
    let rect = Rect::from_w_h(400.0, 400.0);
    app.new_window()
        .size(rect.w() as u32, rect.h() as u32)
        .mouse_pressed(mouse_pressed)
        .view(view)
        .build()
        .unwrap();

    let gol = Gol::new(rect);
    Model { gol }
}

fn mouse_pressed(_app: &App, m: &mut Model, _button: MouseButton) {
    // Reset board when mouse is pressed
    m.gol.init();
}

fn update(_app: &App, m: &mut Model, _update: Update) {
    m.gol.generate();
}

fn view(app: &App, m: &Model, frame: Frame) {
    // Begin drawing
    let draw = app.draw();
    draw.background().color(WHITE);

    m.gol.display(&draw, &app.window_rect());

    // Write the result of our drawing to the window's frame.
    draw.to_frame(app, &frame).unwrap();
}
<|endoftext|>


<commit_before>// Initial Rust implementation.

use std::time::Instant;

fn main() {

    let mut num_steps: i64;
    let step: f64;
    let mut x: f64;
    let mut s: f64;
    let my_pi: f64;
    let arguments = std::env::args();

    num_steps = 100000;

// Arguments are an iterator which is a PITA.
    let mut index = 0;
    for argument in arguments {
        if index == 1 {
            num_steps = argument.parse::<i64>().unwrap();
        }
        index = index + 1;
    }

    print!("Calculating PI using:\n  ");
    print!("{} slices\n", num_steps.to_string());
    print!("  {} threads\n", 1.to_string());

    let start = Instant::now();

    s = 0.0;
    step = 1.0/num_steps as f64;

    for i in 0..num_steps {
        x = ((i as f64) + 0.5)* step;
        s = s + (4.0/(1.0 + (x*x)));
    }

    my_pi = s * step;

    let stop = Instant::now();

    print!("Obtained value of PI: {}\n", my_pi);
    print!("Time Elapsed: {}.", stop.duration_since(start).as_secs());
    print!("{} seconds\n", stop.duration_since(start).subsec_nanos());

}<commit_msg>Final tidy.<commit_after>// Initial Rust implementation.

use std::time::Instant;

fn main() {

    let mut num_steps: i64;
    let step: f64;
    let mut x: f64;
    let mut s: f64;
    let my_pi: f64;
    let arguments = std::env::args();

    num_steps = 100000000;

// Arguments are an iterator which is a PITA.
    let mut index = 0;
    for argument in arguments {
        if index == 1 {
            num_steps = argument.parse::<i64>().unwrap();
        }
        index = index + 1;
    }

    print!("Calculating PI using:\n");
    print!("  {} slices\n", num_steps.to_string());
    print!("  {} threads\n", 1.to_string());

    let start = Instant::now();

    s = 0.0;
    step = 1.0/num_steps as f64;

    for i in 0..num_steps {
        x = ((i as f64) + 0.5)* step;
        s = s + (4.0/(1.0 + (x*x)));
    }

    my_pi = s * step;

    let stop = Instant::now();

    print!("Obtained value of PI: {}\n", my_pi);
    print!("Time Elapsed: {}.", stop.duration_since(start).as_secs());
    print!("{} seconds\n", stop.duration_since(start).subsec_nanos());

}<|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 syntax::{ast, codemap, visit};
use syntax::attr::AttrMetaMethods;
use rustc::ast_map;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty;
use rustc::middle::astconv_util::ast_ty_to_prim_ty;
use utils::{match_def_path, unsafe_context};

declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects");

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]`
/// values are used correctly.
///
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement, assignment, `for` loop, or `match` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a
/// GC pass.
///
/// Structs which have their own mechanism of rooting their unrooted contents (e.g. `ScriptTask`)
/// can be marked as `#[allow(unrooted_must_root)]`. Smart pointers which root their interior type
/// can be marked as `#[allow_unrooted_interior]`
pub struct UnrootedPass {
    in_new_function: bool
}

impl UnrootedPass {
    pub fn new() -> UnrootedPass {
        UnrootedPass {
            in_new_function: true
        }
    }
}

/// Checks if a type is unrooted or contains any owned unrooted types
fn is_unrooted_ty(cx: &Context, ty: &ty::TyS, in_new_function: bool) -> bool {
    let mut ret = false;
    ty.maybe_walk(|t| {
        match t.sty {
            ty::TyStruct(did, _) |
            ty::TyEnum(did, _) => {
                if cx.tcx.has_attr(did, "must_root") {
                    ret = true;
                    false
                } else if cx.tcx.has_attr(did, "allow_unrooted_interior") {
                    false
                } else if match_def_path(cx, did, &["core", "cell", "Ref"])
                        || match_def_path(cx, did, &["core", "cell", "RefMut"]) {
                        // Ref and RefMut are borrowed pointers, okay to hold unrooted stuff
                        // since it will be rooted elsewhere
                    false
                } else {
                    true
                }
            },
            ty::TyBox(..) if in_new_function => false, // box in new() is okay
            ty::TyRef(..) => false, // don't recurse down &ptrs
            ty::TyRawPtr(..) => false, // don't recurse down *ptrs
            _ => true
        }
    });
    ret
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(&mut self,
                        cx: &Context,
                        def: &ast::StructDef,
                        _i: ast::Ident,
                        _gen: &ast::Generics,
                        id: ast::NodeId) {
        let item = match cx.tcx.map.get(id) {
            ast_map::Node::NodeItem(item) => item,
            _ => cx.tcx.map.expect_item(cx.tcx.map.get_parent(id)),
        };
        if item.attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                if is_unrooted_ty(cx, cx.tcx.node_id_to_type(field.node.id), false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, field.span,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate")
                }
            }
        }
    }
    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        ast_ty_to_prim_ty(cx.tcx, &*ty.ty).map(|t| {
                            if is_unrooted_ty(cx, t, false) {
                                cx.span_lint(UNROOTED_MUST_ROOT, ty.ty.span,
                                             "Type must be rooted, use #[must_root] on \
                                              the enum definition to propagate")
                            }
                        });
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _, _, _) |
            visit::FkMethod(i, _, _) if i.name.as_str() == "new"
                                        || i.name.as_str() == "new_inherited"
                                        || i.name.as_str() == "new_initialized" => {
                self.in_new_function = true;
                return;
            },
            visit::FkItemFn(_, _, style, _, _, _) => match style {
                ast::Unsafety::Unsafe => return,
                _ => ()
            },
            _ => ()
        }
        self.in_new_function = false;

        if unsafe_context(&cx.tcx.map, id) {
            return;
        }

        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    ast_ty_to_prim_ty(cx.tcx, &*arg.ty).map(|t| {
                        if is_unrooted_ty(cx, t, false) {
                            cx.span_lint(UNROOTED_MUST_ROOT, arg.ty.span, "Type must be rooted")
                        }
                    });
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    /// Trait casts from #[must_root] types are not allowed
    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        fn require_rooted(cx: &Context, in_new_function: bool, subexpr: &ast::Expr) {
            let ty = cx.tcx.expr_ty(&*subexpr);
            if is_unrooted_ty(cx, ty, in_new_function) {
                cx.span_lint(UNROOTED_MUST_ROOT,
                             subexpr.span,
                             &format!("Expression of type {:?} must be rooted", ty))
            }
        };

        match expr.node {
            ast::ExprCast(ref subexpr, _) => require_rooted(cx, self.in_new_function, &*subexpr),
            _ => {
                // TODO(pcwalton): Check generics with a whitelist of allowed generics.
            }
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements and assignments which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let` or assignment
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        match s.node {
            ast::StmtDecl(_, id) |
            ast::StmtExpr(_, id) |
            ast::StmtSemi(_, id) if unsafe_context(&cx.tcx.map, id) => {
                return
            },
            _ => ()
        };

        let expr = match s.node {
            // Catch a `let` binding
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                    Some(ref e) => &**e,
                    _ => return
                },
                _ => return
            },
            ast::StmtExpr(ref expr, _) => match expr.node {
                // This catches deferred `let` statements
                ast::ExprAssign(_, ref e) |
                // Match statements allow you to bind onto the variable later in an arm
                // We need not check arms individually since enum/struct fields are already
                // linted in `check_struct_def` and `check_variant`
                // (so there is no way of destructuring out a `#[must_root]` field)
                ast::ExprMatch(ref e, _, _) |
                // For loops allow you to bind a return value locally
                ast::ExprForLoop(_, ref e, _, _) => &**e,
                // XXXManishearth look into `if let` once it lands in our rustc
                _ => return
            },
            _ => return
        };

        let ty = cx.tcx.expr_ty(&*expr);
        if is_unrooted_ty(cx, ty, self.in_new_function) {
            cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                     &format!("Expression of type {:?} must be rooted", ty))
        }
    }
}
<commit_msg>Remove fixme for if let in lints and replace with unreachable!()<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 syntax::{ast, codemap, visit};
use syntax::attr::AttrMetaMethods;
use rustc::ast_map;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty;
use rustc::middle::astconv_util::ast_ty_to_prim_ty;
use utils::{match_def_path, unsafe_context};

declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects");

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]`
/// values are used correctly.
///
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement, assignment, `for` loop, or `match` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a
/// GC pass.
///
/// Structs which have their own mechanism of rooting their unrooted contents (e.g. `ScriptTask`)
/// can be marked as `#[allow(unrooted_must_root)]`. Smart pointers which root their interior type
/// can be marked as `#[allow_unrooted_interior]`
pub struct UnrootedPass {
    in_new_function: bool
}

impl UnrootedPass {
    pub fn new() -> UnrootedPass {
        UnrootedPass {
            in_new_function: true
        }
    }
}

/// Checks if a type is unrooted or contains any owned unrooted types
fn is_unrooted_ty(cx: &Context, ty: &ty::TyS, in_new_function: bool) -> bool {
    let mut ret = false;
    ty.maybe_walk(|t| {
        match t.sty {
            ty::TyStruct(did, _) |
            ty::TyEnum(did, _) => {
                if cx.tcx.has_attr(did, "must_root") {
                    ret = true;
                    false
                } else if cx.tcx.has_attr(did, "allow_unrooted_interior") {
                    false
                } else if match_def_path(cx, did, &["core", "cell", "Ref"])
                        || match_def_path(cx, did, &["core", "cell", "RefMut"]) {
                        // Ref and RefMut are borrowed pointers, okay to hold unrooted stuff
                        // since it will be rooted elsewhere
                    false
                } else {
                    true
                }
            },
            ty::TyBox(..) if in_new_function => false, // box in new() is okay
            ty::TyRef(..) => false, // don't recurse down &ptrs
            ty::TyRawPtr(..) => false, // don't recurse down *ptrs
            _ => true
        }
    });
    ret
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(&mut self,
                        cx: &Context,
                        def: &ast::StructDef,
                        _i: ast::Ident,
                        _gen: &ast::Generics,
                        id: ast::NodeId) {
        let item = match cx.tcx.map.get(id) {
            ast_map::Node::NodeItem(item) => item,
            _ => cx.tcx.map.expect_item(cx.tcx.map.get_parent(id)),
        };
        if item.attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                if is_unrooted_ty(cx, cx.tcx.node_id_to_type(field.node.id), false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, field.span,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate")
                }
            }
        }
    }
    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        ast_ty_to_prim_ty(cx.tcx, &*ty.ty).map(|t| {
                            if is_unrooted_ty(cx, t, false) {
                                cx.span_lint(UNROOTED_MUST_ROOT, ty.ty.span,
                                             "Type must be rooted, use #[must_root] on \
                                              the enum definition to propagate")
                            }
                        });
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _, _, _) |
            visit::FkMethod(i, _, _) if i.name.as_str() == "new"
                                        || i.name.as_str() == "new_inherited"
                                        || i.name.as_str() == "new_initialized" => {
                self.in_new_function = true;
                return;
            },
            visit::FkItemFn(_, _, style, _, _, _) => match style {
                ast::Unsafety::Unsafe => return,
                _ => ()
            },
            _ => ()
        }
        self.in_new_function = false;

        if unsafe_context(&cx.tcx.map, id) {
            return;
        }

        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    ast_ty_to_prim_ty(cx.tcx, &*arg.ty).map(|t| {
                        if is_unrooted_ty(cx, t, false) {
                            cx.span_lint(UNROOTED_MUST_ROOT, arg.ty.span, "Type must be rooted")
                        }
                    });
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    /// Trait casts from #[must_root] types are not allowed
    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        fn require_rooted(cx: &Context, in_new_function: bool, subexpr: &ast::Expr) {
            let ty = cx.tcx.expr_ty(&*subexpr);
            if is_unrooted_ty(cx, ty, in_new_function) {
                cx.span_lint(UNROOTED_MUST_ROOT,
                             subexpr.span,
                             &format!("Expression of type {:?} must be rooted", ty))
            }
        };

        match expr.node {
            ast::ExprCast(ref subexpr, _) => require_rooted(cx, self.in_new_function, &*subexpr),
            _ => {
                // TODO(pcwalton): Check generics with a whitelist of allowed generics.
            }
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements and assignments which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let` or assignment
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        match s.node {
            ast::StmtDecl(_, id) |
            ast::StmtExpr(_, id) |
            ast::StmtSemi(_, id) if unsafe_context(&cx.tcx.map, id) => {
                return
            },
            _ => ()
        };

        let expr = match s.node {
            // Catch a `let` binding
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                    Some(ref e) => &**e,
                    _ => return
                },
                _ => return
            },
            ast::StmtExpr(ref expr, _) => match expr.node {
                // This catches deferred `let` statements
                ast::ExprAssign(_, ref e) |
                // Match statements allow you to bind onto the variable later in an arm
                // We need not check arms individually since enum/struct fields are already
                // linted in `check_struct_def` and `check_variant`
                // (so there is no way of destructuring out a `#[must_root]` field)
                ast::ExprMatch(ref e, _, _) => &**e,
                // These are able to bind local variables, but are desugared into
                // loops and matches pre-lint so should not be encountered
                ast::ExprForLoop(..) => unreachable!(),
                ast::ExprIfLet(..) => unreachable!(),
                ast::ExprWhileLet(..) => unreachable!(),
                _ => return
            },
            _ => return
        };

        let ty = cx.tcx.expr_ty(&*expr);
        if is_unrooted_ty(cx, ty, self.in_new_function) {
            cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                     &format!("Expression of type {:?} must be rooted", ty))
        }
    }
}
<|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 crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use crate::dom::bindings::codegen::Bindings::PromiseRejectionEventBinding;
use crate::dom::bindings::codegen::Bindings::PromiseRejectionEventBinding::PromiseRejectionEventMethods;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSContext};
use js::jsval::JSVal;
use js::rust::HandleValue;
use servo_atoms::Atom;
use std::rc::Rc;

#[dom_struct]
pub struct PromiseRejectionEvent {
    event: Event,
    #[ignore_malloc_size_of = "Rc"]
    promise: Rc<Promise>,
    #[ignore_malloc_size_of = "Defined in rust-mozjs"]
    reason: Heap<JSVal>,
}

impl PromiseRejectionEvent {
    #[allow(unrooted_must_root)]
    fn new_inherited(promise: Rc<Promise>) -> Self {
        PromiseRejectionEvent {
            event: Event::new_inherited(),
            promise,
            reason: Heap::default(),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &GlobalScope,
        type_: Atom,
        bubbles: EventBubbles,
        cancelable: EventCancelable,
        promise: Rc<Promise>,
        reason: HandleValue,
    ) -> DomRoot<Self> {
        let ev = reflect_dom_object(
            Box::new(PromiseRejectionEvent::new_inherited(promise)),
            global,
            PromiseRejectionEventBinding::Wrap,
        );

        {
            let event = ev.upcast::<Event>();
            event.init_event(type_, bool::from(bubbles), bool::from(cancelable));

            ev.reason.set(reason.get());
        }
        ev
    }

    #[allow(unrooted_must_root)]
    pub fn Constructor(
        global: &GlobalScope,
        type_: DOMString,
        init: RootedTraceableBox<PromiseRejectionEventBinding::PromiseRejectionEventInit>,
    ) -> Fallible<DomRoot<Self>> {
        let reason = init.reason.handle();
        let promise = match init.promise.as_ref() {
            Some(promise) => promise.clone(),
            None => Promise::new(global),
        };
        let bubbles = EventBubbles::from(init.parent.bubbles);
        let cancelable = EventCancelable::from(init.parent.cancelable);

        let event = PromiseRejectionEvent::new(
            global,
            Atom::from(type_),
            bubbles,
            cancelable,
            promise,
            reason,
        );
        Ok(event)
    }
}

impl PromiseRejectionEventMethods for PromiseRejectionEvent {
    #[allow(unrooted_must_root)]
    // https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-promise
    fn Promise(&self) -> Rc<Promise> {
        self.promise.clone()
    }

    #[allow(unsafe_code)]
    // https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-reason
    unsafe fn Reason(&self, _cx: *mut JSContext) -> JSVal {
        self.reason.get()
    }

    // https://dom.spec.whatwg.org/#dom-event-istrusted
    fn IsTrusted(&self) -> bool {
        self.event.IsTrusted()
    }
}
<commit_msg>Fail to construct if promise is none<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 crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use crate::dom::bindings::codegen::Bindings::PromiseRejectionEventBinding;
use crate::dom::bindings::codegen::Bindings::PromiseRejectionEventBinding::PromiseRejectionEventMethods;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSContext};
use js::jsval::JSVal;
use js::rust::HandleValue;
use servo_atoms::Atom;
use std::rc::Rc;

#[dom_struct]
pub struct PromiseRejectionEvent {
    event: Event,
    #[ignore_malloc_size_of = "Rc"]
    promise: Rc<Promise>,
    #[ignore_malloc_size_of = "Defined in rust-mozjs"]
    reason: Heap<JSVal>,
}

impl PromiseRejectionEvent {
    #[allow(unrooted_must_root)]
    fn new_inherited(promise: Rc<Promise>) -> Self {
        PromiseRejectionEvent {
            event: Event::new_inherited(),
            promise,
            reason: Heap::default(),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &GlobalScope,
        type_: Atom,
        bubbles: EventBubbles,
        cancelable: EventCancelable,
        promise: Rc<Promise>,
        reason: HandleValue,
    ) -> DomRoot<Self> {
        let ev = reflect_dom_object(
            Box::new(PromiseRejectionEvent::new_inherited(promise)),
            global,
            PromiseRejectionEventBinding::Wrap,
        );

        {
            let event = ev.upcast::<Event>();
            event.init_event(type_, bool::from(bubbles), bool::from(cancelable));

            ev.reason.set(reason.get());
        }
        ev
    }

    #[allow(unrooted_must_root)]
    pub fn Constructor(
        global: &GlobalScope,
        type_: DOMString,
        init: RootedTraceableBox<PromiseRejectionEventBinding::PromiseRejectionEventInit>,
    ) -> Fallible<DomRoot<Self>> {
        let reason = init.reason.handle();
        let promise = match init.promise.as_ref() {
            Some(promise) => promise.clone(),
            None => {
                return Err(Error::Type(
                    "required member promise is undefined.".to_string(),
                ))
            },
        };
        let bubbles = EventBubbles::from(init.parent.bubbles);
        let cancelable = EventCancelable::from(init.parent.cancelable);

        let event = PromiseRejectionEvent::new(
            global,
            Atom::from(type_),
            bubbles,
            cancelable,
            promise,
            reason,
        );
        Ok(event)
    }
}

impl PromiseRejectionEventMethods for PromiseRejectionEvent {
    #[allow(unrooted_must_root)]
    // https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-promise
    fn Promise(&self) -> Rc<Promise> {
        self.promise.clone()
    }

    #[allow(unsafe_code)]
    // https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-reason
    unsafe fn Reason(&self, _cx: *mut JSContext) -> JSVal {
        self.reason.get()
    }

    // https://dom.spec.whatwg.org/#dom-event-istrusted
    fn IsTrusted(&self) -> bool {
        self.event.IsTrusted()
    }
}
<|endoftext|>


<commit_before>use collections::VecDeque;
// Temporary hack until libredox get hashmaps
use redox::*;

#[derive(Clone, PartialEq, Copy, Hash)]
pub enum InsertMode {
    Append,
    Insert,
    Replace,
}

#[derive(Clone, PartialEq, Copy, Hash)]
pub struct InsertOptions {
    mode: InsertMode,
}

/// A mode
#[derive(Clone, PartialEq, Copy, Hash)]
pub enum Mode {
    /// A primitive mode (no repeat, no delimiters, no preprocessing)
    Primitive(PrimitiveMode),
    /// Command mode
    Command(CommandMode),
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A command mode
pub enum CommandMode {
//    Visual(VisualOptions),
    /// Normal mode
    Normal,
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A primitive mode
pub enum PrimitiveMode {
    /// Insert mode
    Insert(InsertOptions),
}

#[derive(Clone, PartialEq, Hash)]
pub enum Unit {
    /// Single [repeated] instruction
    Inst(u16, char),
    /// Multiple instructions
    Block(u16, Vec<Unit>),
}

#[derive(Clone, PartialEq, Hash)]
/// The state of the editor
pub struct State {
    /// The current cursor
    pub current_cursor: u8,
    /// The cursors
    pub cursors: Vec<Cursor>,
    /// The text (document)
    pub text: VecDeque<VecDeque<char>>,
    /// The x coordinate of the scroll
    pub scroll_x: u32,
    /// The y coordinate of the scroll
    pub scroll_y: u32,
}

impl State {
    fn insert(&mut self, c: char) {

    }
    fn new() -> State {
        State {
            current_cursor: 0,
            cursors: Vec::new(),
            text: VecDeque::new(),
            scroll_x: 0,
            scroll_y: 0,
        }
    }
}

/// A command char
#[derive(Clone, Copy, Hash, PartialEq)]
pub enum CommandChar {
    /// A char
    Char(char),
    /// A wildcard
    Wildcard,
}

/// The editor
pub struct Editor {
    /// The state of the editor
    pub state: State,
}

impl Editor {
    pub fn new() -> Self {
        Editor {
            state: State::new(),
        }
    }

    pub fn exec(&mut self, cmd: &Unit) {

        match *cmd {
            Unit::Inst(n, ref c) => {
                // Execute commands
            },
            Unit::Block(n, ref units) => {
                for _ in 1..n {
                    for i in units {
                        self.exec(&i);
                    }
                }
            },
        }
    }
}

#[derive(Clone, PartialEq, Hash)]
/// A cursor
pub struct Cursor {
    /// The x coordinate of the cursor
    pub x: u32,
    /// The y coordinate of the cursor
    pub y: u32,
    /// The mode of the cursor
    pub mode: Mode,
    /// The history of the cursor
    pub history: Vec<Unit>,
}

/// An iterator over units
pub struct UnitIterator<'a, I: Iterator<Item = char> + 'a> {
    /// The iterator over the chars
    char_iter: &'a mut I,
    /// The state
    state: &'a mut State,
}

impl<'a, I: Iterator<Item = char> + 'a> Iterator for UnitIterator<'a, I> {
    type Item = Unit;

    fn next(&mut self) -> Option<Unit> {
        match self.state.cursors[self.state.current_cursor as usize].mode {
            Mode::Primitive(_) => Some(Unit::Inst(1, match self.char_iter.next() {
                Some(c) => c,
                None => return None,
            })),
            Mode::Command(_) => {
                let mut ch = self.char_iter.next().unwrap_or('\0');
                let mut n = 1;

                let mut unset = true;
                for c in self.char_iter {
                    n = match c {
                        '0' if n != 0 => n * 10,
                        '1'           => n * 10 + 1,
                        '2'           => n * 10 + 2,
                        '3'           => n * 10 + 3,
                        '4'           => n * 10 + 4,
                        '5'           => n * 10 + 5,
                        '6'           => n * 10 + 6,
                        '7'           => n * 10 + 7,
                        '8'           => n * 10 + 8,
                        '9'           => n * 10 + 9,
                        r             => {
                            ch = r;
                            break;
                        },
                    };

                    if unset {
                        unset = false;
                        n     = 0;
                    }
                }

                if ch == '(' {
                    let mut level = 0;
                    let mut vec = self.char_iter.take_while(|c| {
                        level = match *c {
                            '(' => level + 1,
                            ')' => level - 1,
                            ';' => 0,
                            _ => level,
                        };
                        level != 0
                    }).skip(1).collect::<Vec<_>>();
                    vec.pop();
                    Some(Unit::Block(n, vec.into_iter().unit_iter(&mut self.state).collect()))
                } else if let Some(ch) = self.char_iter.next() {
                    Some(Unit::Inst(n, ch))
                } else {
                    None
                }
            }
        }
    }
}

pub trait ToUnitIterator<'a>: Iterator<Item = char> + 'a {
    /// Create a iterator of the unit given by the chars
    fn unit_iter(&'a mut self, state: &'a mut State) -> UnitIterator<'a, Self>;
}

impl<'a, I: Iterator<Item = char> + 'a> ToUnitIterator<'a> for I {
    fn unit_iter(&'a mut self, state: &'a mut State) -> UnitIterator<'a, I> {
        UnitIterator {
            char_iter: self,
            state: state,
        }
    }
}
<commit_msg>Simplify structure<commit_after>use collections::VecDeque;
// Temporary hack until libredox get hashmaps
use redox::*;

#[derive(Clone, PartialEq, Copy, Hash)]
pub enum InsertMode {
    Append,
    Insert,
    Replace,
}

#[derive(Clone, PartialEq, Copy, Hash)]
pub struct InsertOptions {
    mode: InsertMode,
}

/// A mode
#[derive(Clone, PartialEq, Copy, Hash)]
pub enum Mode {
    /// A primitive mode (no repeat, no delimiters, no preprocessing)
    Primitive(PrimitiveMode),
    /// Command mode
    Command(CommandMode),
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A command mode
pub enum CommandMode {
//    Visual(VisualOptions),
    /// Normal mode
    Normal,
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A primitive mode
pub enum PrimitiveMode {
    /// Insert mode
    Insert(InsertOptions),
}

#[derive(Clone, PartialEq, Hash)]
/// The state of the editor
pub struct State {
    /// The current cursor
    pub current_cursor: u8,
    /// The cursors
    pub cursors: Vec<Cursor>,
    /// The text (document)
    pub text: VecDeque<VecDeque<char>>,
    /// The x coordinate of the scroll
    pub scroll_x: u32,
    /// The y coordinate of the scroll
    pub scroll_y: u32,
    /// Number of repeation entered
    pub n: u16,
}

impl State {
    fn insert(&mut self, c: char) {

    }
    fn new() -> State {
        State {
            current_cursor: 0,
            cursors: Vec::new(),
            text: VecDeque::new(),
            scroll_x: 0,
            scroll_y: 0,
        }
    }
}

/// A command char
#[derive(Clone, Copy, Hash, PartialEq)]
pub enum CommandChar {
    /// A char
    Char(char),
    /// A wildcard
    Wildcard,
}

/// The editor
pub struct Editor {
    /// The state of the editor
    pub state: State,
}

impl Editor {
    pub fn new() -> Self {
        Editor {
            state: State::new(),
        }
    }

    /// Execute a instruction n times
    pub fn exec(&mut self, n: u16, cmd: char) {

        match cmd {

        }
    }

    /// Feed a char to the editor (as input)
    fn feed(&mut self, c: char) {
        match self.state.cursors[self.state.current_cursor as usize].mode {
            Mode::Primitive(_) => {
                self.exec(0, c);
            },
            Mode::Command(_) => {
                self.n = match c {
                    '0' if self.n != 0 => self.n * 10,
                    '1'           => self.n * 10 + 1,
                    '2'           => self.n * 10 + 2,
                    '3'           => self.n * 10 + 3,
                    '4'           => self.n * 10 + 4,
                    '5'           => self.n * 10 + 5,
                    '6'           => self.n * 10 + 6,
                    '7'           => self.n * 10 + 7,
                    '8'           => self.n * 10 + 8,
                    '9'           => self.n * 10 + 9,
                    _             => {
                        self.exec(if self.n == 0 { 1 } else { self.n }, c);
                        self.n
                    }
                }

            }
        }
    }
}

#[derive(Clone, PartialEq, Hash)]
/// A cursor
pub struct Cursor {
    /// The x coordinate of the cursor
    pub x: u32,
    /// The y coordinate of the cursor
    pub y: u32,
    /// The mode of the cursor
    pub mode: Mode,
    /// The history of the cursor
    pub history: Vec<Unit>,

<|endoftext|>