<commit_before>pub mod test_utils;
mod traits;

use slot_clock::SlotClock;
use ssz::{SignedRoot, TreeHash};
use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, Domain, Hash256, Proposal, Slot};

pub use self::traits::{
    BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer,
};

#[derive(Debug, PartialEq)]
pub enum PollOutcome {
    /// A new block was produced.
    BlockProduced(Slot),
    /// A block was not produced as it would have been slashable.
    SlashableBlockNotProduced(Slot),
    /// The validator duties did not require a block to be produced.
    BlockProductionNotRequired(Slot),
    /// The duties for the present epoch were not found.
    ProducerDutiesUnknown(Slot),
    /// The slot has already been processed, execution was skipped.
    SlotAlreadyProcessed(Slot),
    /// The Beacon Node was unable to produce a block at that slot.
    BeaconNodeUnableToProduceBlock(Slot),
    /// The signer failed to sign the message.
    SignerRejection(Slot),
    /// The public key for this validator is not an active validator.
    ValidatorIsUnknown(Slot),
    /// Unable to determine a `Fork` for signature domain generation.
    UnableToGetFork(Slot),
}

#[derive(Debug, PartialEq)]
pub enum Error {
    SlotClockError,
    SlotUnknowable,
    EpochMapPoisoned,
    SlotClockPoisoned,
    EpochLengthIsZero,
    BeaconNodeError(BeaconNodeError),
}

/// A polling state machine which performs block production duties, based upon some epoch duties
/// (`EpochDutiesMap`) and a concept of time (`SlotClock`).
///
/// Ensures that messages are not slashable.
///
/// Relies upon an external service to keep the `EpochDutiesMap` updated.
pub struct BlockProducer<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> {
    pub last_processed_slot: Option<Slot>,
    spec: Arc<ChainSpec>,
    epoch_map: Arc<V>,
    slot_clock: Arc<T>,
    beacon_node: Arc<U>,
    signer: Arc<W>,
}

impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U, V, W> {
    /// Returns a new instance where `last_processed_slot == 0`.
    pub fn new(
        spec: Arc<ChainSpec>,
        epoch_map: Arc<V>,
        slot_clock: Arc<T>,
        beacon_node: Arc<U>,
        signer: Arc<W>,
    ) -> Self {
        Self {
            last_processed_slot: None,
            spec,
            epoch_map,
            slot_clock,
            beacon_node,
            signer,
        }
    }
}

impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U, V, W> {
    /// "Poll" to see if the validator is required to take any action.
    ///
    /// The slot clock will be read and any new actions undertaken.
    pub fn poll(&mut self) -> Result<PollOutcome, Error> {
        let slot = self
            .slot_clock
            .present_slot()
            .map_err(|_| Error::SlotClockError)?
            .ok_or(Error::SlotUnknowable)?;

        // If this is a new slot.
        if !self.is_processed_slot(slot) {
            let is_block_production_slot = match self.epoch_map.is_block_production_slot(slot) {
                Ok(result) => result,
                Err(DutiesReaderError::UnknownEpoch) => {
                    return Ok(PollOutcome::ProducerDutiesUnknown(slot));
                }
                Err(DutiesReaderError::UnknownValidator) => {
                    return Ok(PollOutcome::ValidatorIsUnknown(slot));
                }
                Err(DutiesReaderError::EpochLengthIsZero) => return Err(Error::EpochLengthIsZero),
                Err(DutiesReaderError::Poisoned) => return Err(Error::EpochMapPoisoned),
            };

            if is_block_production_slot {
                self.last_processed_slot = Some(slot);

                self.produce_block(slot)
            } else {
                Ok(PollOutcome::BlockProductionNotRequired(slot))
            }
        } else {
            Ok(PollOutcome::SlotAlreadyProcessed(slot))
        }
    }

    fn is_processed_slot(&self, slot: Slot) -> bool {
        match self.last_processed_slot {
            Some(processed_slot) if processed_slot >= slot => true,
            _ => false,
        }
    }

    /// Produce a block at some slot.
    ///
    /// Assumes that a block is required at this slot (does not check the duties).
    ///
    /// Ensures the message is not slashable.
    ///
    /// !!! UNSAFE !!!
    ///
    /// The slash-protection code is not yet implemented. There is zero protection against
    /// slashing.
    fn produce_block(&mut self, slot: Slot) -> Result<PollOutcome, Error> {
        let fork = match self.epoch_map.fork() {
            Ok(fork) => fork,
            Err(_) => return Ok(PollOutcome::UnableToGetFork(slot)),
        };

        let randao_reveal = {
            // TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`.
            let message = slot.epoch(self.spec.slots_per_epoch).hash_tree_root();

            match self.signer.sign_randao_reveal(
                &message,
                self.spec
                    .get_domain(slot.epoch(self.spec.slots_per_epoch), Domain::Randao, &fork),
            ) {
                None => return Ok(PollOutcome::SignerRejection(slot)),
                Some(signature) => signature,
            }
        };

        if let Some(block) = self
            .beacon_node
            .produce_beacon_block(slot, &randao_reveal)?
        {
            if self.safe_to_produce(&block) {
                let domain = self.spec.get_domain(
                    slot.epoch(self.spec.slots_per_epoch),
                    Domain::Proposal,
                    &fork,
                );
                if let Some(block) = self.sign_block(block, domain) {
                    self.beacon_node.publish_beacon_block(block)?;
                    Ok(PollOutcome::BlockProduced(slot))
                } else {
                    Ok(PollOutcome::SignerRejection(slot))
                }
            } else {
                Ok(PollOutcome::SlashableBlockNotProduced(slot))
            }
        } else {
            Ok(PollOutcome::BeaconNodeUnableToProduceBlock(slot))
        }
    }

    /// Consumes a block, returning that block signed by the validators private key.
    ///
    /// Important: this function will not check to ensure the block is not slashable. This must be
    /// done upstream.
    fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option<BeaconBlock> {
        self.store_produce(&block);

        let proposal = Proposal {
            slot: block.slot,
            shard: self.spec.beacon_chain_shard_number,
            block_root: Hash256::from_slice(&block.signed_root()[..]),
            signature: block.signature.clone(),
        };

        match self
            .signer
            .sign_block_proposal(&proposal.signed_root()[..], domain)
        {
            None => None,
            Some(signature) => {
                block.signature = signature;
                Some(block)
            }
        }
    }

    /// Returns `true` if signing a block is safe (non-slashable).
    ///
    /// !!! UNSAFE !!!
    ///
    /// Important: this function is presently stubbed-out. It provides ZERO SAFETY.
    fn safe_to_produce(&self, _block: &BeaconBlock) -> bool {
        // TODO: ensure the producer doesn't produce slashable blocks.
        // https://github.com/sigp/lighthouse/issues/160
        true
    }

    /// Record that a block was produced so that slashable votes may not be made in the future.
    ///
    /// !!! UNSAFE !!!
    ///
    /// Important: this function is presently stubbed-out. It provides ZERO SAFETY.
    fn store_produce(&mut self, _block: &BeaconBlock) {
        // TODO: record this block production to prevent future slashings.
        // https://github.com/sigp/lighthouse/issues/160
    }
}

impl From<BeaconNodeError> for Error {
    fn from(e: BeaconNodeError) -> Error {
        Error::BeaconNodeError(e)
    }
}

#[cfg(test)]
mod tests {
    use super::test_utils::{EpochMap, LocalSigner, SimulatedBeaconNode};
    use super::*;
    use slot_clock::TestingSlotClock;
    use types::{
        test_utils::{SeedableRng, TestRandom, XorShiftRng},
        Keypair,
    };

    // TODO: implement more thorough testing.
    // https://github.com/sigp/lighthouse/issues/160
    //
    // These tests should serve as a good example for future tests.

    #[test]
    pub fn polling() {
        let mut rng = XorShiftRng::from_seed([42; 16]);

        let spec = Arc::new(ChainSpec::foundation());
        let slot_clock = Arc::new(TestingSlotClock::new(0));
        let beacon_node = Arc::new(SimulatedBeaconNode::default());
        let signer = Arc::new(LocalSigner::new(Keypair::random()));

        let mut epoch_map = EpochMap::new(spec.slots_per_epoch);
        let produce_slot = Slot::new(100);
        let produce_epoch = produce_slot.epoch(spec.slots_per_epoch);
        epoch_map.map.insert(produce_epoch, produce_slot);
        let epoch_map = Arc::new(epoch_map);

        let mut block_proposer = BlockProducer::new(
            spec.clone(),
            epoch_map.clone(),
            slot_clock.clone(),
            beacon_node.clone(),
            signer.clone(),
        );

        // Configure responses from the BeaconNode.
        beacon_node.set_next_produce_result(Ok(Some(BeaconBlock::random_for_test(&mut rng))));
        beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidBlock));

        // One slot before production slot...
        slot_clock.set_slot(produce_slot.as_u64() - 1);
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::BlockProductionNotRequired(produce_slot - 1))
        );

        // On the produce slot...
        slot_clock.set_slot(produce_slot.as_u64());
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::BlockProduced(produce_slot.into()))
        );

        // Trying the same produce slot again...
        slot_clock.set_slot(produce_slot.as_u64());
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::SlotAlreadyProcessed(produce_slot))
        );

        // One slot after the produce slot...
        slot_clock.set_slot(produce_slot.as_u64() + 1);
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::BlockProductionNotRequired(produce_slot + 1))
        );

        // In an epoch without known duties...
        let slot = (produce_epoch.as_u64() + 1) * spec.slots_per_epoch;
        slot_clock.set_slot(slot);
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::ProducerDutiesUnknown(Slot::new(slot)))
        );
    }
}
<commit_msg>Update block proposer to v0.5.0<commit_after>pub mod test_utils;
mod traits;

use slot_clock::SlotClock;
use ssz::{SignedRoot, TreeHash};
use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, Domain, Slot};

pub use self::traits::{
    BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer,
};

#[derive(Debug, PartialEq)]
pub enum PollOutcome {
    /// A new block was produced.
    BlockProduced(Slot),
    /// A block was not produced as it would have been slashable.
    SlashableBlockNotProduced(Slot),
    /// The validator duties did not require a block to be produced.
    BlockProductionNotRequired(Slot),
    /// The duties for the present epoch were not found.
    ProducerDutiesUnknown(Slot),
    /// The slot has already been processed, execution was skipped.
    SlotAlreadyProcessed(Slot),
    /// The Beacon Node was unable to produce a block at that slot.
    BeaconNodeUnableToProduceBlock(Slot),
    /// The signer failed to sign the message.
    SignerRejection(Slot),
    /// The public key for this validator is not an active validator.
    ValidatorIsUnknown(Slot),
    /// Unable to determine a `Fork` for signature domain generation.
    UnableToGetFork(Slot),
}

#[derive(Debug, PartialEq)]
pub enum Error {
    SlotClockError,
    SlotUnknowable,
    EpochMapPoisoned,
    SlotClockPoisoned,
    EpochLengthIsZero,
    BeaconNodeError(BeaconNodeError),
}

/// A polling state machine which performs block production duties, based upon some epoch duties
/// (`EpochDutiesMap`) and a concept of time (`SlotClock`).
///
/// Ensures that messages are not slashable.
///
/// Relies upon an external service to keep the `EpochDutiesMap` updated.
pub struct BlockProducer<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> {
    pub last_processed_slot: Option<Slot>,
    spec: Arc<ChainSpec>,
    epoch_map: Arc<V>,
    slot_clock: Arc<T>,
    beacon_node: Arc<U>,
    signer: Arc<W>,
}

impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U, V, W> {
    /// Returns a new instance where `last_processed_slot == 0`.
    pub fn new(
        spec: Arc<ChainSpec>,
        epoch_map: Arc<V>,
        slot_clock: Arc<T>,
        beacon_node: Arc<U>,
        signer: Arc<W>,
    ) -> Self {
        Self {
            last_processed_slot: None,
            spec,
            epoch_map,
            slot_clock,
            beacon_node,
            signer,
        }
    }
}

impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U, V, W> {
    /// "Poll" to see if the validator is required to take any action.
    ///
    /// The slot clock will be read and any new actions undertaken.
    pub fn poll(&mut self) -> Result<PollOutcome, Error> {
        let slot = self
            .slot_clock
            .present_slot()
            .map_err(|_| Error::SlotClockError)?
            .ok_or(Error::SlotUnknowable)?;

        // If this is a new slot.
        if !self.is_processed_slot(slot) {
            let is_block_production_slot = match self.epoch_map.is_block_production_slot(slot) {
                Ok(result) => result,
                Err(DutiesReaderError::UnknownEpoch) => {
                    return Ok(PollOutcome::ProducerDutiesUnknown(slot));
                }
                Err(DutiesReaderError::UnknownValidator) => {
                    return Ok(PollOutcome::ValidatorIsUnknown(slot));
                }
                Err(DutiesReaderError::EpochLengthIsZero) => return Err(Error::EpochLengthIsZero),
                Err(DutiesReaderError::Poisoned) => return Err(Error::EpochMapPoisoned),
            };

            if is_block_production_slot {
                self.last_processed_slot = Some(slot);

                self.produce_block(slot)
            } else {
                Ok(PollOutcome::BlockProductionNotRequired(slot))
            }
        } else {
            Ok(PollOutcome::SlotAlreadyProcessed(slot))
        }
    }

    fn is_processed_slot(&self, slot: Slot) -> bool {
        match self.last_processed_slot {
            Some(processed_slot) if processed_slot >= slot => true,
            _ => false,
        }
    }

    /// Produce a block at some slot.
    ///
    /// Assumes that a block is required at this slot (does not check the duties).
    ///
    /// Ensures the message is not slashable.
    ///
    /// !!! UNSAFE !!!
    ///
    /// The slash-protection code is not yet implemented. There is zero protection against
    /// slashing.
    fn produce_block(&mut self, slot: Slot) -> Result<PollOutcome, Error> {
        let fork = match self.epoch_map.fork() {
            Ok(fork) => fork,
            Err(_) => return Ok(PollOutcome::UnableToGetFork(slot)),
        };

        let randao_reveal = {
            // TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`.
            let message = slot.epoch(self.spec.slots_per_epoch).hash_tree_root();

            match self.signer.sign_randao_reveal(
                &message,
                self.spec
                    .get_domain(slot.epoch(self.spec.slots_per_epoch), Domain::Randao, &fork),
            ) {
                None => return Ok(PollOutcome::SignerRejection(slot)),
                Some(signature) => signature,
            }
        };

        if let Some(block) = self
            .beacon_node
            .produce_beacon_block(slot, &randao_reveal)?
        {
            if self.safe_to_produce(&block) {
                let domain = self.spec.get_domain(
                    slot.epoch(self.spec.slots_per_epoch),
                    Domain::BeaconBlock,
                    &fork,
                );
                if let Some(block) = self.sign_block(block, domain) {
                    self.beacon_node.publish_beacon_block(block)?;
                    Ok(PollOutcome::BlockProduced(slot))
                } else {
                    Ok(PollOutcome::SignerRejection(slot))
                }
            } else {
                Ok(PollOutcome::SlashableBlockNotProduced(slot))
            }
        } else {
            Ok(PollOutcome::BeaconNodeUnableToProduceBlock(slot))
        }
    }

    /// Consumes a block, returning that block signed by the validators private key.
    ///
    /// Important: this function will not check to ensure the block is not slashable. This must be
    /// done upstream.
    fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option<BeaconBlock> {
        self.store_produce(&block);

        match self
            .signer
            .sign_block_proposal(&block.signed_root()[..], domain)
        {
            None => None,
            Some(signature) => {
                block.signature = signature;
                Some(block)
            }
        }
    }

    /// Returns `true` if signing a block is safe (non-slashable).
    ///
    /// !!! UNSAFE !!!
    ///
    /// Important: this function is presently stubbed-out. It provides ZERO SAFETY.
    fn safe_to_produce(&self, _block: &BeaconBlock) -> bool {
        // TODO: ensure the producer doesn't produce slashable blocks.
        // https://github.com/sigp/lighthouse/issues/160
        true
    }

    /// Record that a block was produced so that slashable votes may not be made in the future.
    ///
    /// !!! UNSAFE !!!
    ///
    /// Important: this function is presently stubbed-out. It provides ZERO SAFETY.
    fn store_produce(&mut self, _block: &BeaconBlock) {
        // TODO: record this block production to prevent future slashings.
        // https://github.com/sigp/lighthouse/issues/160
    }
}

impl From<BeaconNodeError> for Error {
    fn from(e: BeaconNodeError) -> Error {
        Error::BeaconNodeError(e)
    }
}

#[cfg(test)]
mod tests {
    use super::test_utils::{EpochMap, LocalSigner, SimulatedBeaconNode};
    use super::*;
    use slot_clock::TestingSlotClock;
    use types::{
        test_utils::{SeedableRng, TestRandom, XorShiftRng},
        Keypair,
    };

    // TODO: implement more thorough testing.
    // https://github.com/sigp/lighthouse/issues/160
    //
    // These tests should serve as a good example for future tests.

    #[test]
    pub fn polling() {
        let mut rng = XorShiftRng::from_seed([42; 16]);

        let spec = Arc::new(ChainSpec::foundation());
        let slot_clock = Arc::new(TestingSlotClock::new(0));
        let beacon_node = Arc::new(SimulatedBeaconNode::default());
        let signer = Arc::new(LocalSigner::new(Keypair::random()));

        let mut epoch_map = EpochMap::new(spec.slots_per_epoch);
        let produce_slot = Slot::new(100);
        let produce_epoch = produce_slot.epoch(spec.slots_per_epoch);
        epoch_map.map.insert(produce_epoch, produce_slot);
        let epoch_map = Arc::new(epoch_map);

        let mut block_proposer = BlockProducer::new(
            spec.clone(),
            epoch_map.clone(),
            slot_clock.clone(),
            beacon_node.clone(),
            signer.clone(),
        );

        // Configure responses from the BeaconNode.
        beacon_node.set_next_produce_result(Ok(Some(BeaconBlock::random_for_test(&mut rng))));
        beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidBlock));

        // One slot before production slot...
        slot_clock.set_slot(produce_slot.as_u64() - 1);
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::BlockProductionNotRequired(produce_slot - 1))
        );

        // On the produce slot...
        slot_clock.set_slot(produce_slot.as_u64());
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::BlockProduced(produce_slot.into()))
        );

        // Trying the same produce slot again...
        slot_clock.set_slot(produce_slot.as_u64());
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::SlotAlreadyProcessed(produce_slot))
        );

        // One slot after the produce slot...
        slot_clock.set_slot(produce_slot.as_u64() + 1);
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::BlockProductionNotRequired(produce_slot + 1))
        );

        // In an epoch without known duties...
        let slot = (produce_epoch.as_u64() + 1) * spec.slots_per_epoch;
        slot_clock.set_slot(slot);
        assert_eq!(
            block_proposer.poll(),
            Ok(PollOutcome::ProducerDutiesUnknown(Slot::new(slot)))
        );
    }
}
<|endoftext|>


<commit_before>use super::{BaseNum, PartialOrd};
use num_traits::NumCast;
use std::ops::Mul;

/// A two-dimensional dimension.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Dimension2<T: BaseNum> {
    pub width: T,
    pub height: T,
}

pub type Dimension2f = Dimension2<super::DefaultFloat>;
pub type Dimension2i = Dimension2<super::DefaultInt>;
pub type Dimension2u = Dimension2<super::DefaultUnsigned>;

impl<T: BaseNum + NumCast> Dimension2<T> {
    pub fn new(width: T, height: T) -> Self {
        Dimension2 {
            width: width,
            height: height,
        }
    }
    /// Returns the area of a `Dimension`
    pub fn area(&self) -> <T as Mul>::Output {
        self.width * self.height
    }
    /// Scales the `Dimension2` with a scalar
    pub fn scale(&self, scale: T) -> Dimension2<T> {
        Dimension2 {
            width: self.width * scale,
            height: self.height * scale,
        }
    }
    /// Calculates the aspect ratio of a `Dimension`
    pub fn aspect_ratio(&self) -> f32 {
        assert!(!self.height.is_zero());
        self.width.to_f32().unwrap() / self.height.to_f32().unwrap()
    }
    /// Shrinks a `Dimension` until it fits into another `Dimension`
    pub fn fitting(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_min(other.width / self.width, other.height / self.height);
        self.scale(scale)
    }
    /// Expands a `Dimension` until it fills another `Dimension`
    pub fn filling(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_max(other.width / self.width, other.height / self.height);
        self.scale(scale)
    }
}

#[test]
fn test_area() {
    let test1 = Dimension2::new(3, 5);
    let test2 = Dimension2::new(0, 0);

    assert_eq!(test2.area(), 0);
    assert_eq!(test1.area(), 15);
}
#[test]
fn test_scale() {
    let test1 = Dimension2::new(3, 5);
    let test2 = Dimension2::new(12, 20);

    assert_eq!(test1.scale(4).width, 12);
    assert_eq!(test2.scale(0).width, 0);
}
#[test]
fn test_aspect_ratio() {
    let test1 = Dimension2::new(3, 5);

    assert_eq!(test1.aspect_ratio(), 3 / 5);
}
#[test]
fn test_fitting() {
    let test1 = Dimension2::new(2.0, 1.0);
    let test2 = Dimension2::new(4.0, 3.0);

    assert_eq!(test2.fitting(test1), Dimension2::new(4.0 / 3.0, 1.0));
}
#[test]
fn test_filling() {
    let test1 = Dimension2::new(2.0, 1.0);
    let test2 = Dimension2::new(4.0, 3.0);

    assert_eq!(test1.filling(test2), Dimension2::new(6.0, 3.0));
}
<commit_msg>adjust dimension tests to reflect new 'aspect_ratio' return type<commit_after>use super::{BaseNum, PartialOrd};
use num_traits::NumCast;
use std::ops::Mul;

/// A two-dimensional dimension.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Dimension2<T: BaseNum> {
    pub width: T,
    pub height: T,
}

pub type Dimension2f = Dimension2<super::DefaultFloat>;
pub type Dimension2i = Dimension2<super::DefaultInt>;
pub type Dimension2u = Dimension2<super::DefaultUnsigned>;

impl<T: BaseNum + NumCast> Dimension2<T> {
    pub fn new(width: T, height: T) -> Self {
        Dimension2 {
            width: width,
            height: height,
        }
    }
    /// Returns the area of a `Dimension`
    pub fn area(&self) -> <T as Mul>::Output {
        self.width * self.height
    }
    /// Scales the `Dimension2` with a scalar
    pub fn scale(&self, scale: T) -> Dimension2<T> {
        Dimension2 {
            width: self.width * scale,
            height: self.height * scale,
        }
    }
    /// Calculates the aspect ratio of a `Dimension`
    pub fn aspect_ratio(&self) -> f32 {
        assert!(!self.height.is_zero());
        self.width.to_f32().unwrap() / self.height.to_f32().unwrap()
    }
    /// Shrinks a `Dimension` until it fits into another `Dimension`
    pub fn fitting(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_min(other.width / self.width, other.height / self.height);
        self.scale(scale)
    }
    /// Expands a `Dimension` until it fills another `Dimension`
    pub fn filling(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_max(other.width / self.width, other.height / self.height);
        self.scale(scale)
    }
}

#[test]
fn test_area() {
    let test1 = Dimension2::new(3, 5);
    let test2 = Dimension2::new(0, 0);

    assert_eq!(test2.area(), 0);
    assert_eq!(test1.area(), 15);
}
#[test]
fn test_scale() {
    let test1 = Dimension2::new(3, 5);
    let test2 = Dimension2::new(12, 20);

    assert_eq!(test1.scale(4).width, 12);
    assert_eq!(test2.scale(0).width, 0);
}
#[test]
fn test_aspect_ratio() {
    let test1 = Dimension2::new(3, 5);

    assert_eq!(test1.aspect_ratio(), 3.0 / 5.0);
}
#[test]
fn test_fitting() {
    let test1 = Dimension2::new(2.0, 1.0);
    let test2 = Dimension2::new(4.0, 3.0);

    assert_eq!(test2.fitting(test1), Dimension2::new(4.0 / 3.0, 1.0));
}
#[test]
fn test_filling() {
    let test1 = Dimension2::new(2.0, 1.0);
    let test2 = Dimension2::new(4.0, 3.0);

    assert_eq!(test1.filling(test2), Dimension2::new(6.0, 3.0));
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod bench {
	use test::Bencher;
	use basic_dsp::{
        TimeDomainOperations,
        FrequencyDomainOperations,
		DataVector32};
    use tools::VectorBox;
    use basic_dsp::window_functions::TriangularWindow;

	#[bench]
	fn plain_fft_ifft_32_benchmark(b: &mut Bencher)
	{
		let mut vector = VectorBox::<DataVector32>::with_size(true, 10000);
		b.iter(|| {
			vector.execute_res(|v|
            {
                v.plain_fft()
                .and_then(|v|v.plain_ifft())
            } )
		});
	}

    #[bench]
	fn window_32_benchmark(b: &mut Bencher)
	{
		let mut vector = VectorBox::<DataVector32>::with_size(true, 10000);
		b.iter(|| {
			vector.execute_res(|v|
            {
                let triag = TriangularWindow;
                v.apply_window(&triag)
            } )
		});
	}
}<commit_msg>Added a fft/ifft benchmark<commit_after>#[cfg(test)]
mod bench {
	use test::Bencher;
	use basic_dsp::{
        DataVector,
        TimeDomainOperations,
        FrequencyDomainOperations,
		DataVector32,
        DataVectorDomain};
    use tools::VectorBox;
    use basic_dsp::window_functions::TriangularWindow;

	#[bench]
	fn plain_fft_ifft_32t_benchmark(b: &mut Bencher)
	{
		let mut vector = VectorBox::<DataVector32>::with_size(true, 2000);
		b.iter(|| {
			vector.execute_res(|v|
            {
                if v.domain() == DataVectorDomain::Time {
                    v.plain_fft()
                } else {
                    v.plain_ifft()
                }
            } )
		});
	}

    #[bench]
	fn window_32t_benchmark(b: &mut Bencher)
	{
		let mut vector = VectorBox::<DataVector32>::with_size(true, 2000);
		b.iter(|| {
			vector.execute_res(|v|
            {
                let triag = TriangularWindow;
                v.apply_window(&triag)
            } )
		});
	}

    #[bench]
	fn fft_ifft_32t_benchmark(b: &mut Bencher)
	{
		let mut vector = VectorBox::<DataVector32>::with_size(true, 2000);
		b.iter(|| {
			vector.execute_res(|v|
            {
                if v.domain() == DataVectorDomain::Time {
                    v.fft()
                } else {
                    v.ifft()
                }
            } )
		});
	}
}<|endoftext|>


<commit_before>//! Compiler plugin for Rust-PHF
//!
//! See the documentation for the `phf` crate for more details.
#[crate_id="github.com/sfackler/rust-phf/phf_mac"];
#[crate_type="lib"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[feature(managed_boxes, macro_registrar)];

extern mod extra;
extern mod syntax;
extern mod phf;

use extra::time;
use std::hashmap::HashMap;
use std::rand;
use std::os;
use std::vec;
use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        SyntaxExpanderTT,
                        SyntaxExpanderTTExpanderWithoutContext};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{COMMA, EOF, FAT_ARROW};

static DEFAULT_LAMBDA: uint = 5;

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~SyntaxExpanderTT {
                expander: SyntaxExpanderTTExpanderWithoutContext(expand_mphf_map),
                span: None
             },
             None));
}

struct Entry {
    key_str: @str,
    key: @Expr,
    value: @Expr
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_owned());
    let mut entries = ~[];

    let mut bad = false;
    while parser.token != EOF {
        let key = parser.parse_expr();

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(s, _) => s,
                    _ => {
                        cx.span_err(key.span, "expected string literal");
                        bad = true;
                        @""
                    }
                }
            }
            _ => {
                cx.span_err(key.span, "expected string literal");
                bad = true;
                @""
            }
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_err(parser.span, "expected `=>`");
            return MacResult::dummy_expr();
        }

        let value = parser.parse_expr();

        entries.push(Entry {
            key_str: key_str,
            key: key,
            value: value
        });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return MacResult::dummy_expr();
        }
    }

    if entries.len() > phf::MAX_SIZE {
        cx.span_err(parser.span,
                    format!("maps with more than {} items are not supported",
                            phf::MAX_SIZE));
        return MacResult::dummy_expr();
    }

    if bad {
        return MacResult::dummy_expr();
    }

    entries.sort_by(|a, b| a.key_str.cmp(&b.key_str));
    if check_for_duplicates(cx, sp, entries) {
        return MacResult::dummy_expr();
    }

    let start = time::precise_time_s();
    let state;
    loop {
        match generate_hash(entries) {
            Some(s) => {
                state = s;
                break;
            }
            None => {}
        }
    }
    let time = time::precise_time_s() - start;
    if (os::getenv("PHF_STATS").is_some()) {
        cx.parse_sess().span_diagnostic.span_note(sp, format!("PHF generation took {} seconds", time));
    }

    let len = entries.len();
    let k1 = state.k1;
    let k2 = state.k2;
    let disps = state.disps.iter().map(|&(d1, d2)| {
            quote_expr!(&*cx, ($d1, $d2))
        }).collect();
    let disps = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(disps, MutImmutable),
        span: sp,
    };
    let entries = state.map.iter().map(|&idx| {
            match idx {
                Some(idx) => {
                    let Entry { key, value, .. } = entries[idx];
                    quote_expr!(&*cx, Some(($key, $value)))
                }
                None => quote_expr!(&*cx, None),
            }
        }).collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap {
        len: $len,
        k1: $k1,
        k2: $k2,
        disps: &'static $disps,
        entries: &'static $entries,
    }))
}

fn check_for_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool {
    let mut dups = false;
    let mut in_dup = false;
    for window in entries.windows(2) {
        let ref a = window[0];
        let ref b = window[1];
        if a.key_str == b.key_str {
            dups = true;
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a.key_str));
                cx.span_note(a.key.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_note(b.key.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }

    dups
}

struct HashState {
    k1: u64,
    k2: u64,
    disps: ~[(uint, uint)],
    map: ~[Option<uint>],
}

fn generate_hash(entries: &[Entry]) -> Option<HashState> {
    struct Bucket {
        idx: uint,
        keys: ~[uint],
    }

    struct Hashes {
        g: uint,
        f1: uint,
        f2: uint,
    }

    let k1 = rand::random();
    let k2 = rand::random();

    let hashes = entries.iter().map(|entry| {
            let (g, f1, f2) = phf::hash(entry.key_str, k1, k2);
            Hashes {
                g: g,
                f1: f1,
                f2: f2
            }
        }).to_owned_vec();

    let buckets_len = (entries.len() + DEFAULT_LAMBDA - 1) / DEFAULT_LAMBDA;
    let mut buckets = vec::from_fn(buckets_len,
                                   |i| Bucket { idx: i, keys: ~[] });

    for (i, hash) in hashes.iter().enumerate() {
        buckets[hash.g % buckets_len].keys.push(i);
    }

    // Sort descending
    buckets.sort_by(|a, b| b.keys.len().cmp(&a.keys.len()));

    let table_len = entries.len();
    let mut map = vec::from_elem(table_len, None);
    let mut disps = vec::from_elem(buckets_len, None);
    let mut try_map = HashMap::new();
    'buckets: for bucket in buckets.iter() {
        for d1 in range(0, table_len) {
            'disps: for d2 in range(0, table_len) {
                try_map.clear();
                for &key in bucket.keys.iter() {
                    let idx = phf::displace(hashes[key].f1, hashes[key].f2,
                                            d1, d2) % table_len;
                    if try_map.find(&idx).is_some() || map[idx].is_some() {
                        continue 'disps;
                    }
                    try_map.insert(idx, key);
                }

                // We've picked a good set of disps
                disps[bucket.idx] = Some((d1, d2));
                for (&idx, &key) in try_map.iter() {
                    map[idx] = Some(key);
                }
                continue 'buckets;
            }
        }

        // Unable to find displacements for a bucket
        return None;
    }

    let disps = disps.move_iter().map(|i| i.expect("should have a bucket")).collect();

    Some(HashState {
        k1: k1,
        k2: k2,
        disps: disps,
        map: map,
    })
}
<commit_msg>Removed unneeded parentheses<commit_after>//! Compiler plugin for Rust-PHF
//!
//! See the documentation for the `phf` crate for more details.
#[crate_id="github.com/sfackler/rust-phf/phf_mac"];
#[crate_type="lib"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[feature(managed_boxes, macro_registrar)];

extern mod extra;
extern mod syntax;
extern mod phf;

use extra::time;
use std::hashmap::HashMap;
use std::rand;
use std::os;
use std::vec;
use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        SyntaxExpanderTT,
                        SyntaxExpanderTTExpanderWithoutContext};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{COMMA, EOF, FAT_ARROW};

static DEFAULT_LAMBDA: uint = 5;

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~SyntaxExpanderTT {
                expander: SyntaxExpanderTTExpanderWithoutContext(expand_mphf_map),
                span: None
             },
             None));
}

struct Entry {
    key_str: @str,
    key: @Expr,
    value: @Expr
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_owned());
    let mut entries = ~[];

    let mut bad = false;
    while parser.token != EOF {
        let key = parser.parse_expr();

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(s, _) => s,
                    _ => {
                        cx.span_err(key.span, "expected string literal");
                        bad = true;
                        @""
                    }
                }
            }
            _ => {
                cx.span_err(key.span, "expected string literal");
                bad = true;
                @""
            }
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_err(parser.span, "expected `=>`");
            return MacResult::dummy_expr();
        }

        let value = parser.parse_expr();

        entries.push(Entry {
            key_str: key_str,
            key: key,
            value: value
        });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return MacResult::dummy_expr();
        }
    }

    if entries.len() > phf::MAX_SIZE {
        cx.span_err(parser.span,
                    format!("maps with more than {} items are not supported",
                            phf::MAX_SIZE));
        return MacResult::dummy_expr();
    }

    if bad {
        return MacResult::dummy_expr();
    }

    entries.sort_by(|a, b| a.key_str.cmp(&b.key_str));
    if check_for_duplicates(cx, sp, entries) {
        return MacResult::dummy_expr();
    }

    let start = time::precise_time_s();
    let state;
    loop {
        match generate_hash(entries) {
            Some(s) => {
                state = s;
                break;
            }
            None => {}
        }
    }
    let time = time::precise_time_s() - start;
    if os::getenv("PHF_STATS").is_some() {
        cx.parse_sess().span_diagnostic.span_note(sp, format!("PHF generation took {} seconds", time));
    }

    let len = entries.len();
    let k1 = state.k1;
    let k2 = state.k2;
    let disps = state.disps.iter().map(|&(d1, d2)| {
            quote_expr!(&*cx, ($d1, $d2))
        }).collect();
    let disps = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(disps, MutImmutable),
        span: sp,
    };
    let entries = state.map.iter().map(|&idx| {
            match idx {
                Some(idx) => {
                    let Entry { key, value, .. } = entries[idx];
                    quote_expr!(&*cx, Some(($key, $value)))
                }
                None => quote_expr!(&*cx, None),
            }
        }).collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap {
        len: $len,
        k1: $k1,
        k2: $k2,
        disps: &'static $disps,
        entries: &'static $entries,
    }))
}

fn check_for_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool {
    let mut dups = false;
    let mut in_dup = false;
    for window in entries.windows(2) {
        let ref a = window[0];
        let ref b = window[1];
        if a.key_str == b.key_str {
            dups = true;
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a.key_str));
                cx.span_note(a.key.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_note(b.key.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }

    dups
}

struct HashState {
    k1: u64,
    k2: u64,
    disps: ~[(uint, uint)],
    map: ~[Option<uint>],
}

fn generate_hash(entries: &[Entry]) -> Option<HashState> {
    struct Bucket {
        idx: uint,
        keys: ~[uint],
    }

    struct Hashes {
        g: uint,
        f1: uint,
        f2: uint,
    }

    let k1 = rand::random();
    let k2 = rand::random();

    let hashes = entries.iter().map(|entry| {
            let (g, f1, f2) = phf::hash(entry.key_str, k1, k2);
            Hashes {
                g: g,
                f1: f1,
                f2: f2
            }
        }).to_owned_vec();

    let buckets_len = (entries.len() + DEFAULT_LAMBDA - 1) / DEFAULT_LAMBDA;
    let mut buckets = vec::from_fn(buckets_len,
                                   |i| Bucket { idx: i, keys: ~[] });

    for (i, hash) in hashes.iter().enumerate() {
        buckets[hash.g % buckets_len].keys.push(i);
    }

    // Sort descending
    buckets.sort_by(|a, b| b.keys.len().cmp(&a.keys.len()));

    let table_len = entries.len();
    let mut map = vec::from_elem(table_len, None);
    let mut disps = vec::from_elem(buckets_len, None);
    let mut try_map = HashMap::new();
    'buckets: for bucket in buckets.iter() {
        for d1 in range(0, table_len) {
            'disps: for d2 in range(0, table_len) {
                try_map.clear();
                for &key in bucket.keys.iter() {
                    let idx = phf::displace(hashes[key].f1, hashes[key].f2,
                                            d1, d2) % table_len;
                    if try_map.find(&idx).is_some() || map[idx].is_some() {
                        continue 'disps;
                    }
                    try_map.insert(idx, key);
                }

                // We've picked a good set of disps
                disps[bucket.idx] = Some((d1, d2));
                for (&idx, &key) in try_map.iter() {
                    map[idx] = Some(key);
                }
                continue 'buckets;
            }
        }

        // Unable to find displacements for a bucket
        return None;
    }

    let disps = disps.move_iter().map(|i| i.expect("should have a bucket")).collect();

    Some(HashState {
        k1: k1,
        k2: k2,
        disps: disps,
        map: map,
    })
}
<|endoftext|>


<commit_before>use ast::{self, Name};
use attr::{self, AttrMetaMethods, HasAttrs};
use codemap::{ExpnInfo, MacroAttribute, NameAndSpan};
use ext::base::*;
use ext::build::AstBuilder;
use ext::expand::{MacroExpander, expand_multi_modified};
use parse::token::intern;
use util::small_vector::SmallVector;

pub fn expand_annotatable(
    mut item: Annotatable,
    fld: &mut MacroExpander,
) -> SmallVector<Annotatable> {
    let mut out_items = SmallVector::zero();
    let mut new_attrs = Vec::new();

    item = expand_1(item, fld, &mut out_items, &mut new_attrs);

    item = item.fold_attrs(new_attrs);
    let expanded = expand_multi_modified(item, fld);
    out_items.push_all(expanded);

    out_items
}

// Responsible for expanding `cfg_attr` and delegating to expand_2.
//
// The expansion turns this:
//
//     #[cfg_attr(COND1, SPEC1)]
//     #[cfg_attr(COND2, SPEC2)]
//     struct Item { ... }
//
// into this:
//
//     #[cfg(COND1)]
//     impl Trait for Item { ... }
//     #[cfg_attr(COND2, SPEC3)]
//     struct Item { ... }
//
// In the example, SPEC1 was handled by expand_2 to create the impl, and the
// handling of SPEC2 resulted in a new attribute SPEC3 which remains
// conditional.
fn expand_1(
    mut item: Annotatable,
    fld: &mut MacroExpander,
    out_items: &mut SmallVector<Annotatable>,
    new_attrs: &mut Vec<ast::Attribute>,
) -> Annotatable {
    while !item.attrs().is_empty() {
        // Pop the first attribute.
        let mut attr = None;
        item = item.map_attrs(|mut attrs| {
            attr = Some(attrs.remove(0));
            attrs
        });
        let attr = attr.unwrap();

        match attr.node.value.node {
            // #[cfg_attr(COND, SPEC)]
            ast::MetaItemKind::List(ref word, ref vec)
                if word == "cfg_attr" && vec.len() == 2 =>
            {
                // #[cfg(COND)]
                let cond = fld.cx.attribute(
                    attr.span,
                    fld.cx.meta_list(
                        attr.node.value.span,
                        intern("cfg").as_str(),
                        vec[..1].to_vec()));
                // #[SPEC]
                let spec = fld.cx.attribute(
                    attr.span,
                    vec[1].clone());
                let mut items = SmallVector::zero();
                let mut attrs = Vec::new();
                item = expand_2(item, &spec, fld, &mut items, &mut attrs);
                for new_item in items {
                    let new_item = new_item.map_attrs(|mut attrs| {
                        attrs.push(cond.clone());
                        attrs
                    });
                    out_items.push(new_item);
                }
                for new_attr in attrs {
                    // #[cfg_attr(COND, NEW_SPEC)]
                    let new_attr = fld.cx.attribute(
                        attr.span,
                        fld.cx.meta_list(
                            attr.node.value.span,
                            word.clone(),
                            vec![vec[0].clone(), new_attr.node.value]));
                    new_attrs.push(new_attr);
                }
            }
            _ => {
                item = expand_2(item, &attr, fld, out_items, new_attrs);
            }
        }
    }
    item
}

// Responsible for expanding `derive` and delegating to expand_3.
//
// The expansion turns this:
//
//     #[derive(Serialize, Clone)]
//     #[other_attr]
//     struct Item { ... }
//
// into this:
//
//     impl Serialize for Item { ... }
//     #[derive(Clone)]
//     #[other_attr]
//     struct Item { ... }
//
// In the example, `derive_Serialize` was handled by expand_3 to create the impl
// but `derive_Clone` and `other_attr` were not handled. Attributes that are not
// handled by expand_3 are preserved.
fn expand_2(
    mut item: Annotatable,
    attr: &ast::Attribute,
    fld: &mut MacroExpander,
    out_items: &mut SmallVector<Annotatable>,
    new_attrs: &mut Vec<ast::Attribute>,
) -> Annotatable {
    let mname = intern(&attr.name());
    let mitem = &attr.node.value;
    if mname.as_str() == "derive" {
        let traits = mitem.meta_item_list().unwrap_or(&[]);
        if traits.is_empty() {
            fld.cx.span_warn(mitem.span, "empty trait list in `derive`");
        }
        let mut not_handled = Vec::new();
        for titem in traits.iter().rev() {
            let tname = match titem.node {
                ast::MetaItemKind::Word(ref tname) => tname,
                _ => {
                    fld.cx.span_err(titem.span, "malformed `derive` entry");
                    continue;
                }
            };
            let tname = intern(&format!("derive_{}", tname));
            // #[derive_Trait]
            let derive = fld.cx.attribute(
                attr.span,
                fld.cx.meta_word(titem.span, tname.as_str()));
            let (handled, out) = expand_3(item, &derive, fld, out_items, tname);
            if !handled {
                not_handled.push((*titem).clone());
            }
            item = out;
        }
        if !not_handled.is_empty() {
            // #[derive(Trait, ...)]
            let derive = fld.cx.attribute(
                attr.span,
                fld.cx.meta_list(mitem.span, mname.as_str(), not_handled));
            new_attrs.push(derive);
        }
        item
    } else {
        let (handled, out) = expand_3(item, attr, fld, out_items, mname);
        if !handled {
            new_attrs.push((*attr).clone());
        }
        out
    }
}

// Responsible for expanding attributes that match a MultiDecorator or
// MultiModifier registered in the syntax_env. Returns whether the given
// attribute was handled, along with the item to continue processing.
//
// Syntex supports only a special case of MultiModifier - those that produce
// exactly one output. If a MultiModifier produces zero or more than one output
// this function panics. The problematic case we cannot support is:
//
//     #[decorator] // not registered with Syntex
//     #[modifier] // registered
//     struct A;
fn expand_3(
    item: Annotatable,
    attr: &ast::Attribute,
    fld: &mut MacroExpander,
    out_items: &mut SmallVector<Annotatable>,
    mname: Name,
) -> (bool, Annotatable) {
    match fld.cx.syntax_env.find(mname) {
        Some(rc) => match *rc {
            MultiDecorator(ref mac) => {
                attr::mark_used(&attr);
                fld.cx.bt_push(ExpnInfo {
                    call_site: attr.span,
                    callee: NameAndSpan {
                        format: MacroAttribute(mname),
                        span: Some(attr.span),
                        // attributes can do whatever they like, for now.
                        allow_internal_unstable: true,
                    }
                });

                let mut modified = Vec::new();
                mac.expand(fld.cx, attr.span, &attr.node.value, &item,
                        &mut |item| modified.push(item));

                fld.cx.bt_pop();
                out_items.extend(modified.into_iter()
                    .flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
                (true, item)
            }
            MultiModifier(ref mac) => {
                attr::mark_used(&attr);
                fld.cx.bt_push(ExpnInfo {
                    call_site: attr.span,
                    callee: NameAndSpan {
                        format: MacroAttribute(mname),
                        span: Some(attr.span),
                        // attributes can do whatever they like, for now.
                        allow_internal_unstable: true,
                    }
                });

                let mut modified = mac.expand(fld.cx,
                                              attr.span,
                                              &attr.node.value,
                                              item);
                if modified.len() != 1 {
                    panic!("syntex limitation: expected 1 output from `#[{}]` but got {}",
                           mname, modified.len());
                }
                let modified = modified.pop().unwrap();

                fld.cx.bt_pop();

                let mut expanded = expand_annotatable(modified, fld);
                if expanded.is_empty() {
                    panic!("syntex limitation: output of `#[{}]` must not expand further",
                           mname);
                }
                let last = expanded.pop().unwrap();

                out_items.extend(expanded);
                (true, last)
            }
            _ => (false, item),
        },
        _ => (false, item),
    }
}
<commit_msg>Clearer return type for attribute that is not handled<commit_after>use ast::{self, Name};
use attr::{self, AttrMetaMethods, HasAttrs};
use codemap::{ExpnInfo, MacroAttribute, NameAndSpan};
use ext::base::*;
use ext::build::AstBuilder;
use ext::expand::{MacroExpander, expand_multi_modified};
use parse::token::intern;
use util::small_vector::SmallVector;

pub fn expand_annotatable(
    mut item: Annotatable,
    fld: &mut MacroExpander,
) -> SmallVector<Annotatable> {
    let mut out_items = SmallVector::zero();
    let mut new_attrs = Vec::new();

    item = expand_1(item, fld, &mut out_items, &mut new_attrs);

    item = item.fold_attrs(new_attrs);
    let expanded = expand_multi_modified(item, fld);
    out_items.push_all(expanded);

    out_items
}

// Responsible for expanding `cfg_attr` and delegating to expand_2.
//
// The expansion turns this:
//
//     #[cfg_attr(COND1, SPEC1)]
//     #[cfg_attr(COND2, SPEC2)]
//     struct Item { ... }
//
// into this:
//
//     #[cfg(COND1)]
//     impl Trait for Item { ... }
//     #[cfg_attr(COND2, SPEC3)]
//     struct Item { ... }
//
// In the example, SPEC1 was handled by expand_2 to create the impl, and the
// handling of SPEC2 resulted in a new attribute SPEC3 which remains
// conditional.
fn expand_1(
    mut item: Annotatable,
    fld: &mut MacroExpander,
    out_items: &mut SmallVector<Annotatable>,
    new_attrs: &mut Vec<ast::Attribute>,
) -> Annotatable {
    while !item.attrs().is_empty() {
        // Pop the first attribute.
        let mut attr = None;
        item = item.map_attrs(|mut attrs| {
            attr = Some(attrs.remove(0));
            attrs
        });
        let attr = attr.unwrap();

        match attr.node.value.node {
            // #[cfg_attr(COND, SPEC)]
            ast::MetaItemKind::List(ref word, ref vec)
                if word == "cfg_attr" && vec.len() == 2 =>
            {
                // #[cfg(COND)]
                let cond = fld.cx.attribute(
                    attr.span,
                    fld.cx.meta_list(
                        attr.node.value.span,
                        intern("cfg").as_str(),
                        vec[..1].to_vec()));
                // #[SPEC]
                let spec = fld.cx.attribute(
                    attr.span,
                    vec[1].clone());
                let mut items = SmallVector::zero();
                let mut attrs = Vec::new();
                item = expand_2(item, &spec, fld, &mut items, &mut attrs);
                for new_item in items {
                    let new_item = new_item.map_attrs(|mut attrs| {
                        attrs.push(cond.clone());
                        attrs
                    });
                    out_items.push(new_item);
                }
                for new_attr in attrs {
                    // #[cfg_attr(COND, NEW_SPEC)]
                    let new_attr = fld.cx.attribute(
                        attr.span,
                        fld.cx.meta_list(
                            attr.node.value.span,
                            word.clone(),
                            vec![vec[0].clone(), new_attr.node.value]));
                    new_attrs.push(new_attr);
                }
            }
            _ => {
                item = expand_2(item, &attr, fld, out_items, new_attrs);
            }
        }
    }
    item
}

// Responsible for expanding `derive` and delegating to expand_3.
//
// The expansion turns this:
//
//     #[derive(Serialize, Clone)]
//     #[other_attr]
//     struct Item { ... }
//
// into this:
//
//     impl Serialize for Item { ... }
//     #[derive(Clone)]
//     #[other_attr]
//     struct Item { ... }
//
// In the example, `derive_Serialize` was handled by expand_3 to create the impl
// but `derive_Clone` and `other_attr` were not handled. Attributes that are not
// handled by expand_3 are preserved.
fn expand_2(
    mut item: Annotatable,
    attr: &ast::Attribute,
    fld: &mut MacroExpander,
    out_items: &mut SmallVector<Annotatable>,
    new_attrs: &mut Vec<ast::Attribute>,
) -> Annotatable {
    let mname = intern(&attr.name());
    let mitem = &attr.node.value;
    if mname.as_str() == "derive" {
        let traits = mitem.meta_item_list().unwrap_or(&[]);
        if traits.is_empty() {
            fld.cx.span_warn(mitem.span, "empty trait list in `derive`");
        }
        let mut not_handled = Vec::new();
        for titem in traits.iter().rev() {
            let tname = match titem.node {
                ast::MetaItemKind::Word(ref tname) => tname,
                _ => {
                    fld.cx.span_err(titem.span, "malformed `derive` entry");
                    continue;
                }
            };
            let tname = intern(&format!("derive_{}", tname));
            // #[derive_Trait]
            let derive = fld.cx.attribute(
                attr.span,
                fld.cx.meta_word(titem.span, tname.as_str()));
            item = match expand_3(item, &derive, fld, out_items, tname) {
                Expansion::Handled(item) => item,
                Expansion::NotHandled(item) => {
                    not_handled.push((*titem).clone());
                    item
                }
            };
        }
        if !not_handled.is_empty() {
            // #[derive(Trait, ...)]
            let derive = fld.cx.attribute(
                attr.span,
                fld.cx.meta_list(mitem.span, mname.as_str(), not_handled));
            new_attrs.push(derive);
        }
        item
    } else {
        match expand_3(item, attr, fld, out_items, mname) {
            Expansion::Handled(item) => item,
            Expansion::NotHandled(item) => {
                new_attrs.push((*attr).clone());
                item
            }
        }
    }
}

enum Expansion {
    Handled(Annotatable),
    /// Here is your `Annotatable` back.
    NotHandled(Annotatable),
}

// Responsible for expanding attributes that match a MultiDecorator or
// MultiModifier registered in the syntax_env. Returns the item to continue
// processing.
//
// Syntex supports only a special case of MultiModifier - those that produce
// exactly one output. If a MultiModifier produces zero or more than one output
// this function panics. The problematic case we cannot support is:
//
//     #[decorator] // not registered with Syntex
//     #[modifier] // registered
//     struct A;
fn expand_3(
    item: Annotatable,
    attr: &ast::Attribute,
    fld: &mut MacroExpander,
    out_items: &mut SmallVector<Annotatable>,
    mname: Name,
) -> Expansion {
    match fld.cx.syntax_env.find(mname) {
        Some(rc) => match *rc {
            MultiDecorator(ref mac) => {
                attr::mark_used(&attr);
                fld.cx.bt_push(ExpnInfo {
                    call_site: attr.span,
                    callee: NameAndSpan {
                        format: MacroAttribute(mname),
                        span: Some(attr.span),
                        // attributes can do whatever they like, for now.
                        allow_internal_unstable: true,
                    }
                });

                let mut modified = Vec::new();
                mac.expand(fld.cx, attr.span, &attr.node.value, &item,
                        &mut |item| modified.push(item));

                fld.cx.bt_pop();
                out_items.extend(modified.into_iter()
                    .flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
                Expansion::Handled(item)
            }
            MultiModifier(ref mac) => {
                attr::mark_used(&attr);
                fld.cx.bt_push(ExpnInfo {
                    call_site: attr.span,
                    callee: NameAndSpan {
                        format: MacroAttribute(mname),
                        span: Some(attr.span),
                        // attributes can do whatever they like, for now.
                        allow_internal_unstable: true,
                    }
                });

                let mut modified = mac.expand(fld.cx,
                                              attr.span,
                                              &attr.node.value,
                                              item);
                if modified.len() != 1 {
                    panic!("syntex limitation: expected 1 output from `#[{}]` but got {}",
                           mname, modified.len());
                }
                let modified = modified.pop().unwrap();

                fld.cx.bt_pop();

                let mut expanded = expand_annotatable(modified, fld);
                if expanded.is_empty() {
                    panic!("syntex limitation: output of `#[{}]` must not expand further",
                           mname);
                }
                let last = expanded.pop().unwrap();

                out_items.extend(expanded);
                Expansion::Handled(last)
            }
            _ => Expansion::NotHandled(item),
        },
        _ => Expansion::NotHandled(item),
    }
}
<|endoftext|>


<commit_before>use pg::Pg;
use query_dsl::DistinctOnDsl;
use query_builder::{AstPass, QueryFragment, SelectStatement};
use result::QueryResult;
use expression::{SelectableExpression, Expression};

#[derive(Debug, Clone, Copy)]
pub struct DistinctOnClause<T>(pub(crate) T);

impl<T> QueryFragment<Pg> for DistinctOnClause<T>
where
    T: QueryFragment<Pg>,
{
    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
        out.push_sql("DISTINCT ON(");
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl_query_id!(DistinctOnClause<T>);

impl<ST, F, S, D, W, O, L, Of, G, Selection> DistinctOnDsl<Selection, F>
    for SelectStatement<F, S, D, W, O, L, Of, G>
where
    Selection: SelectableExpression<F>,
    Self: Expression<SqlType = ST>,
    SelectStatement<F, S, DistinctOnClause<Selection>, W, O, L, Of, G>: Expression<SqlType = ST>,
{
    type Output = SelectStatement<F, S, DistinctOnClause<Selection>, W, O, L, Of, G>;

    fn distinct_on(self, selection: Selection) -> Self::Output {
        SelectStatement::new(
            self.select,
            self.from,
            DistinctOnClause(selection),
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
            self.for_update,
        )
    }
}
<commit_msg>Run rustfmt<commit_after>use pg::Pg;
use query_dsl::DistinctOnDsl;
use query_builder::{AstPass, QueryFragment, SelectStatement};
use result::QueryResult;
use expression::{Expression, SelectableExpression};

#[derive(Debug, Clone, Copy)]
pub struct DistinctOnClause<T>(pub(crate) T);

impl<T> QueryFragment<Pg> for DistinctOnClause<T>
where
    T: QueryFragment<Pg>,
{
    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
        out.push_sql("DISTINCT ON(");
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl_query_id!(DistinctOnClause<T>);

impl<ST, F, S, D, W, O, L, Of, G, Selection> DistinctOnDsl<Selection, F>
    for SelectStatement<F, S, D, W, O, L, Of, G>
where
    Selection: SelectableExpression<F>,
    Self: Expression<SqlType = ST>,
    SelectStatement<F, S, DistinctOnClause<Selection>, W, O, L, Of, G>: Expression<SqlType = ST>,
{
    type Output = SelectStatement<F, S, DistinctOnClause<Selection>, W, O, L, Of, G>;

    fn distinct_on(self, selection: Selection) -> Self::Output {
        SelectStatement::new(
            self.select,
            self.from,
            DistinctOnClause(selection),
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
            self.for_update,
        )
    }
}
<|endoftext|>


<commit_before>//!Types for interpolation between multiple colors.
//!
//!This module is only available if the `std` feature is enabled (this is the
//!default).

use num_traits::{One, Zero};
use float::Float;
use std::cmp::max;
use approx::{AbsDiffEq, RelativeEq, UlpsEq};

use cast;

use Mix;

///A linear interpolation between colors.
///
///It's used to smoothly transition between a series of colors, that can be
///either evenly spaced or have customized positions. The gradient is
///continuous between the control points, but it's possible to iterate over a
///number of evenly spaced points using the `take` method. Any point outside
///the domain of the gradient will have the same color as the closest control
///point.
#[derive(Clone, Debug)]
pub struct Gradient<C: Mix + Clone>(Vec<(C::Scalar, C)>);

impl<C: Mix + Clone> Gradient<C> {
    ///Create a gradient of evenly spaced colors with the domain [0.0, 1.0].
    ///There must be at least one color.
    pub fn new<I: IntoIterator<Item = C>>(colors: I) -> Gradient<C> {
        let mut points: Vec<_> = colors.into_iter().map(|c| (C::Scalar::zero(), c)).collect();
        assert!(points.len() > 0);
        let step_size = C::Scalar::one() / cast(max(points.len() - 1, 1) as f64);

        for (i, &mut (ref mut p, _)) in points.iter_mut().enumerate() {
            *p = cast::<C::Scalar, _>(i) * step_size;
        }

        Gradient(points)
    }

    ///Create a gradient of colors with custom spacing and domain. There must be
    ///at least one color and they are expected to be ordered by their
    ///position value.
    pub fn with_domain(colors: Vec<(C::Scalar, C)>) -> Gradient<C> {
        assert!(colors.len() > 0);

        //Maybe sort the colors?
        Gradient(colors)
    }

    ///Get a color from the gradient. The color of the closest control point
    ///will be returned if `i` is outside the domain.
    pub fn get(&self, i: C::Scalar) -> C {
        let &(mut min, ref min_color) = self.0
            .get(0)
            .expect("a Gradient must contain at least one color");
        let mut min_color = min_color;
        let mut min_index = 0;

        if i <= min {
            return min_color.clone();
        }

        let &(mut max, ref max_color) = self.0
            .last()
            .expect("a Gradient must contain at least one color");
        let mut max_color = max_color;
        let mut max_index = self.0.len() - 1;

        if i >= max {
            return max_color.clone();
        }

        while min_index < max_index - 1 {
            let index = min_index + (max_index - min_index) / 2;

            let (p, ref color) = self.0[index];

            if i <= p {
                max = p;
                max_color = color;
                max_index = index;
            } else {
                min = p;
                min_color = color;
                min_index = index;
            }
        }

        let factor = (i - min) / (max - min);

        min_color.mix(max_color, factor)
    }

    ///Take `n` evenly spaced colors from the gradient, as an iterator.
    pub fn take(&self, n: usize) -> Take<C> {
        let (min, max) = self.domain();

        Take {
            gradient: MaybeSlice::NotSlice(self),
            from: min,
            diff: max - min,
            len: n,
            current: 0,
        }
    }

    ///Slice this gradient to limit its domain.
    pub fn slice<R: Into<Range<C::Scalar>>>(&self, range: R) -> Slice<C> {
        Slice {
            gradient: self,
            range: range.into(),
        }
    }

    ///Get the limits of this gradient's domain.
    pub fn domain(&self) -> (C::Scalar, C::Scalar) {
        let &(min, _) = self.0
            .get(0)
            .expect("a Gradient must contain at least one color");
        let &(max, _) = self.0
            .last()
            .expect("a Gradient must contain at least one color");
        (min, max)
    }
}

///An iterator over interpolated colors.
#[derive(Clone)]
pub struct Take<'a, C: Mix + Clone + 'a> {
    gradient: MaybeSlice<'a, C>,
    from: C::Scalar,
    diff: C::Scalar,
    len: usize,
    current: usize,
}

impl<'a, C: Mix + Clone> Iterator for Take<'a, C> {
    type Item = C;

    fn next(&mut self) -> Option<C> {
        if self.current < self.len {
            let i = self.from + (self.diff / cast(self.len)) * cast(self.current);
            self.current += 1;
            Some(self.gradient.get(i))
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.current, Some(self.len - self.current))
    }
}

impl<'a, C: Mix + Clone> ExactSizeIterator for Take<'a, C> {}

///A slice of a Gradient that limits its domain.
#[derive(Clone, Debug)]
pub struct Slice<'a, C: Mix + Clone + 'a> {
    gradient: &'a Gradient<C>,
    range: Range<C::Scalar>,
}

impl<'a, C: Mix + Clone> Slice<'a, C> {
    ///Get a color from the gradient slice. The color of the closest domain
    ///limit will be returned if `i` is outside the domain.
    pub fn get(&self, i: C::Scalar) -> C {
        self.gradient.get(self.range.clamp(i))
    }

    ///Take `n` evenly spaced colors from the gradient slice, as an iterator.
    pub fn take(&self, n: usize) -> Take<C> {
        let (min, max) = self.domain();

        Take {
            gradient: MaybeSlice::Slice(self.clone()),
            from: min,
            diff: max - min,
            len: n,
            current: 0,
        }
    }

    ///Slice this gradient slice to further limit its domain. Ranges outside
    ///the domain will be clamped to the nearest domain limit.
    pub fn slice<R: Into<Range<C::Scalar>>>(&self, range: R) -> Slice<C> {
        Slice {
            gradient: self.gradient,
            range: self.range.constrain(&range.into()),
        }
    }

    ///Get the limits of this gradient slice's domain.
    pub fn domain(&self) -> (C::Scalar, C::Scalar) {
        if let Range {
            from: Some(from),
            to: Some(to),
        } = self.range
        {
            (from, to)
        } else {
            let (from, to) = self.gradient.domain();
            (self.range.from.unwrap_or(from), self.range.to.unwrap_or(to))
        }
    }
}

///A domain range for gradient slices.
#[derive(Clone, Debug, PartialEq)]
pub struct Range<T: Float> {
    from: Option<T>,
    to: Option<T>,
}

impl<T: Float> Range<T> {
    fn clamp(&self, mut x: T) -> T {
        x = self.from.unwrap_or(x).max(x);
        self.to.unwrap_or(x).min(x)
    }

    fn constrain(&self, other: &Range<T>) -> Range<T> {
        if let (Some(f), Some(t)) = (other.from, self.to) {
            if f >= t {
                return Range {
                    from: self.to,
                    to: self.to,
                };
            }
        }

        if let (Some(t), Some(f)) = (other.to, self.from) {
            if t <= f {
                return Range {
                    from: self.from,
                    to: self.from,
                };
            }
        }

        Range {
            from: match (self.from, other.from) {
                (Some(s), Some(o)) => Some(s.max(o)),
                (Some(s), None) => Some(s),
                (None, Some(o)) => Some(o),
                (None, None) => None,
            },
            to: match (self.to, other.to) {
                (Some(s), Some(o)) => Some(s.min(o)),
                (Some(s), None) => Some(s),
                (None, Some(o)) => Some(o),
                (None, None) => None,
            },
        }
    }
}

impl<T: Float> From<::std::ops::Range<T>> for Range<T> {
    fn from(range: ::std::ops::Range<T>) -> Range<T> {
        Range {
            from: Some(range.start),
            to: Some(range.end),
        }
    }
}

impl<T: Float> From<::std::ops::RangeFrom<T>> for Range<T> {
    fn from(range: ::std::ops::RangeFrom<T>) -> Range<T> {
        Range {
            from: Some(range.start),
            to: None,
        }
    }
}

impl<T: Float> From<::std::ops::RangeTo<T>> for Range<T> {
    fn from(range: ::std::ops::RangeTo<T>) -> Range<T> {
        Range {
            from: None,
            to: Some(range.end),
        }
    }
}

impl<T: Float> From<::std::ops::RangeFull> for Range<T> {
    fn from(_range: ::std::ops::RangeFull) -> Range<T> {
        Range {
            from: None,
            to: None,
        }
    }
}

impl<T> AbsDiffEq for Range<T>
where
    T: AbsDiffEq + Float,
    T::Epsilon: Copy,
{
    type Epsilon = T::Epsilon;

    fn default_epsilon() -> Self::Epsilon {
        T::default_epsilon()
    }

    fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
        let from = match (self.from, other.from) {
            (Some(s), Some(o)) => s.abs_diff_eq(&o, epsilon),
            (None, None) => true,
            _ => false,
        };

        let to = match (self.to, other.to) {
            (Some(s), Some(o)) => s.abs_diff_eq(&o, epsilon),
            (None, None) => true,
            _ => false,
        };

        from && to
    }
}

impl<T> RelativeEq for Range<T>
where
    T: RelativeEq + Float,
    T::Epsilon: Copy,
{
    fn default_max_relative() -> Self::Epsilon {
        T::default_max_relative()
    }

    fn relative_eq(
        &self,
        other: &Range<T>,
        epsilon: Self::Epsilon,
        max_relative: Self::Epsilon,
    ) -> bool {
        let from = match (self.from, other.from) {
            (Some(s), Some(o)) => s.relative_eq(&o, epsilon, max_relative),
            (None, None) => true,
            _ => false,
        };

        let to = match (self.to, other.to) {
            (Some(s), Some(o)) => s.relative_eq(&o, epsilon, max_relative),
            (None, None) => true,
            _ => false,
        };

        from && to
    }
}

impl<T> UlpsEq for Range<T>
where
    T: UlpsEq + Float,
    T::Epsilon: Copy,
{
    fn default_max_ulps() -> u32 {
        T::default_max_ulps()
    }

    fn ulps_eq(&self, other: &Range<T>, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
        let from = match (self.from, other.from) {
            (Some(s), Some(o)) => s.ulps_eq(&o, epsilon, max_ulps),
            (None, None) => true,
            _ => false,
        };

        let to = match (self.to, other.to) {
            (Some(s), Some(o)) => s.ulps_eq(&o, epsilon, max_ulps),
            (None, None) => true,
            _ => false,
        };

        from && to
    }
}

#[derive(Clone)]
enum MaybeSlice<'a, C: Mix + Clone + 'a> {
    NotSlice(&'a Gradient<C>),
    Slice(Slice<'a, C>),
}

impl<'a, C: Mix + Clone> MaybeSlice<'a, C> {
    fn get(&self, i: C::Scalar) -> C {
        match *self {
            MaybeSlice::NotSlice(g) => g.get(i),
            MaybeSlice::Slice(ref s) => s.get(i),
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Gradient, Range};
    use LinSrgb;

    #[test]
    fn range_clamp() {
        let range: Range<f64> = (0.0..1.0).into();
        assert_eq!(range.clamp(-1.0), 0.0);
        assert_eq!(range.clamp(2.0), 1.0);
        assert_eq!(range.clamp(0.5), 0.5);
    }

    #[test]
    fn range_constrain() {
        let range: Range<f64> = (0.0..1.0).into();
        assert_eq!(range.constrain(&(-3.0..-5.0).into()), (0.0..0.0).into());
        assert_eq!(range.constrain(&(-3.0..0.8).into()), (0.0..0.8).into());

        assert_eq!(range.constrain(&(3.0..5.0).into()), (1.0..1.0).into());
        assert_eq!(range.constrain(&(0.2..5.0).into()), (0.2..1.0).into());

        assert_eq!(range.constrain(&(0.2..0.8).into()), (0.2..0.8).into());
    }

    #[test]
    fn simple_slice() {
        let g1 = Gradient::new(vec![
            LinSrgb::new(1.0, 0.0, 0.0),
            LinSrgb::new(0.0, 0.0, 1.0),
        ]);
        let g2 = g1.slice(..0.5);

        let v1: Vec<_> = g1.take(10).take(5).collect();
        let v2: Vec<_> = g2.take(5).collect();
        for (t1, t2) in v1.iter().zip(v2.iter()) {
            assert_relative_eq!(t1, t2);
        }
    }
}
<commit_msg>Add DoubleEndedIterator impl for gradient::Take, closes #153<commit_after>//!Types for interpolation between multiple colors.
//!
//!This module is only available if the `std` feature is enabled (this is the
//!default).

use num_traits::{One, Zero};
use float::Float;
use std::cmp::max;
use approx::{AbsDiffEq, RelativeEq, UlpsEq};

use cast;

use Mix;

///A linear interpolation between colors.
///
///It's used to smoothly transition between a series of colors, that can be
///either evenly spaced or have customized positions. The gradient is
///continuous between the control points, but it's possible to iterate over a
///number of evenly spaced points using the `take` method. Any point outside
///the domain of the gradient will have the same color as the closest control
///point.
#[derive(Clone, Debug)]
pub struct Gradient<C: Mix + Clone>(Vec<(C::Scalar, C)>);

impl<C: Mix + Clone> Gradient<C> {
    ///Create a gradient of evenly spaced colors with the domain [0.0, 1.0].
    ///There must be at least one color.
    pub fn new<I: IntoIterator<Item = C>>(colors: I) -> Gradient<C> {
        let mut points: Vec<_> = colors.into_iter().map(|c| (C::Scalar::zero(), c)).collect();
        assert!(points.len() > 0);
        let step_size = C::Scalar::one() / cast(max(points.len() - 1, 1) as f64);

        for (i, &mut (ref mut p, _)) in points.iter_mut().enumerate() {
            *p = cast::<C::Scalar, _>(i) * step_size;
        }

        Gradient(points)
    }

    ///Create a gradient of colors with custom spacing and domain. There must be
    ///at least one color and they are expected to be ordered by their
    ///position value.
    pub fn with_domain(colors: Vec<(C::Scalar, C)>) -> Gradient<C> {
        assert!(colors.len() > 0);

        //Maybe sort the colors?
        Gradient(colors)
    }

    ///Get a color from the gradient. The color of the closest control point
    ///will be returned if `i` is outside the domain.
    pub fn get(&self, i: C::Scalar) -> C {
        let &(mut min, ref min_color) = self.0
            .get(0)
            .expect("a Gradient must contain at least one color");
        let mut min_color = min_color;
        let mut min_index = 0;

        if i <= min {
            return min_color.clone();
        }

        let &(mut max, ref max_color) = self.0
            .last()
            .expect("a Gradient must contain at least one color");
        let mut max_color = max_color;
        let mut max_index = self.0.len() - 1;

        if i >= max {
            return max_color.clone();
        }

        while min_index < max_index - 1 {
            let index = min_index + (max_index - min_index) / 2;

            let (p, ref color) = self.0[index];

            if i <= p {
                max = p;
                max_color = color;
                max_index = index;
            } else {
                min = p;
                min_color = color;
                min_index = index;
            }
        }

        let factor = (i - min) / (max - min);

        min_color.mix(max_color, factor)
    }

    ///Take `n` evenly spaced colors from the gradient, as an iterator.
    pub fn take(&self, n: usize) -> Take<C> {
        let (min, max) = self.domain();

        Take {
            gradient: MaybeSlice::NotSlice(self),
            from: min,
            diff: max - min,
            len: n,
            from_head: 0,
            from_end: 0,
        }
    }

    ///Slice this gradient to limit its domain.
    pub fn slice<R: Into<Range<C::Scalar>>>(&self, range: R) -> Slice<C> {
        Slice {
            gradient: self,
            range: range.into(),
        }
    }

    ///Get the limits of this gradient's domain.
    pub fn domain(&self) -> (C::Scalar, C::Scalar) {
        let &(min, _) = self.0
            .get(0)
            .expect("a Gradient must contain at least one color");
        let &(max, _) = self.0
            .last()
            .expect("a Gradient must contain at least one color");
        (min, max)
    }
}

///An iterator over interpolated colors.
#[derive(Clone)]
pub struct Take<'a, C: Mix + Clone + 'a> {
    gradient: MaybeSlice<'a, C>,
    from: C::Scalar,
    diff: C::Scalar,
    len: usize,
    from_head: usize,
    from_end: usize,
}

impl<'a, C: Mix + Clone> Iterator for Take<'a, C> {
    type Item = C;

    fn next(&mut self) -> Option<C> {
        if self.from_head + self.from_end < self.len {
            let i = self.from + (self.diff / cast(self.len)) * cast(self.from_head);
            self.from_head += 1;
            Some(self.gradient.get(i))
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.from_head - self.from_end, Some(self.len - self.from_head - self.from_end))
    }
}

impl<'a, C: Mix + Clone> ExactSizeIterator for Take<'a, C> {}

impl<'a, C: Mix + Clone> DoubleEndedIterator for Take<'a, C> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.from_head + self.from_end < self.len {
            let i = self.from + (self.diff / cast(self.len)) * cast(self.len - self.from_end - 1);
            self.from_end += 1;
            Some(self.gradient.get(i))
        } else {
            None
        }
    }
}

///A slice of a Gradient that limits its domain.
#[derive(Clone, Debug)]
pub struct Slice<'a, C: Mix + Clone + 'a> {
    gradient: &'a Gradient<C>,
    range: Range<C::Scalar>,
}

impl<'a, C: Mix + Clone> Slice<'a, C> {
    ///Get a color from the gradient slice. The color of the closest domain
    ///limit will be returned if `i` is outside the domain.
    pub fn get(&self, i: C::Scalar) -> C {
        self.gradient.get(self.range.clamp(i))
    }

    ///Take `n` evenly spaced colors from the gradient slice, as an iterator.
    pub fn take(&self, n: usize) -> Take<C> {
        let (min, max) = self.domain();

        Take {
            gradient: MaybeSlice::Slice(self.clone()),
            from: min,
            diff: max - min,
            len: n,
            from_head: 0,
            from_end: 0,
        }
    }

    ///Slice this gradient slice to further limit its domain. Ranges outside
    ///the domain will be clamped to the nearest domain limit.
    pub fn slice<R: Into<Range<C::Scalar>>>(&self, range: R) -> Slice<C> {
        Slice {
            gradient: self.gradient,
            range: self.range.constrain(&range.into()),
        }
    }

    ///Get the limits of this gradient slice's domain.
    pub fn domain(&self) -> (C::Scalar, C::Scalar) {
        if let Range {
            from: Some(from),
            to: Some(to),
        } = self.range
        {
            (from, to)
        } else {
            let (from, to) = self.gradient.domain();
            (self.range.from.unwrap_or(from), self.range.to.unwrap_or(to))
        }
    }
}

///A domain range for gradient slices.
#[derive(Clone, Debug, PartialEq)]
pub struct Range<T: Float> {
    from: Option<T>,
    to: Option<T>,
}

impl<T: Float> Range<T> {
    fn clamp(&self, mut x: T) -> T {
        x = self.from.unwrap_or(x).max(x);
        self.to.unwrap_or(x).min(x)
    }

    fn constrain(&self, other: &Range<T>) -> Range<T> {
        if let (Some(f), Some(t)) = (other.from, self.to) {
            if f >= t {
                return Range {
                    from: self.to,
                    to: self.to,
                };
            }
        }

        if let (Some(t), Some(f)) = (other.to, self.from) {
            if t <= f {
                return Range {
                    from: self.from,
                    to: self.from,
                };
            }
        }

        Range {
            from: match (self.from, other.from) {
                (Some(s), Some(o)) => Some(s.max(o)),
                (Some(s), None) => Some(s),
                (None, Some(o)) => Some(o),
                (None, None) => None,
            },
            to: match (self.to, other.to) {
                (Some(s), Some(o)) => Some(s.min(o)),
                (Some(s), None) => Some(s),
                (None, Some(o)) => Some(o),
                (None, None) => None,
            },
        }
    }
}

impl<T: Float> From<::std::ops::Range<T>> for Range<T> {
    fn from(range: ::std::ops::Range<T>) -> Range<T> {
        Range {
            from: Some(range.start),
            to: Some(range.end),
        }
    }
}

impl<T: Float> From<::std::ops::RangeFrom<T>> for Range<T> {
    fn from(range: ::std::ops::RangeFrom<T>) -> Range<T> {
        Range {
            from: Some(range.start),
            to: None,
        }
    }
}

impl<T: Float> From<::std::ops::RangeTo<T>> for Range<T> {
    fn from(range: ::std::ops::RangeTo<T>) -> Range<T> {
        Range {
            from: None,
            to: Some(range.end),
        }
    }
}

impl<T: Float> From<::std::ops::RangeFull> for Range<T> {
    fn from(_range: ::std::ops::RangeFull) -> Range<T> {
        Range {
            from: None,
            to: None,
        }
    }
}

impl<T> AbsDiffEq for Range<T>
where
    T: AbsDiffEq + Float,
    T::Epsilon: Copy,
{
    type Epsilon = T::Epsilon;

    fn default_epsilon() -> Self::Epsilon {
        T::default_epsilon()
    }

    fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
        let from = match (self.from, other.from) {
            (Some(s), Some(o)) => s.abs_diff_eq(&o, epsilon),
            (None, None) => true,
            _ => false,
        };

        let to = match (self.to, other.to) {
            (Some(s), Some(o)) => s.abs_diff_eq(&o, epsilon),
            (None, None) => true,
            _ => false,
        };

        from && to
    }
}

impl<T> RelativeEq for Range<T>
where
    T: RelativeEq + Float,
    T::Epsilon: Copy,
{
    fn default_max_relative() -> Self::Epsilon {
        T::default_max_relative()
    }

    fn relative_eq(
        &self,
        other: &Range<T>,
        epsilon: Self::Epsilon,
        max_relative: Self::Epsilon,
    ) -> bool {
        let from = match (self.from, other.from) {
            (Some(s), Some(o)) => s.relative_eq(&o, epsilon, max_relative),
            (None, None) => true,
            _ => false,
        };

        let to = match (self.to, other.to) {
            (Some(s), Some(o)) => s.relative_eq(&o, epsilon, max_relative),
            (None, None) => true,
            _ => false,
        };

        from && to
    }
}

impl<T> UlpsEq for Range<T>
where
    T: UlpsEq + Float,
    T::Epsilon: Copy,
{
    fn default_max_ulps() -> u32 {
        T::default_max_ulps()
    }

    fn ulps_eq(&self, other: &Range<T>, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
        let from = match (self.from, other.from) {
            (Some(s), Some(o)) => s.ulps_eq(&o, epsilon, max_ulps),
            (None, None) => true,
            _ => false,
        };

        let to = match (self.to, other.to) {
            (Some(s), Some(o)) => s.ulps_eq(&o, epsilon, max_ulps),
            (None, None) => true,
            _ => false,
        };

        from && to
    }
}

#[derive(Clone)]
enum MaybeSlice<'a, C: Mix + Clone + 'a> {
    NotSlice(&'a Gradient<C>),
    Slice(Slice<'a, C>),
}

impl<'a, C: Mix + Clone> MaybeSlice<'a, C> {
    fn get(&self, i: C::Scalar) -> C {
        match *self {
            MaybeSlice::NotSlice(g) => g.get(i),
            MaybeSlice::Slice(ref s) => s.get(i),
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Gradient, Range};
    use LinSrgb;

    #[test]
    fn range_clamp() {
        let range: Range<f64> = (0.0..1.0).into();
        assert_eq!(range.clamp(-1.0), 0.0);
        assert_eq!(range.clamp(2.0), 1.0);
        assert_eq!(range.clamp(0.5), 0.5);
    }

    #[test]
    fn range_constrain() {
        let range: Range<f64> = (0.0..1.0).into();
        assert_eq!(range.constrain(&(-3.0..-5.0).into()), (0.0..0.0).into());
        assert_eq!(range.constrain(&(-3.0..0.8).into()), (0.0..0.8).into());

        assert_eq!(range.constrain(&(3.0..5.0).into()), (1.0..1.0).into());
        assert_eq!(range.constrain(&(0.2..5.0).into()), (0.2..1.0).into());

        assert_eq!(range.constrain(&(0.2..0.8).into()), (0.2..0.8).into());
    }

    #[test]
    fn simple_slice() {
        let g1 = Gradient::new(vec![
            LinSrgb::new(1.0, 0.0, 0.0),
            LinSrgb::new(0.0, 0.0, 1.0),
        ]);
        let g2 = g1.slice(..0.5);

        let v1: Vec<_> = g1.take(10).take(5).collect();
        let v2: Vec<_> = g2.take(5).collect();
        for (t1, t2) in v1.iter().zip(v2.iter()) {
            assert_relative_eq!(t1, t2);
        }
    }

    #[test]
    fn iter_rev_eq_rev_iter() {
        let g = Gradient::new(vec![
            LinSrgb::new(1.0, 0.0, 0.0),
            LinSrgb::new(0.0, 0.0, 1.0),
        ]);

        let v1: Vec<_> = g.take(10).collect::<Vec<_>>().iter().rev().cloned().collect();
        let v2: Vec<_> = g.take(10).rev().collect();
        assert_eq!(v1, v2);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2018 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

///! Import a new corpus into `CorTeX` from the command line.
///! Example run: $ ./target/release/examples/tex_to_html_import /data/arxmliv/ arXMLiv

extern crate cortex;
extern crate pericortex;
extern crate rustc_serialize;

// use std::collections::HashMap;
// use std::path::Path;
// use std::fs;
use std::env;
// use std::io::Read;
// use std::io::Error;

use std::thread;
use std::time::Duration;
use cortex::backend::{Backend, DEFAULT_DB_ADDRESS};
use cortex::models::{NewTask, Service, NewService};
use cortex::helpers::TaskStatus;
use cortex::manager::TaskManager;
use cortex::worker::InitWorker;
use pericortex::worker::Worker;

fn main() {
  let job_limit: Option<usize> = Some(1);
  let mut input_args = env::args();
  let _ = input_args.next();
  let mut corpus_path = match input_args.next() {
    Some(path) => path,
    None => "/arXMLiv/modern".to_string(),
  };
  if let Some(c) = corpus_path.pop() {
    if c != '/' {
      corpus_path.push(c);
    }
  }
  corpus_path.push('/');
  println!("-- Importing corpus at {:?} ...", &corpus_path);
  let backend = Backend::default();

  backend
    .add(&NewTask {
      entry: corpus_path.clone(),
      service_id: 1, // Init service always has id 1
      corpus_id: 1,
      status: TaskStatus::TODO.raw(),
    })
    .unwrap();

  // Let us thread out a ventilator on a special port
  // Start up a ventilator/sink pair
  thread::spawn(move || {
    let manager = TaskManager {
      source_port: 5757,
      result_port: 5758,
      queue_size: 100000,
      message_size: 100,
      backend_address: DEFAULT_DB_ADDRESS.to_string(),
    };
    assert!(manager.start(job_limit).is_ok());
  });

  // Start up an init worker
  let worker = InitWorker {
    service: "init".to_string(),
    version: 0.1,
    message_size: 100000,
    source: "tcp://localhost:5757".to_string(),
    sink: "tcp://localhost:5758".to_string(),
    backend_address: DEFAULT_DB_ADDRESS.to_string(),
  };
  // Perform a single echo task
  assert!(worker.start(job_limit).is_ok());
  // Wait for the final finisher to persist to DB
  thread::sleep(Duration::new(2, 0)); // TODO: Can this be deterministic? Join?

  // Then add a TeX-to-HTML service on this corpus.
  let service_name = "tex_to_html";
  let new_tex_to_html_service = NewService {
    name: service_name.to_string(),
    version: 0.1,
    inputformat: "tex".to_string(),
    outputformat: "html".to_string(),
    inputconverter: Some("import".to_string()),
    complex: true,
  };
  assert!(backend.add(&new_tex_to_html_service).is_ok());
  let service_registered_result = Service::find_by_name(service_name, &backend.connection);
  assert!(service_registered_result.is_ok());
  let service_registered = service_registered_result.unwrap();

  assert!(
    backend
      .register_service(&service_registered, &corpus_path)
      .is_ok()
  );
}
<commit_msg>default example should have no limit<commit_after>// Copyright 2015-2018 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

///! Import a new corpus into `CorTeX` from the command line.
///! Example run: $ ./target/release/examples/tex_to_html_import /data/arxmliv/ arXMLiv

extern crate cortex;
extern crate pericortex;
extern crate rustc_serialize;

// use std::collections::HashMap;
// use std::path::Path;
// use std::fs;
use std::env;
// use std::io::Read;
// use std::io::Error;

use std::thread;
use std::time::Duration;
use cortex::backend::{Backend, DEFAULT_DB_ADDRESS};
use cortex::models::{NewTask, Service, NewService};
use cortex::helpers::TaskStatus;
use cortex::manager::TaskManager;
use cortex::worker::InitWorker;
use pericortex::worker::Worker;

fn main() {
  let job_limit: Option<usize> = None;//Some(1);
  let mut input_args = env::args();
  let _ = input_args.next();
  let mut corpus_path = match input_args.next() {
    Some(path) => path,
    None => "/arXMLiv/modern".to_string(),
  };
  if let Some(c) = corpus_path.pop() {
    if c != '/' {
      corpus_path.push(c);
    }
  }
  corpus_path.push('/');
  println!("-- Importing corpus at {:?} ...", &corpus_path);
  let backend = Backend::default();

  backend
    .add(&NewTask {
      entry: corpus_path.clone(),
      service_id: 1, // Init service always has id 1
      corpus_id: 1,
      status: TaskStatus::TODO.raw(),
    })
    .unwrap();

  // Let us thread out a ventilator on a special port
  // Start up a ventilator/sink pair
  thread::spawn(move || {
    let manager = TaskManager {
      source_port: 5757,
      result_port: 5758,
      queue_size: 100000,
      message_size: 100,
      backend_address: DEFAULT_DB_ADDRESS.to_string(),
    };
    assert!(manager.start(job_limit).is_ok());
  });

  // Start up an init worker
  let worker = InitWorker {
    service: "init".to_string(),
    version: 0.1,
    message_size: 100000,
    source: "tcp://localhost:5757".to_string(),
    sink: "tcp://localhost:5758".to_string(),
    backend_address: DEFAULT_DB_ADDRESS.to_string(),
  };
  // Perform a single echo task
  assert!(worker.start(job_limit).is_ok());
  // Wait for the final finisher to persist to DB
  thread::sleep(Duration::new(2, 0)); // TODO: Can this be deterministic? Join?

  // Then add a TeX-to-HTML service on this corpus.
  let service_name = "tex_to_html";
  let new_tex_to_html_service = NewService {
    name: service_name.to_string(),
    version: 0.1,
    inputformat: "tex".to_string(),
    outputformat: "html".to_string(),
    inputconverter: Some("import".to_string()),
    complex: true,
  };
  assert!(backend.add(&new_tex_to_html_service).is_ok());
  let service_registered_result = Service::find_by_name(service_name, &backend.connection);
  assert!(service_registered_result.is_ok());
  let service_registered = service_registered_result.unwrap();

  assert!(
    backend
      .register_service(&service_registered, &corpus_path)
      .is_ok()
  );
}
<|endoftext|>


<commit_before>pub fn verse(n: i32) -> String {
    unimplemented!()
}

pub fn sing(start: i32, end: i32) -> String {
    unimplemented!()
}
<commit_msg>beer-song: eliminate stub warnings<commit_after>pub fn verse(n: i32) -> String {
    unimplemented!("emit verse {}", n)
}

pub fn sing(start: i32, end: i32) -> String {
    unimplemented!("sing verses {} to {}, inclusive", start, end)
}
<|endoftext|>