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

//! Weighted index sampling
//!
//! This module provides two implementations for sampling indices:
//!
//! *   [`WeightedIndex`] allows `O(log N)` sampling
//! *   [`alias_method::WeightedIndex`] allows `O(1)` sampling, but with
//!      much greater set-up cost
//!
//! [`alias_method::WeightedIndex`]: alias_method/struct.WeightedIndex.html

pub mod alias_method;

use crate::Rng;
use crate::distributions::Distribution;
use crate::distributions::uniform::{UniformSampler, SampleUniform, SampleBorrow};
use core::cmp::PartialOrd;
use core::fmt;

// Note that this whole module is only imported if feature="alloc" is enabled.
#[cfg(not(feature="std"))] use crate::alloc::vec::Vec;

/// A distribution using weighted sampling to pick a discretely selected
/// item.
///
/// Sampling a `WeightedIndex` distribution returns the index of a randomly
/// selected element from the iterator used when the `WeightedIndex` was
/// created. The chance of a given element being picked is proportional to the
/// value of the element. The weights can use any type `X` for which an
/// implementation of [`Uniform<X>`] exists.
///
/// # Performance
///
/// A `WeightedIndex<X>` contains a `Vec<X>` and a [`Uniform<X>`] and so its
/// size is the sum of the size of those objects, possibly plus some alignment.
///
/// Creating a `WeightedIndex<X>` will allocate enough space to hold `N - 1`
/// weights of type `X`, where `N` is the number of weights. However, since
/// `Vec` doesn't guarantee a particular growth strategy, additional memory
/// might be allocated but not used. Since the `WeightedIndex` object also
/// contains, this might cause additional allocations, though for primitive
/// types, ['Uniform<X>`] doesn't allocate any memory.
///
/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where
/// `N` is the number of weights.
///
/// Sampling from `WeightedIndex` will result in a single call to
/// `Uniform<X>::sample` (method of the [`Distribution`] trait), which typically
/// will request a single value from the underlying [`RngCore`], though the
/// exact number depends on the implementaiton of `Uniform<X>::sample`.
///
/// # Example
///
/// ```
/// use rand::prelude::*;
/// use rand::distributions::WeightedIndex;
///
/// let choices = ['a', 'b', 'c'];
/// let weights = [2,   1,   1];
/// let dist = WeightedIndex::new(&weights).unwrap();
/// let mut rng = thread_rng();
/// for _ in 0..100 {
///     // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c'
///     println!("{}", choices[dist.sample(&mut rng)]);
/// }
///
/// let items = [('a', 0), ('b', 3), ('c', 7)];
/// let dist2 = WeightedIndex::new(items.iter().map(|item| item.1)).unwrap();
/// for _ in 0..100 {
///     // 0% chance to print 'a', 30% chance to print 'b', 70% chance to print 'c'
///     println!("{}", items[dist2.sample(&mut rng)].0);
/// }
/// ```
///
/// [`Uniform<X>`]: crate::distributions::uniform::Uniform
/// [`RngCore`]: crate::RngCore
#[derive(Debug, Clone)]
pub struct WeightedIndex<X: SampleUniform + PartialOrd> {
    cumulative_weights: Vec<X>,
    weight_distribution: X::Sampler,
}

impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
    /// Creates a new a `WeightedIndex` [`Distribution`] using the values
    /// in `weights`. The weights can use any type `X` for which an
    /// implementation of [`Uniform<X>`] exists.
    ///
    /// Returns an error if the iterator is empty, if any weight is `< 0`, or
    /// if its total value is 0.
    ///
    /// [`Uniform<X>`]: crate::distributions::uniform::Uniform
    pub fn new<I>(weights: I) -> Result<WeightedIndex<X>, WeightedError>
        where I: IntoIterator,
              I::Item: SampleBorrow<X>,
              X: for<'a> ::core::ops::AddAssign<&'a X> +
                 Clone +
                 Default {
        let mut iter = weights.into_iter();
        let mut total_weight: X = iter.next()
                                      .ok_or(WeightedError::NoItem)?
                                      .borrow()
                                      .clone();

        let zero = <X as Default>::default();
        if total_weight < zero {
            return Err(WeightedError::InvalidWeight);
        }

        let mut weights = Vec::<X>::with_capacity(iter.size_hint().0);
        for w in iter {
            if *w.borrow() < zero {
                return Err(WeightedError::InvalidWeight);
            }
            weights.push(total_weight.clone());
            total_weight += w.borrow();
        }

        if total_weight == zero {
            return Err(WeightedError::AllWeightsZero);
        }
        let distr = X::Sampler::new(zero, total_weight);

        Ok(WeightedIndex { cumulative_weights: weights, weight_distribution: distr })
    }
}

impl<X> Distribution<usize> for WeightedIndex<X> where
    X: SampleUniform + PartialOrd {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
        use ::core::cmp::Ordering;
        let chosen_weight = self.weight_distribution.sample(rng);
        // Find the first item which has a weight *higher* than the chosen weight.
        self.cumulative_weights.binary_search_by(
            |w| if *w <= chosen_weight { Ordering::Less } else { Ordering::Greater }).unwrap_err()
    }
}

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

    #[test]
    #[cfg(not(miri))] // Miri is too slow
    fn test_weightedindex() {
        let mut r = crate::test::rng(700);
        const N_REPS: u32 = 5000;
        let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
        let total_weight = weights.iter().sum::<u32>() as f32;

        let verify = |result: [i32; 14]| {
            for (i, count) in result.iter().enumerate() {
                let exp = (weights[i] * N_REPS) as f32 / total_weight;
                let mut err = (*count as f32 - exp).abs();
                if err != 0.0 {
                    err /= exp;
                }
                assert!(err <= 0.25);
            }
        };

        // WeightedIndex from vec
        let mut chosen = [0i32; 14];
        let distr = WeightedIndex::new(weights.to_vec()).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        // WeightedIndex from slice
        chosen = [0i32; 14];
        let distr = WeightedIndex::new(&weights[..]).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        // WeightedIndex from iterator
        chosen = [0i32; 14];
        let distr = WeightedIndex::new(weights.iter()).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        for _ in 0..5 {
            assert_eq!(WeightedIndex::new(&[0, 1]).unwrap().sample(&mut r), 1);
            assert_eq!(WeightedIndex::new(&[1, 0]).unwrap().sample(&mut r), 0);
            assert_eq!(WeightedIndex::new(&[0, 0, 0, 0, 10, 0]).unwrap().sample(&mut r), 4);
        }

        assert_eq!(WeightedIndex::new(&[10][0..0]).unwrap_err(), WeightedError::NoItem);
        assert_eq!(WeightedIndex::new(&[0]).unwrap_err(), WeightedError::AllWeightsZero);
        assert_eq!(WeightedIndex::new(&[10, 20, -1, 30]).unwrap_err(), WeightedError::InvalidWeight);
        assert_eq!(WeightedIndex::new(&[-10, 20, 1, 30]).unwrap_err(), WeightedError::InvalidWeight);
        assert_eq!(WeightedIndex::new(&[-10]).unwrap_err(), WeightedError::InvalidWeight);
    }
}

/// Error type returned from `WeightedIndex::new`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WeightedError {
    /// The provided weight collection contains no items.
    NoItem,

    /// A weight is either less than zero, greater than the supported maximum or
    /// otherwise invalid.
    InvalidWeight,

    /// All items in the provided weight collection are zero.
    AllWeightsZero,

    /// Too many weights are provided (length greater than `u32::MAX`)
    TooMany,
}

impl WeightedError {
    fn msg(&self) -> &str {
        match *self {
            WeightedError::NoItem => "No weights provided.",
            WeightedError::InvalidWeight => "A weight is invalid.",
            WeightedError::AllWeightsZero => "All weights are zero.",
            WeightedError::TooMany => "Too many weights (hit u32::MAX)",
        }
    }
}

#[cfg(feature="std")]
impl ::std::error::Error for WeightedError {
    fn description(&self) -> &str {
        self.msg()
    }
    fn cause(&self) -> Option<&dyn (::std::error::Error)> {
        None
    }
}

impl fmt::Display for WeightedError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.msg())
    }
}
<commit_msg>WeightedIndex: Make it possible to update a subset of weights<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Weighted index sampling
//!
//! This module provides two implementations for sampling indices:
//!
//! *   [`WeightedIndex`] allows `O(log N)` sampling
//! *   [`alias_method::WeightedIndex`] allows `O(1)` sampling, but with
//!      much greater set-up cost
//!
//! [`alias_method::WeightedIndex`]: alias_method/struct.WeightedIndex.html

pub mod alias_method;

use crate::Rng;
use crate::distributions::Distribution;
use crate::distributions::uniform::{UniformSampler, SampleUniform, SampleBorrow};
use core::cmp::PartialOrd;
use core::fmt;

// Note that this whole module is only imported if feature="alloc" is enabled.
#[cfg(not(feature="std"))] use crate::alloc::vec::Vec;

/// A distribution using weighted sampling to pick a discretely selected
/// item.
///
/// Sampling a `WeightedIndex` distribution returns the index of a randomly
/// selected element from the iterator used when the `WeightedIndex` was
/// created. The chance of a given element being picked is proportional to the
/// value of the element. The weights can use any type `X` for which an
/// implementation of [`Uniform<X>`] exists.
///
/// # Performance
///
/// A `WeightedIndex<X>` contains a `Vec<X>` and a [`Uniform<X>`] and so its
/// size is the sum of the size of those objects, possibly plus some alignment.
///
/// Creating a `WeightedIndex<X>` will allocate enough space to hold `N - 1`
/// weights of type `X`, where `N` is the number of weights. However, since
/// `Vec` doesn't guarantee a particular growth strategy, additional memory
/// might be allocated but not used. Since the `WeightedIndex` object also
/// contains, this might cause additional allocations, though for primitive
/// types, ['Uniform<X>`] doesn't allocate any memory.
///
/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where
/// `N` is the number of weights.
///
/// Sampling from `WeightedIndex` will result in a single call to
/// `Uniform<X>::sample` (method of the [`Distribution`] trait), which typically
/// will request a single value from the underlying [`RngCore`], though the
/// exact number depends on the implementaiton of `Uniform<X>::sample`.
///
/// # Example
///
/// ```
/// use rand::prelude::*;
/// use rand::distributions::WeightedIndex;
///
/// let choices = ['a', 'b', 'c'];
/// let weights = [2,   1,   1];
/// let dist = WeightedIndex::new(&weights).unwrap();
/// let mut rng = thread_rng();
/// for _ in 0..100 {
///     // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c'
///     println!("{}", choices[dist.sample(&mut rng)]);
/// }
///
/// let items = [('a', 0), ('b', 3), ('c', 7)];
/// let dist2 = WeightedIndex::new(items.iter().map(|item| item.1)).unwrap();
/// for _ in 0..100 {
///     // 0% chance to print 'a', 30% chance to print 'b', 70% chance to print 'c'
///     println!("{}", items[dist2.sample(&mut rng)].0);
/// }
/// ```
///
/// [`Uniform<X>`]: crate::distributions::uniform::Uniform
/// [`RngCore`]: crate::RngCore
#[derive(Debug, Clone)]
pub struct WeightedIndex<X: SampleUniform + PartialOrd> {
    cumulative_weights: Vec<X>,
    total_weight: X,
    weight_distribution: X::Sampler,
}

impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
    /// Creates a new a `WeightedIndex` [`Distribution`] using the values
    /// in `weights`. The weights can use any type `X` for which an
    /// implementation of [`Uniform<X>`] exists.
    ///
    /// Returns an error if the iterator is empty, if any weight is `< 0`, or
    /// if its total value is 0.
    ///
    /// [`Uniform<X>`]: crate::distributions::uniform::Uniform
    pub fn new<I>(weights: I) -> Result<WeightedIndex<X>, WeightedError>
        where I: IntoIterator,
              I::Item: SampleBorrow<X>,
              X: for<'a> ::core::ops::AddAssign<&'a X> +
                 Clone +
                 Default {
        let mut iter = weights.into_iter();
        let mut total_weight: X = iter.next()
                                      .ok_or(WeightedError::NoItem)?
                                      .borrow()
                                      .clone();

        let zero = <X as Default>::default();
        if total_weight < zero {
            return Err(WeightedError::InvalidWeight);
        }

        let mut weights = Vec::<X>::with_capacity(iter.size_hint().0);
        for w in iter {
            if *w.borrow() < zero {
                return Err(WeightedError::InvalidWeight);
            }
            weights.push(total_weight.clone());
            total_weight += w.borrow();
        }

        if total_weight == zero {
            return Err(WeightedError::AllWeightsZero);
        }
        let distr = X::Sampler::new(zero, total_weight.clone());

        Ok(WeightedIndex { cumulative_weights: weights, total_weight, weight_distribution: distr })
    }

    /// Update a subset of weights, without changing the number of weights.
    ///
    /// Using this method instead of `new` might be more efficient if only a small number of
    /// weights is modified. For weights that are `Copy`, no allocations are performed.
    ///
    /// In case of error, `self` is not modified.
    pub fn update_weights(&mut self, new_weights: &[(usize, &X)]) -> Result<(), WeightedError>
        where X: for<'a> ::core::ops::AddAssign<&'a X> +
                 for<'a> ::core::ops::SubAssign<&'a X> +
                 Clone +
                 Default {
        let zero = <X as Default>::default();

        let mut total_weight = self.total_weight.clone();

        for &(i, w) in new_weights {
            if *w < zero {
                return Err(WeightedError::InvalidWeight);
            }
            if i >= self.cumulative_weights.len() {
                return Err(WeightedError::TooMany);
            }

            // Unfortunately, we will have to calculate the non-cumulative weight a second time, to
            // avoid producing an invalid state of `self`.
            let mut old_w = self.cumulative_weights[i].clone();
            if i > 0 {
                old_w -= &self.cumulative_weights[i - 1];
            }

            total_weight -= &old_w;
            total_weight += w;
        }
        if total_weight == zero {
            return Err(WeightedError::AllWeightsZero);
        }

        for &(i, w) in new_weights {
            let mut old_w = self.cumulative_weights[i].clone();
            if i > 0 {
                old_w -= &self.cumulative_weights[i - 1];
            }

            for j in i..self.cumulative_weights.len() {
                self.cumulative_weights[j] -= &old_w;
                self.cumulative_weights[j] += w;
            }
        }
        self.total_weight = total_weight;
        self.weight_distribution = X::Sampler::new(zero, self.total_weight.clone());

        Ok(())
    }
}

impl<X> Distribution<usize> for WeightedIndex<X> where
    X: SampleUniform + PartialOrd {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
        use ::core::cmp::Ordering;
        let chosen_weight = self.weight_distribution.sample(rng);
        // Find the first item which has a weight *higher* than the chosen weight.
        self.cumulative_weights.binary_search_by(
            |w| if *w <= chosen_weight { Ordering::Less } else { Ordering::Greater }).unwrap_err()
    }
}

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

    #[test]
    #[cfg(not(miri))] // Miri is too slow
    fn test_weightedindex() {
        let mut r = crate::test::rng(700);
        const N_REPS: u32 = 5000;
        let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
        let total_weight = weights.iter().sum::<u32>() as f32;

        let verify = |result: [i32; 14]| {
            for (i, count) in result.iter().enumerate() {
                let exp = (weights[i] * N_REPS) as f32 / total_weight;
                let mut err = (*count as f32 - exp).abs();
                if err != 0.0 {
                    err /= exp;
                }
                assert!(err <= 0.25);
            }
        };

        // WeightedIndex from vec
        let mut chosen = [0i32; 14];
        let distr = WeightedIndex::new(weights.to_vec()).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        // WeightedIndex from slice
        chosen = [0i32; 14];
        let distr = WeightedIndex::new(&weights[..]).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        // WeightedIndex from iterator
        chosen = [0i32; 14];
        let distr = WeightedIndex::new(weights.iter()).unwrap();
        for _ in 0..N_REPS {
            chosen[distr.sample(&mut r)] += 1;
        }
        verify(chosen);

        for _ in 0..5 {
            assert_eq!(WeightedIndex::new(&[0, 1]).unwrap().sample(&mut r), 1);
            assert_eq!(WeightedIndex::new(&[1, 0]).unwrap().sample(&mut r), 0);
            assert_eq!(WeightedIndex::new(&[0, 0, 0, 0, 10, 0]).unwrap().sample(&mut r), 4);
        }

        assert_eq!(WeightedIndex::new(&[10][0..0]).unwrap_err(), WeightedError::NoItem);
        assert_eq!(WeightedIndex::new(&[0]).unwrap_err(), WeightedError::AllWeightsZero);
        assert_eq!(WeightedIndex::new(&[10, 20, -1, 30]).unwrap_err(), WeightedError::InvalidWeight);
        assert_eq!(WeightedIndex::new(&[-10, 20, 1, 30]).unwrap_err(), WeightedError::InvalidWeight);
        assert_eq!(WeightedIndex::new(&[-10]).unwrap_err(), WeightedError::InvalidWeight);
    }

    #[test]
    fn test_update_weights() {
        let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
        let total_weight = weights.iter().sum::<u32>();
        let mut distr = WeightedIndex::new(weights.to_vec()).unwrap();
        assert_eq!(distr.total_weight, total_weight);

        distr.update_weights(&[(2, &4), (5, &1)]).unwrap();
        let expected_weights = [1u32, 2, 4, 0, 5, 1, 7, 1, 2, 3, 4, 5, 6, 7];
        let expected_total_weight = expected_weights.iter().sum::<u32>();
        let expected_distr = WeightedIndex::new(expected_weights.to_vec()).unwrap();
        assert_eq!(distr.total_weight, expected_total_weight);
        assert_eq!(distr.total_weight, expected_distr.total_weight);
        assert_eq!(distr.cumulative_weights, expected_distr.cumulative_weights);
    }
}

/// Error type returned from `WeightedIndex::new`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WeightedError {
    /// The provided weight collection contains no items.
    NoItem,

    /// A weight is either less than zero, greater than the supported maximum or
    /// otherwise invalid.
    InvalidWeight,

    /// All items in the provided weight collection are zero.
    AllWeightsZero,

    /// Too many weights are provided (length greater than `u32::MAX`)
    TooMany,
}

impl WeightedError {
    fn msg(&self) -> &str {
        match *self {
            WeightedError::NoItem => "No weights provided.",
            WeightedError::InvalidWeight => "A weight is invalid.",
            WeightedError::AllWeightsZero => "All weights are zero.",
            WeightedError::TooMany => "Too many weights (hit u32::MAX)",
        }
    }
}

#[cfg(feature="std")]
impl ::std::error::Error for WeightedError {
    fn description(&self) -> &str {
        self.msg()
    }
    fn cause(&self) -> Option<&dyn (::std::error::Error)> {
        None
    }
}

impl fmt::Display for WeightedError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.msg())
    }
}
<|endoftext|>


<commit_before>use super::compact::{Compact};
use super::chunked::{MemChunker, SizedChunkedArena, MultiSized};
use super::slot_map::{SlotIndices, SlotMap};
use super::messaging::{Actor, Individual, Recipient, Message, Packet, Fate};
use super::actor_system::{ID};
use ::std::marker::PhantomData;

pub struct Swarm<Actor> {
    actors: MultiSized<SizedChunkedArena>,
    slot_map: SlotMap,
    _marker: PhantomData<[Actor]>
}

const CHUNK_SIZE : usize = 4096 * 128;

impl<A: Actor> Swarm<A> {
    pub fn new() -> Self {
        let chunker = MemChunker::new("", CHUNK_SIZE);
        Swarm{
            actors: MultiSized::new(chunker.child("_actors"), A::typical_size()),
            slot_map: SlotMap::new(chunker.child("_slot_map")),
            _marker: PhantomData
        }
    }

    fn allocate_instance_id(&mut self) -> (usize, usize) {
        self.slot_map.allocate_id()
    }

    fn at_index(&self, index: SlotIndices) -> &A {
        unsafe {&*(self.actors.collections[index.collection()].at(index.slot()) as *const A)}
    }

    fn at_index_mut(&mut self, index: SlotIndices) -> &mut A {
        unsafe {&mut *(self.actors.collections[index.collection()].at_mut(index.slot()) as *mut A)}
    }

    fn at_mut(&mut self, id: usize) -> &mut A {
        let index = *self.slot_map.indices_of(id);
        self.at_index_mut(index)
    }

    fn add(&mut self, initial_state: &A) -> ID {
        let id = unsafe{(*super::actor_system::THE_SYSTEM).instance_id::<A>(self.allocate_instance_id())};
        let size = initial_state.total_size_bytes();
        let collection_index = self.actors.size_to_index(size);
        let collection = &mut self.actors.sized_for_mut(size);
        let (ptr, index) = collection.push();

        self.slot_map.associate(id.instance_id as usize, SlotIndices::new(collection_index, index));
        assert!(self.slot_map.indices_of(id.instance_id as usize).collection() == collection_index);

        unsafe {
            let actor_in_slot = &mut *(ptr as *mut A);
            actor_in_slot.compact_behind_from(initial_state);
            actor_in_slot.set_id(id)
        }
        id
    }

    fn swap_remove(&mut self, indices: SlotIndices) -> bool {
        unsafe {
            let collection = &mut self.actors.collections[indices.collection()];
            match collection.swap_remove(indices.slot()) {
                Some(ptr) => {
                    let swapped_actor = &*(ptr as *mut A);
                    self.slot_map.associate(swapped_actor.id().instance_id as usize, indices);
                    true
                },
                None => false
            }

        }
    }

    fn remove(&mut self, id: ID) {
        let i = *self.slot_map.indices_of(id.instance_id as usize);
        self.remove_at_index(i, id);
    }

    fn remove_at_index(&mut self, i: SlotIndices, id: ID) {
        self.swap_remove(i);
        self.slot_map.free(id.instance_id as usize, id.version as usize);
    }

    fn resize(&mut self, id: usize) -> bool {
        let index = *self.slot_map.indices_of(id);
        self.resize_at_index(index)
    }

    fn resize_at_index(&mut self, old_i: SlotIndices) -> bool {
        let old_actor_ptr = self.at_index(old_i) as *const A;
        self.add(unsafe{&*old_actor_ptr});
        self.swap_remove(old_i)
    }

    fn receive_instance<M: Message>(&mut self, packet: &Packet<M>) where A: Recipient<M> {
        let (fate, is_still_compact) = {
            let actor = self.at_mut(packet.recipient_id.instance_id as usize);
            let fate = actor.receive_packet(packet);
            (fate, actor.is_still_compact())
        };

        match fate {
            Fate::Live => {
                if !is_still_compact {
                    self.resize(packet.recipient_id.instance_id as usize);
                }
            },
            Fate::Die | Fate::Explode(..) => self.remove(packet.recipient_id)
        }
    }

    fn receive_broadcast<M: Message>(&mut self, packet: &Packet<M>) where A: Recipient<M> {
        // this function has to deal with the fact that during the iteration, receivers of the broadcast can be resized
        // and thus removed from a collection, swapping in either
        //    - other receivers that didn't receive the broadcast yet
        //    - resized and added receivers that alredy received the broadcast
        //    - actors that were created during one of the broadcast receive handlers, that shouldn't receive this broadcast
        // the only assumption is that no actors are immediately completely deleted

        let recipients_todo_per_collection : Vec<usize> = {
            self.actors.collections.iter().map(|collection| {collection.len()}).collect()
        };

        let n_collections = self.actors.collections.len();

        for (c, recipients_todo) in recipients_todo_per_collection.iter().enumerate().take(n_collections) {
            let mut slot = 0;
            let mut index_after_last_recipient = *recipients_todo;

            for _ in 0..*recipients_todo {
                let index = SlotIndices::new(c, slot);
                let (fate, is_still_compact, id) = {
                    let actor = self.at_index_mut(index);
                    let fate = actor.receive_packet(packet);
                    (fate, actor.is_still_compact(), actor.id())
                };

                let repeat_slot = match fate {
                    Fate::Live => if is_still_compact {
                            false
                        } else {
                            self.resize_at_index(index);
                            // this should also work in the case where the "resized" actor itself is added to the same collection again
                            let swapped_in_another_receiver = self.actors.collections[c].len() < index_after_last_recipient;
                            if swapped_in_another_receiver {
                                index_after_last_recipient -= 1;
                                true
                            } else {
                                false
                            }
                        },
                    Fate::Die | Fate::Explode(..) => {
                        self.remove_at_index(index, id);
                        // this should also work in the case where the "resized" actor itself is added to the same collection again
                        let swapped_in_another_receiver = self.actors.collections[c].len() < index_after_last_recipient;
                        if swapped_in_another_receiver {
                            index_after_last_recipient -= 1;
                            true
                        } else {
                            false
                        }
                    }
                };

                if !repeat_slot {
                    slot += 1;
                }
            }
        }
    }

    pub fn all() -> ID where Self: Sized {
        unsafe{(*super::actor_system::THE_SYSTEM).broadcast_id::<A>()}
    }
}

impl <A: Actor> Individual for Swarm<A> {}

pub trait RecipientAsSwarm<M: Message> : Sized {
    fn receive_packet(swarm: &mut Swarm<Self>, packet: &Packet<M>) -> Fate {
        Self::receive(swarm, &packet.message)
    }
    fn receive(_swarm: &mut Swarm<Self>, _message: &M) -> Fate {unimplemented!()}
}

impl <M: Message, A: Actor + RecipientAsSwarm<M>> Recipient<M> for Swarm<A> {
    fn receive_packet(&mut self, packet: &Packet<M>) -> Fate {
        A::receive_packet(self, packet)
    }
}

impl <M: Message + NotACreateMessage, A: Actor + Recipient<M>> RecipientAsSwarm<M> for A {
    fn receive_packet(swarm: &mut Swarm<A>, packet: &Packet<M>) -> Fate {
        if packet.recipient_id.is_broadcast() {
            swarm.receive_broadcast(packet);
        } else {
            swarm.receive_instance(packet);
        }
        Fate::Live
    }
}

#[derive(Clone)]
pub struct Create<A: Actor>(pub A);

impl<A: Actor> Compact for Create<A> {
    fn is_still_compact(&self) -> bool {self.0.is_still_compact()}
    fn dynamic_size_bytes(&self) -> usize {self.0.dynamic_size_bytes()}
    unsafe fn compact_from(&mut self, source: &Self, new_dynamic_part: *mut u8) {
        self.0.compact_from(&source.0, new_dynamic_part);
    }
}

pub trait NotACreateMessage {}

impl NotACreateMessage for .. {}

impl <A: Actor> !NotACreateMessage for Create<A> {}
impl <A: Actor, M: Message> !NotACreateMessage for CreateWith<A, M> {}

impl <A: Actor> RecipientAsSwarm<Create<A>> for A {
    fn receive(swarm: &mut Swarm<A>, msg: &Create<A>) -> Fate {match *msg{
        Create(ref initial_state) => {
            swarm.add(initial_state);
            Fate::Live
        }
    }}
}

#[derive(Clone)]
pub struct CreateWith<A: Actor, M: Message>(pub A, pub M);

impl<A: Actor, M: Message> Compact for CreateWith<A, M> {
    fn is_still_compact(&self) -> bool {self.0.is_still_compact() && self.1.is_still_compact()}
    fn dynamic_size_bytes(&self) -> usize {self.0.dynamic_size_bytes() + self.1.dynamic_size_bytes()}
    unsafe fn compact_from(&mut self, source: &Self, new_dynamic_part: *mut u8) {
        self.0.compact_from(&source.0, new_dynamic_part);
        self.1.compact_from(&source.1, new_dynamic_part.offset(self.0.dynamic_size_bytes() as isize))
    }
}

impl <M: Message, A: Actor + Recipient<M>> RecipientAsSwarm<CreateWith<A, M>> for A {
    fn receive(swarm: &mut Swarm<A>, msg: &CreateWith<A, M>) -> Fate {match *msg{
        CreateWith(ref initial_state, ref initial_message) => {
            let id = swarm.add(initial_state);
            let initial_packet = Packet{
                recipient_id: id,
                message: (*initial_message).clone()
            };
            swarm.receive_instance(&initial_packet);
            Fate::Live
        }
    }}
}<commit_msg>Critical fix in swarm.rs 💣<commit_after>use super::compact::{Compact};
use super::chunked::{MemChunker, SizedChunkedArena, MultiSized};
use super::slot_map::{SlotIndices, SlotMap};
use super::messaging::{Actor, Individual, Recipient, Message, Packet, Fate};
use super::actor_system::{ID};
use ::std::marker::PhantomData;

pub struct Swarm<Actor> {
    actors: MultiSized<SizedChunkedArena>,
    slot_map: SlotMap,
    _marker: PhantomData<[Actor]>
}

const CHUNK_SIZE : usize = 4096 * 128;

impl<A: Actor> Swarm<A> {
    pub fn new() -> Self {
        let chunker = MemChunker::new("", CHUNK_SIZE);
        Swarm{
            actors: MultiSized::new(chunker.child("_actors"), A::typical_size()),
            slot_map: SlotMap::new(chunker.child("_slot_map")),
            _marker: PhantomData
        }
    }

    fn allocate_instance_id(&mut self) -> (usize, usize) {
        self.slot_map.allocate_id()
    }

    fn at_index(&self, index: SlotIndices) -> &A {
        unsafe {&*(self.actors.collections[index.collection()].at(index.slot()) as *const A)}
    }

    fn at_index_mut(&mut self, index: SlotIndices) -> &mut A {
        unsafe {&mut *(self.actors.collections[index.collection()].at_mut(index.slot()) as *mut A)}
    }

    fn at_mut(&mut self, id: usize) -> &mut A {
        let index = *self.slot_map.indices_of(id);
        self.at_index_mut(index)
    }

    fn add(&mut self, initial_state: &A) -> ID {
        let id = unsafe{(*super::actor_system::THE_SYSTEM).instance_id::<A>(self.allocate_instance_id())};
        self.add_with_id(initial_state, id);
        id
    }

    fn add_with_id(&mut self, initial_state: &A, id: ID) {
        let size = initial_state.total_size_bytes();
        let collection_index = self.actors.size_to_index(size);
        let collection = &mut self.actors.sized_for_mut(size);
        let (ptr, index) = collection.push();

        self.slot_map.associate(id.instance_id as usize, SlotIndices::new(collection_index, index));
        assert!(self.slot_map.indices_of(id.instance_id as usize).collection() == collection_index);

        unsafe {
            let actor_in_slot = &mut *(ptr as *mut A);
            actor_in_slot.compact_behind_from(initial_state);
            actor_in_slot.set_id(id)
        }
    }

    fn swap_remove(&mut self, indices: SlotIndices) -> bool {
        unsafe {
            let collection = &mut self.actors.collections[indices.collection()];
            match collection.swap_remove(indices.slot()) {
                Some(ptr) => {
                    let swapped_actor = &*(ptr as *mut A);
                    self.slot_map.associate(swapped_actor.id().instance_id as usize, indices);
                    true
                },
                None => false
            }

        }
    }

    fn remove(&mut self, id: ID) {
        let i = *self.slot_map.indices_of(id.instance_id as usize);
        self.remove_at_index(i, id);
    }

    fn remove_at_index(&mut self, i: SlotIndices, id: ID) {
        self.swap_remove(i);
        self.slot_map.free(id.instance_id as usize, id.version as usize);
    }

    fn resize(&mut self, id: usize) -> bool {
        let index = *self.slot_map.indices_of(id);
        self.resize_at_index(index)
    }

    fn resize_at_index(&mut self, old_i: SlotIndices) -> bool {
        let old_actor_ptr = self.at_index(old_i) as *const A;
        let old_actor = unsafe{&*old_actor_ptr};
        self.add_with_id(old_actor, old_actor.id());
        self.swap_remove(old_i)
    }

    fn receive_instance<M: Message>(&mut self, packet: &Packet<M>) where A: Recipient<M> {
        let (fate, is_still_compact) = {
            let actor = self.at_mut(packet.recipient_id.instance_id as usize);
            let fate = actor.receive_packet(packet);
            (fate, actor.is_still_compact())
        };

        match fate {
            Fate::Live => {
                if !is_still_compact {
                    self.resize(packet.recipient_id.instance_id as usize);
                }
            },
            Fate::Die | Fate::Explode(..) => self.remove(packet.recipient_id)
        }
    }

    fn receive_broadcast<M: Message>(&mut self, packet: &Packet<M>) where A: Recipient<M> {
        // this function has to deal with the fact that during the iteration, receivers of the broadcast can be resized
        // and thus removed from a collection, swapping in either
        //    - other receivers that didn't receive the broadcast yet
        //    - resized and added receivers that alredy received the broadcast
        //    - actors that were created during one of the broadcast receive handlers, that shouldn't receive this broadcast
        // the only assumption is that no actors are immediately completely deleted

        let recipients_todo_per_collection : Vec<usize> = {
            self.actors.collections.iter().map(|collection| {collection.len()}).collect()
        };

        let n_collections = self.actors.collections.len();

        for (c, recipients_todo) in recipients_todo_per_collection.iter().enumerate().take(n_collections) {
            let mut slot = 0;
            let mut index_after_last_recipient = *recipients_todo;

            for _ in 0..*recipients_todo {
                let index = SlotIndices::new(c, slot);
                let (fate, is_still_compact, id) = {
                    let actor = self.at_index_mut(index);
                    let fate = actor.receive_packet(packet);
                    (fate, actor.is_still_compact(), actor.id())
                };

                let repeat_slot = match fate {
                    Fate::Live => if is_still_compact {
                            false
                        } else {
                            self.resize_at_index(index);
                            // this should also work in the case where the "resized" actor itself is added to the same collection again
                            let swapped_in_another_receiver = self.actors.collections[c].len() < index_after_last_recipient;
                            if swapped_in_another_receiver {
                                index_after_last_recipient -= 1;
                                true
                            } else {
                                false
                            }
                        },
                    Fate::Die | Fate::Explode(..) => {
                        self.remove_at_index(index, id);
                        // this should also work in the case where the "resized" actor itself is added to the same collection again
                        let swapped_in_another_receiver = self.actors.collections[c].len() < index_after_last_recipient;
                        if swapped_in_another_receiver {
                            index_after_last_recipient -= 1;
                            true
                        } else {
                            false
                        }
                    }
                };

                if !repeat_slot {
                    slot += 1;
                }
            }
        }
    }

    pub fn all() -> ID where Self: Sized {
        unsafe{(*super::actor_system::THE_SYSTEM).broadcast_id::<A>()}
    }
}

impl <A: Actor> Individual for Swarm<A> {}

pub trait RecipientAsSwarm<M: Message> : Sized {
    fn receive_packet(swarm: &mut Swarm<Self>, packet: &Packet<M>) -> Fate {
        Self::receive(swarm, &packet.message)
    }
    fn receive(_swarm: &mut Swarm<Self>, _message: &M) -> Fate {unimplemented!()}
}

impl <M: Message, A: Actor + RecipientAsSwarm<M>> Recipient<M> for Swarm<A> {
    fn receive_packet(&mut self, packet: &Packet<M>) -> Fate {
        A::receive_packet(self, packet)
    }
}

impl <M: Message + NotACreateMessage, A: Actor + Recipient<M>> RecipientAsSwarm<M> for A {
    fn receive_packet(swarm: &mut Swarm<A>, packet: &Packet<M>) -> Fate {
        if packet.recipient_id.is_broadcast() {
            swarm.receive_broadcast(packet);
        } else {
            swarm.receive_instance(packet);
        }
        Fate::Live
    }
}

#[derive(Clone)]
pub struct Create<A: Actor>(pub A);

impl<A: Actor> Compact for Create<A> {
    fn is_still_compact(&self) -> bool {self.0.is_still_compact()}
    fn dynamic_size_bytes(&self) -> usize {self.0.dynamic_size_bytes()}
    unsafe fn compact_from(&mut self, source: &Self, new_dynamic_part: *mut u8) {
        self.0.compact_from(&source.0, new_dynamic_part);
    }
}

pub trait NotACreateMessage {}

impl NotACreateMessage for .. {}

impl <A: Actor> !NotACreateMessage for Create<A> {}
impl <A: Actor, M: Message> !NotACreateMessage for CreateWith<A, M> {}

impl <A: Actor> RecipientAsSwarm<Create<A>> for A {
    fn receive(swarm: &mut Swarm<A>, msg: &Create<A>) -> Fate {match *msg{
        Create(ref initial_state) => {
            swarm.add(initial_state);
            Fate::Live
        }
    }}
}

#[derive(Clone)]
pub struct CreateWith<A: Actor, M: Message>(pub A, pub M);

impl<A: Actor, M: Message> Compact for CreateWith<A, M> {
    fn is_still_compact(&self) -> bool {self.0.is_still_compact() && self.1.is_still_compact()}
    fn dynamic_size_bytes(&self) -> usize {self.0.dynamic_size_bytes() + self.1.dynamic_size_bytes()}
    unsafe fn compact_from(&mut self, source: &Self, new_dynamic_part: *mut u8) {
        self.0.compact_from(&source.0, new_dynamic_part);
        self.1.compact_from(&source.1, new_dynamic_part.offset(self.0.dynamic_size_bytes() as isize))
    }
}

impl <M: Message, A: Actor + Recipient<M>> RecipientAsSwarm<CreateWith<A, M>> for A {
    fn receive(swarm: &mut Swarm<A>, msg: &CreateWith<A, M>) -> Fate {match *msg{
        CreateWith(ref initial_state, ref initial_message) => {
            let id = swarm.add(initial_state);
            let initial_packet = Packet{
                recipient_id: id,
                message: (*initial_message).clone()
            };
            swarm.receive_instance(&initial_packet);
            Fate::Live
        }
    }}
}<|endoftext|>


<commit_before>use std::ops::Range;
use vk;

#[derive(Debug, Clone)]
pub enum ViewportsState {
    Fixed {
        data: Vec<(Viewport, Scissor)>,
    },

    DynamicViewports {
        scissors: Vec<Scissor>,
    },

    DynamicScissors {
        viewports: Vec<Viewport>,
    },

    Dynamic {
        num: u32,
    },
}

impl ViewportsState {
    pub fn dynamic_viewports(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => true,
            ViewportsState::DynamicScissors { .. } => false,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    pub fn dynamic_scissors(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => false,
            ViewportsState::DynamicScissors { .. } => true,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    pub fn num_viewports(&self) -> u32 {
        match *self {
            ViewportsState::Fixed { ref data } => data.len() as u32,
            ViewportsState::DynamicViewports { ref scissors } => scissors.len() as u32,
            ViewportsState::DynamicScissors { ref viewports } => viewports.len() as u32,
            ViewportsState::Dynamic { num } => num,
        }
    }
}

#[derive(Debug, Clone)]
pub struct Viewport {
    pub origin: [f32; 2],
    pub dimensions: [f32; 2],
    pub depth_range: Range<f32>,
}

#[doc(hidden)]
impl Into<vk::Viewport> for Viewport {
    #[inline]
    fn into(self) -> vk::Viewport {
        vk::Viewport {
            x: self.origin[0],
            y: self.origin[1],
            width: self.dimensions[0],
            height: self.dimensions[1],
            minDepth: self.depth_range.start,
            maxDepth: self.depth_range.end,
        }
    }
}

#[derive(Debug, Clone)]
pub struct Scissor {
    pub origin: [i32; 2],
    pub dimensions: [u32; 2],
}

#[doc(hidden)]
impl Into<vk::Rect2D> for Scissor {
    #[inline]
    fn into(self) -> vk::Rect2D {
        vk::Rect2D {
            offset: vk::Offset2D {
                x: self.origin[0],
                y: self.origin[1],
            },
            extent: vk::Extent2D {
                width: self.dimensions[0],
                height: self.dimensions[1],
            },
        }
    }
}
<commit_msg>Add docs to viewport.rs<commit_after>//! Viewports and scissor boxes.
//!
//! There are two different concepts to determine where things will be drawn:
//!
//! - The viewport is the region of the image which corresponds to the
//!   vertex coordinates `-1.0` to `1.0`.
//! - Any pixel outside of the scissor box will be discarded.
//!
//! In other words modifying the viewport will stretch the image, while modifying the scissor
//! box acts like a filter.
//!
//! It is legal and sensible to use a viewport that is larger than the target image.
//!
//! # Multiple viewports
//!
//! In most situations, you only need a single viewport and a single scissor box.
//!
//! If, however, you use a geometry shader, you can specify multiple viewports and scissor boxes.
//! Then in your geometry shader you can specify in which viewport and scissor box the primitive
//! should be written to. In GLSL this is done by writing to the special variable
//! `gl_ViewportIndex`.
//!
//! # Dynamic and fixed
//!
//! Vulkan allows four different setups:
//!
//! - The state of both the viewports and scissor boxes is known at pipeline creation.
//! - The state of viewports is known at pipeline creation, but the state of scissor boxes is
//!   only known when submitting the draw command.
//! - The state of scissor boxes is known at pipeline creation, but the state of viewports is
//!   only known when submitting the draw command.
//! - The state of both the viewports and scissor boxes is only known when submitting the
//!   draw command.
//!
//! In all cases the number of viewports and scissor boxes must be the same.
//!
use std::ops::Range;
use vk;

/// List of viewports and scissors that are used when creating a graphics pipeline object.
///
/// Note that the number of viewports and scissors must be the same.
#[derive(Debug, Clone)]
pub enum ViewportsState {
    /// The state is known in advance.
    Fixed {
        /// State of the viewports and scissors.
        data: Vec<(Viewport, Scissor)>,
    },

    /// The state of scissors is known in advance, but the state of viewports is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicViewports {
        /// State of the scissors.
        scissors: Vec<Scissor>,
    },

    /// The state of viewports is known in advance, but the state of scissors is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicScissors {
        /// State of the viewports
        viewports: Vec<Viewport>,
    },

    /// The state of both the viewports and scissors is dynamic and will be set when drawing.
    Dynamic {
        /// Number of viewports and scissors.
        num: u32,
    },
}

impl ViewportsState {
    /// Returns true if the state of the viewports is dynamic.
    pub fn dynamic_viewports(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => true,
            ViewportsState::DynamicScissors { .. } => false,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns true if the state of the scissors is dynamic.
    pub fn dynamic_scissors(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => false,
            ViewportsState::DynamicScissors { .. } => true,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns the number of viewports and scissors.
    pub fn num_viewports(&self) -> u32 {
        match *self {
            ViewportsState::Fixed { ref data } => data.len() as u32,
            ViewportsState::DynamicViewports { ref scissors } => scissors.len() as u32,
            ViewportsState::DynamicScissors { ref viewports } => viewports.len() as u32,
            ViewportsState::Dynamic { num } => num,
        }
    }
}

/// State of a single viewport.
// FIXME: check that:
//        x + width must be less than or equal to viewportBoundsRange[0]
//        y + height must be less than or equal to viewportBoundsRange[1]
#[derive(Debug, Clone)]
pub struct Viewport {
    /// Coordinates in pixels of the top-left hand corner of the viewport.
    pub origin: [f32; 2],

    /// Dimensions in pixels of the viewport.
    pub dimensions: [f32; 2],

    /// Minimum and maximum values of the depth.
    ///
    /// The values `-1.0` to `1.0` of each vertex's Z coordinate will be mapped to this
    /// `depth_range` before being compared to the existing depth value.
    ///
    /// This is equivalents to `glDepthRange` in OpenGL.
    pub depth_range: Range<f32>,
}

#[doc(hidden)]
impl Into<vk::Viewport> for Viewport {
    #[inline]
    fn into(self) -> vk::Viewport {
        vk::Viewport {
            x: self.origin[0],
            y: self.origin[1],
            width: self.dimensions[0],
            height: self.dimensions[1],
            minDepth: self.depth_range.start,
            maxDepth: self.depth_range.end,
        }
    }
}

/// State of a single scissor box.
// FIXME: add a check:
//      Evaluation of (offset.x + extent.width) must not cause a signed integer addition overflow
//      Evaluation of (offset.y + extent.height) must not cause a signed integer addition overflow
#[derive(Debug, Copy, Clone)]
pub struct Scissor {
    /// Coordinates in pixels of the top-left hand corner of the box.
    pub origin: [i32; 2],

    /// Dimensions in pixels of the box.
    pub dimensions: [u32; 2],
}

impl Scissor {
    /// Defines a scissor box that it outside of the image.
    #[inline]
    pub fn irrelevant() -> Scissor {
        Scissor {
            origin: [0, 0],
            dimensions: [0x7fffffff, 0x7fffffff],
        }
    }
}

impl Default for Scissor {
    #[inline]
    fn default() -> Scissor {
        Scissor::irrelevant()
    }
}

#[doc(hidden)]
impl Into<vk::Rect2D> for Scissor {
    #[inline]
    fn into(self) -> vk::Rect2D {
        vk::Rect2D {
            offset: vk::Offset2D {
                x: self.origin[0],
                y: self.origin[1],
            },
            extent: vk::Extent2D {
                width: self.dimensions[0],
                height: self.dimensions[1],
            },
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "alloc")]

extern crate jemallocator;
extern crate nom;

#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

use nom::{
  branch::alt,
  bytes::complete::{escaped, tag, take_while},
  character::complete::{alphanumeric1 as alphanumeric, char, one_of},
  combinator::{cut, map, opt, value},
  error::{context, convert_error, ContextError, ErrorKind, ParseError, VerboseError},
  multi::separated_list0,
  number::complete::double,
  sequence::{delimited, preceded, separated_pair, terminated},
  Err, IResult,
};
use std::collections::HashMap;
use std::str;

#[derive(Debug, PartialEq)]
pub enum JsonValue {
  Str(String),
  Boolean(bool),
  Num(f64),
  Array(Vec<JsonValue>),
  Object(HashMap<String, JsonValue>),
}

/// parser combinators are constructed from the bottom up:
/// first we write parsers for the smallest elements (here a space character),
/// then we'll combine them in larger parsers
fn sp<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  let chars = " \t\r\n";

  // nom combinators like `take_while` return a function. That function is the
  // parser,to which we can pass the input
  take_while(move |c| chars.contains(c))(i)
}

/// A nom parser has the following signature:
/// `Input -> IResult<Input, Output, Error>`, with `IResult` defined as:
/// `type IResult<I, O, E = (I, ErrorKind)> = Result<(I, O), Err<E>>;`
///
/// most of the times you can ignore the error type and use the default (but this
/// examples shows custom error types later on!)
///
/// Here we use `&str` as input type, but nom parsers can be generic over
/// the input type, and work directly with `&[u8]` or any other type that
/// implements the required traits.
///
/// Finally, we can see here that the input and output type are both `&str`
/// with the same lifetime tag. This means that the produced value is a subslice
/// of the input data. and there is no allocation needed. This is the main idea
/// behind nom's performance.
fn parse_str<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  escaped(alphanumeric, '\\', one_of("\"n\\"))(i)
}

/// `tag(string)` generates a parser that recognizes the argument string.
///
/// we can combine it with other functions, like `value` that takes another
/// parser, and if that parser returns without an error, returns a given
/// constant value.
///
/// `alt` is another combinator that tries multiple parsers one by one, until
/// one of them succeeds
///
/// `value` is a combinator that returns its value if the inner parser
fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool, E> {
  // This is a parser that returns `true` if it sees the string "true", and
  // an error otherwise
  let parse_true = value(true, tag("true"));

  // This is a parser that returns `true` if it sees the string "true", and
  // an error otherwise
  let parse_false = value(false, tag("false"));

  // `alt` combines the two parsers. It returns the result of the first
  // successful parser, or an error
  alt((parse_true, parse_false))(input)
}

/// this parser combines the previous `parse_str` parser, that recognizes the
/// interior of a string, with a parse to recognize the double quote character,
/// before the string (using `preceded`) and after the string (using `terminated`).
///
/// `context` and `cut` are related to error management:
/// - `cut` transforms an `Err::Error(e)` in `Err::Failure(e)`, signaling to
/// combinators like  `alt` that they should not try other parsers. We were in the
/// right branch (since we found the `"` character) but encountered an error when
/// parsing the string
/// - `context` lets you add a static string to provide more information in the
/// error chain (to indicate which parser had an error)
fn string<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, &'a str, E> {
  context(
    "string",
    preceded(char('\"'), cut(terminated(parse_str, char('\"')))),
  )(i)
}

/// some combinators, like `separated_list0` or `many0`, will call a parser repeatedly,
/// accumulating results in a `Vec`, until it encounters an error.
/// If you want more control on the parser application, check out the `iterator`
/// combinator (cf `examples/iterator.rs`)
fn array<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, Vec<JsonValue>, E> {
  context(
    "array",
    preceded(
      char('['),
      cut(terminated(
        separated_list0(preceded(sp, char(',')), json_value),
        preceded(sp, char(']')),
      )),
    ),
  )(i)
}

fn key_value<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, (&'a str, JsonValue), E> {
  separated_pair(
    preceded(sp, string),
    cut(preceded(sp, char(':'))),
    json_value,
  )(i)
}

fn hash<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, HashMap<String, JsonValue>, E> {
  context(
    "map",
    preceded(
      char('{'),
      cut(terminated(
        map(
          separated_list0(preceded(sp, char(',')), key_value),
          |tuple_vec| {
            tuple_vec
              .into_iter()
              .map(|(k, v)| (String::from(k), v))
              .collect()
          },
        ),
        preceded(sp, char('}')),
      )),
    ),
  )(i)
}

/// here, we apply the space parser before trying to parse a value
fn json_value<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, JsonValue, E> {
  preceded(
    sp,
    alt((
      map(hash, JsonValue::Object),
      map(array, JsonValue::Array),
      map(string, |s| JsonValue::Str(String::from(s))),
      map(double, JsonValue::Num),
      map(boolean, JsonValue::Boolean),
    )),
  )(i)
}

/// the root element of a JSON parser is either an object or an array
fn root<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, JsonValue, E> {
  delimited(
    sp,
    alt((map(hash, JsonValue::Object), map(array, JsonValue::Array))),
    opt(sp),
  )(i)
}

fn main() {
  let data = "  { \"a\"\t: 42,
  \"b\": [ \"x\", \"y\", 12 ] ,
  \"c\": { \"hello\" : \"world\"
  }
  } ";

  println!(
    "will try to parse valid JSON data:\n\n**********\n{}\n**********\n",
    data
  );

  // this will print:
  // Ok(
  //     (
  //         "",
  //         Object(
  //             {
  //                 "b": Array(
  //                     [
  //                         Str(
  //                             "x",
  //                         ),
  //                         Str(
  //                             "y",
  //                         ),
  //                         Num(
  //                             12.0,
  //                         ),
  //                     ],
  //                 ),
  //                 "c": Object(
  //                     {
  //                         "hello": Str(
  //                             "world",
  //                         ),
  //                     },
  //                 ),
  //                 "a": Num(
  //                     42.0,
  //                 ),
  //             },
  //         ),
  //     ),
  // )
  println!(
    "parsing a valid file:\n{:#?}\n",
    root::<(&str, ErrorKind)>(data)
  );

  let data = "  { \"a\"\t: 42,
  \"b\": [ \"x\", \"y\", 12 ] ,
  \"c\": { 1\"hello\" : \"world\"
  }
  } ";

  println!(
    "will try to parse invalid JSON data:\n\n**********\n{}\n**********\n",
    data
  );

  // here we use `(Input, ErrorKind)` as error type, which is used by default
  // if you don't specify it. It contains the position of the error and some
  // info on which parser encountered it.
  // It is fast and small, but does not provide much context.
  //
  // This will print:
  // basic errors - `root::<(&str, ErrorKind)>(data)`:
  // Err(
  //   Failure(
  //       (
  //           "1\"hello\" : \"world\"\n  }\n  } ",
  //           Char,
  //       ),
  //   ),
  // )
  println!(
    "basic errors - `root::<(&str, ErrorKind)>(data)`:\n{:#?}\n",
    root::<(&str, ErrorKind)>(data)
  );

  // nom also provides `the `VerboseError<Input>` type, which will generate a sort
  // of backtrace of the path through the parser, accumulating info on input positions
  // and affected parsers.
  //
  // This will print:
  //
  // parsed verbose: Err(
  //   Failure(
  //       VerboseError {
  //           errors: [
  //               (
  //                   "1\"hello\" : \"world\"\n  }\n  } ",
  //                   Char(
  //                       '}',
  //                   ),
  //               ),
  //               (
  //                   "{ 1\"hello\" : \"world\"\n  }\n  } ",
  //                   Context(
  //                       "map",
  //                   ),
  //               ),
  //               (
  //                   "{ \"a\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } ",
  //                   Context(
  //                       "map",
  //                   ),
  //               ),
  //           ],
  //       },
  //   ),
  // )
  println!("parsed verbose: {:#?}", root::<VerboseError<&str>>(data));

  match root::<VerboseError<&str>>(data) {
    Err(Err::Error(e)) | Err(Err::Failure(e)) => {
      // here we use the `convert_error` function, to transform a `VerboseError<&str>`
      // into a printable trace.
      //
      // This will print:
      // verbose errors - `root::<VerboseError>(data)`:
      // 0: at line 2:
      //   "c": { 1"hello" : "world"
      //          ^
      // expected '}', found 1
      //
      // 1: at line 2, in map:
      //   "c": { 1"hello" : "world"
      //        ^
      //
      // 2: at line 0, in map:
      //   { "a" : 42,
      //   ^
      println!(
        "verbose errors - `root::<VerboseError>(data)`:\n{}",
        convert_error(data, e)
      );
    }
    _ => {}
  }
}
<commit_msg>Update json.rs<commit_after>#![cfg(feature = "alloc")]

extern crate jemallocator;
extern crate nom;

#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

use nom::{
  branch::alt,
  bytes::complete::{escaped, tag, take_while},
  character::complete::{alphanumeric1 as alphanumeric, char, one_of},
  combinator::{cut, map, opt, value},
  error::{context, convert_error, ContextError, ErrorKind, ParseError, VerboseError},
  multi::separated_list0,
  number::complete::double,
  sequence::{delimited, preceded, separated_pair, terminated},
  Err, IResult,
};
use std::collections::HashMap;
use std::str;

#[derive(Debug, PartialEq)]
pub enum JsonValue {
  Str(String),
  Boolean(bool),
  Num(f64),
  Array(Vec<JsonValue>),
  Object(HashMap<String, JsonValue>),
}

/// parser combinators are constructed from the bottom up:
/// first we write parsers for the smallest elements (here a space character),
/// then we'll combine them in larger parsers
fn sp<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  let chars = " \t\r\n";

  // nom combinators like `take_while` return a function. That function is the
  // parser,to which we can pass the input
  take_while(move |c| chars.contains(c))(i)
}

/// A nom parser has the following signature:
/// `Input -> IResult<Input, Output, Error>`, with `IResult` defined as:
/// `type IResult<I, O, E = (I, ErrorKind)> = Result<(I, O), Err<E>>;`
///
/// most of the times you can ignore the error type and use the default (but this
/// examples shows custom error types later on!)
///
/// Here we use `&str` as input type, but nom parsers can be generic over
/// the input type, and work directly with `&[u8]` or any other type that
/// implements the required traits.
///
/// Finally, we can see here that the input and output type are both `&str`
/// with the same lifetime tag. This means that the produced value is a subslice
/// of the input data. and there is no allocation needed. This is the main idea
/// behind nom's performance.
fn parse_str<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  escaped(alphanumeric, '\\', one_of("\"n\\"))(i)
}

/// `tag(string)` generates a parser that recognizes the argument string.
///
/// we can combine it with other functions, like `value` that takes another
/// parser, and if that parser returns without an error, returns a given
/// constant value.
///
/// `alt` is another combinator that tries multiple parsers one by one, until
/// one of them succeeds
fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool, E> {
  // This is a parser that returns `true` if it sees the string "true", and
  // an error otherwise
  let parse_true = value(true, tag("true"));

  // This is a parser that returns `false` if it sees the string "false", and
  // an error otherwise
  let parse_false = value(false, tag("false"));

  // `alt` combines the two parsers. It returns the result of the first
  // successful parser, or an error
  alt((parse_true, parse_false))(input)
}

/// this parser combines the previous `parse_str` parser, that recognizes the
/// interior of a string, with a parse to recognize the double quote character,
/// before the string (using `preceded`) and after the string (using `terminated`).
///
/// `context` and `cut` are related to error management:
/// - `cut` transforms an `Err::Error(e)` in `Err::Failure(e)`, signaling to
/// combinators like  `alt` that they should not try other parsers. We were in the
/// right branch (since we found the `"` character) but encountered an error when
/// parsing the string
/// - `context` lets you add a static string to provide more information in the
/// error chain (to indicate which parser had an error)
fn string<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, &'a str, E> {
  context(
    "string",
    preceded(char('\"'), cut(terminated(parse_str, char('\"')))),
  )(i)
}

/// some combinators, like `separated_list0` or `many0`, will call a parser repeatedly,
/// accumulating results in a `Vec`, until it encounters an error.
/// If you want more control on the parser application, check out the `iterator`
/// combinator (cf `examples/iterator.rs`)
fn array<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, Vec<JsonValue>, E> {
  context(
    "array",
    preceded(
      char('['),
      cut(terminated(
        separated_list0(preceded(sp, char(',')), json_value),
        preceded(sp, char(']')),
      )),
    ),
  )(i)
}

fn key_value<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, (&'a str, JsonValue), E> {
  separated_pair(
    preceded(sp, string),
    cut(preceded(sp, char(':'))),
    json_value,
  )(i)
}

fn hash<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, HashMap<String, JsonValue>, E> {
  context(
    "map",
    preceded(
      char('{'),
      cut(terminated(
        map(
          separated_list0(preceded(sp, char(',')), key_value),
          |tuple_vec| {
            tuple_vec
              .into_iter()
              .map(|(k, v)| (String::from(k), v))
              .collect()
          },
        ),
        preceded(sp, char('}')),
      )),
    ),
  )(i)
}

/// here, we apply the space parser before trying to parse a value
fn json_value<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, JsonValue, E> {
  preceded(
    sp,
    alt((
      map(hash, JsonValue::Object),
      map(array, JsonValue::Array),
      map(string, |s| JsonValue::Str(String::from(s))),
      map(double, JsonValue::Num),
      map(boolean, JsonValue::Boolean),
    )),
  )(i)
}

/// the root element of a JSON parser is either an object or an array
fn root<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
  i: &'a str,
) -> IResult<&'a str, JsonValue, E> {
  delimited(
    sp,
    alt((map(hash, JsonValue::Object), map(array, JsonValue::Array))),
    opt(sp),
  )(i)
}

fn main() {
  let data = "  { \"a\"\t: 42,
  \"b\": [ \"x\", \"y\", 12 ] ,
  \"c\": { \"hello\" : \"world\"
  }
  } ";

  println!(
    "will try to parse valid JSON data:\n\n**********\n{}\n**********\n",
    data
  );

  // this will print:
  // Ok(
  //     (
  //         "",
  //         Object(
  //             {
  //                 "b": Array(
  //                     [
  //                         Str(
  //                             "x",
  //                         ),
  //                         Str(
  //                             "y",
  //                         ),
  //                         Num(
  //                             12.0,
  //                         ),
  //                     ],
  //                 ),
  //                 "c": Object(
  //                     {
  //                         "hello": Str(
  //                             "world",
  //                         ),
  //                     },
  //                 ),
  //                 "a": Num(
  //                     42.0,
  //                 ),
  //             },
  //         ),
  //     ),
  // )
  println!(
    "parsing a valid file:\n{:#?}\n",
    root::<(&str, ErrorKind)>(data)
  );

  let data = "  { \"a\"\t: 42,
  \"b\": [ \"x\", \"y\", 12 ] ,
  \"c\": { 1\"hello\" : \"world\"
  }
  } ";

  println!(
    "will try to parse invalid JSON data:\n\n**********\n{}\n**********\n",
    data
  );

  // here we use `(Input, ErrorKind)` as error type, which is used by default
  // if you don't specify it. It contains the position of the error and some
  // info on which parser encountered it.
  // It is fast and small, but does not provide much context.
  //
  // This will print:
  // basic errors - `root::<(&str, ErrorKind)>(data)`:
  // Err(
  //   Failure(
  //       (
  //           "1\"hello\" : \"world\"\n  }\n  } ",
  //           Char,
  //       ),
  //   ),
  // )
  println!(
    "basic errors - `root::<(&str, ErrorKind)>(data)`:\n{:#?}\n",
    root::<(&str, ErrorKind)>(data)
  );

  // nom also provides `the `VerboseError<Input>` type, which will generate a sort
  // of backtrace of the path through the parser, accumulating info on input positions
  // and affected parsers.
  //
  // This will print:
  //
  // parsed verbose: Err(
  //   Failure(
  //       VerboseError {
  //           errors: [
  //               (
  //                   "1\"hello\" : \"world\"\n  }\n  } ",
  //                   Char(
  //                       '}',
  //                   ),
  //               ),
  //               (
  //                   "{ 1\"hello\" : \"world\"\n  }\n  } ",
  //                   Context(
  //                       "map",
  //                   ),
  //               ),
  //               (
  //                   "{ \"a\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } ",
  //                   Context(
  //                       "map",
  //                   ),
  //               ),
  //           ],
  //       },
  //   ),
  // )
  println!("parsed verbose: {:#?}", root::<VerboseError<&str>>(data));

  match root::<VerboseError<&str>>(data) {
    Err(Err::Error(e)) | Err(Err::Failure(e)) => {
      // here we use the `convert_error` function, to transform a `VerboseError<&str>`
      // into a printable trace.
      //
      // This will print:
      // verbose errors - `root::<VerboseError>(data)`:
      // 0: at line 2:
      //   "c": { 1"hello" : "world"
      //          ^
      // expected '}', found 1
      //
      // 1: at line 2, in map:
      //   "c": { 1"hello" : "world"
      //        ^
      //
      // 2: at line 0, in map:
      //   { "a" : 42,
      //   ^
      println!(
        "verbose errors - `root::<VerboseError>(data)`:\n{}",
        convert_error(data, e)
      );
    }
    _ => {}
  }
}
<|endoftext|>


<commit_before>#![feature(conservative_impl_trait)]
#[macro_use]
extern crate generator;
use generator::*;

fn main() {
    fn square<'a, T: Iterator<Item = u32> + 'a>(input: T) -> impl Iterator<Item = u32> + 'a {
        Gn::new_scoped(|mut s| {
            for i in input {
                s.yield_with(i * i);
            }
            done!();
        })
    }

    fn sum<'a, T: Iterator<Item = u32> + 'a>(input: T) -> impl Iterator<Item = u32> + 'a {
        Gn::new_scoped(|mut s| {
            let mut acc = 0;
            for i in input {
                acc += i;
                s.yield_with(acc);
            }
            done!();
        })
    }

    for i in sum(square(0..10)) {
        println!("i = {:?}", i);
    }
}
<commit_msg>update pipe example<commit_after>// #![feature(conservative_impl_trait)]
#[macro_use]
extern crate generator;
use generator::*;

fn main() {
    // fn square<'a, T: Iterator<Item = u32> + 'a>(input: T) -> impl Iterator<Item = u32> + 'a {
    fn square<'a, T: Iterator<Item = u32> + 'a>(input: T) -> Generator<'a, (), u32> {
        Gn::new_scoped(|mut s| {
            for i in input {
                s.yield_with(i * i);
            }
            done!();
        })
    }

    // fn sum<'a, T: Iterator<Item = u32> + 'a>(input: T) -> impl Iterator<Item = u32> + 'a {
    fn sum<'a, T: Iterator<Item = u32> + 'a>(input: T) -> Generator<'a, (), u32> {
        Gn::new_scoped(|mut s| {
            let mut acc = 0;
            for i in input {
                acc += i;
                s.yield_with(acc);
            }
            done!();
        })
    }

    for (i, sum) in sum(square(0..20)).enumerate() {
        println!("square_sum_{:<2} = {:^4}", i, sum);
    }
}
<|endoftext|>


<commit_before>//! Parser for an Accept-Language HTTP header.

use language_tags::LanguageTag;

struct Weight(Option<f32>);

impl Weight {
    fn numeric(&self) -> f32 {
        self.0.unwrap_or(1.0)
    }
}

struct Item {
    tag: LanguageTag,
    weight: Weight,
}

/// Stores a parsed version of an HTTP Accept-Language header.
///
/// https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5
pub struct AcceptLanguage(Box<[Item]>);

/// Errors when parsing an `AcceptLanguage`.
#[derive(Debug, PartialEq)]
pub enum Error {
    NoElements,
}

impl AcceptLanguage {
    pub fn parse(s: &str) -> Result<AcceptLanguage, Error> {
        let mut items = Vec::new();

        for val in s.split(',') {

        }

        if items.len() == 0 {
            Err(Error::NoElements)
        } else {
            Ok(AcceptLanguage(items.into_boxed_slice()))
        }
    }
}

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

    #[test]
    fn empty_lists_yield_error() {
        assert!(matches!(
            AcceptLanguage::parse(""),
            Err(Error::NoElements)
        ));

        assert!(matches!(
            AcceptLanguage::parse(","),
            Err(Error::NoElements)
        ));

        assert!(matches!(
            AcceptLanguage::parse(", , ,,,"),
            Err(Error::NoElements)
        ));
    }
}
<commit_msg>Finish parser for AcceptLanguage<commit_after>//! Parser for an Accept-Language HTTP header.

use language_tags::{LanguageTag, ParseError};

use std::str::FromStr;

#[derive(Debug, PartialEq)]
struct Weight(Option<f32>);

impl Weight {
    fn numeric(&self) -> f32 {
        self.0.unwrap_or(1.0)
    }
}

#[derive(Debug, PartialEq)]
struct Item {
    tag: LanguageTag,
    weight: Weight,
}

/// Stores a parsed version of an HTTP Accept-Language header.
///
/// https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5
#[derive(Debug, PartialEq)]
pub struct AcceptLanguage(Box<[Item]>);

/// Errors when parsing an `AcceptLanguage`.
#[derive(Debug, PartialEq)]
pub enum Error {
    NoElements,
    InvalidCharacters,
    InvalidLanguageTag(ParseError),
    InvalidWeight,
}

/// Optional whitespace, Space or Tab, per https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.3
const OWS: [char; 2] = ['\x20', '\x09'];

impl AcceptLanguage {
    pub fn parse(s: &str) -> Result<AcceptLanguage, Error> {
        if !s.is_ascii() {
            return Err(Error::InvalidCharacters);
        }

        let mut items = Vec::new();

        for val in s.split(',') {
            let trimmed = val.trim_matches(&OWS[..]);
            if trimmed.len() == 0 {
                continue;
            }

            items.push(Item::parse(trimmed)?);
        }

        if items.len() == 0 {
            Err(Error::NoElements)
        } else {
            Ok(AcceptLanguage(items.into_boxed_slice()))
        }
    }
}

impl Item {
    fn parse(s: &str) -> Result<Item, Error> {
        let semicolon_pos = s.find(';');

        let (before_semicolon, after_semicolon) = if let Some(semi) = semicolon_pos {
            (&s[..semi], Some(&s[semi + 1..]))
        } else {
            (s, None)
        };

        let tag = LanguageTag::parse(before_semicolon).map_err(Error::InvalidLanguageTag)?;

        let weight;

        if let Some(quality) = after_semicolon {
            let quality = quality.trim_start_matches(&OWS[..]);

            let number = if let Some(qvalue) = quality.strip_prefix("q=") {
                if qvalue.starts_with(&['0', '1'][..]) {
                    let first_digit = qvalue.chars().next().unwrap();

                    if let Some(decimals) = qvalue[1..].strip_prefix(".") {
                        if first_digit == '0'
                            && decimals.len() <= 3
                            && decimals.chars().all(|c| c.is_digit(10))
                        {
                            qvalue
                        } else if first_digit == '1'
                            && decimals.len() <= 3
                            && decimals.chars().all(|c| c == '0')
                        {
                            qvalue
                        } else {
                            return Err(Error::InvalidWeight);
                        }
                    } else {
                        qvalue
                    }
                } else {
                    return Err(Error::InvalidWeight);
                }
            } else {
                return Err(Error::InvalidWeight);
            };

            weight = Weight(Some(
                f32::from_str(number).map_err(|_| Error::InvalidWeight)?,
            ));
        } else {
            weight = Weight(None);
        }

        Ok(Item { tag, weight })
    }
}

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

    #[test]
    fn parses_accept_language() {
        // plain tag
        assert_eq!(
            AcceptLanguage::parse("es-MX").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(None)
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // with quality
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=0.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(0.0))
                }]
                .into_boxed_slice()
            )
        );

        // zero decimals are allowed
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // one decimal
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.0").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // two decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.00").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // three decimals
        assert_eq!(
            AcceptLanguage::parse("es-MX;q=1.000").unwrap(),
            AcceptLanguage(
                vec![Item {
                    tag: LanguageTag::parse("es-MX").unwrap(),
                    weight: Weight(Some(1.0))
                }]
                .into_boxed_slice()
            )
        );

        // multiple elements
        assert_eq!(
            AcceptLanguage::parse("es-MX, en; q=0.5").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(None)
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.5))
                    },
                ]
                .into_boxed_slice()
            )
        );

        // superfluous whitespace
        assert_eq!(
            AcceptLanguage::parse(",es-MX;q=1.000  , en; q=0.125  ,  ,").unwrap(),
            AcceptLanguage(
                vec![
                    Item {
                        tag: LanguageTag::parse("es-MX").unwrap(),
                        weight: Weight(Some(1.0))
                    },
                    Item {
                        tag: LanguageTag::parse("en").unwrap(),
                        weight: Weight(Some(0.125))
                    },
                ]
                .into_boxed_slice()
            )
        );
    }

    #[test]
    fn empty_lists() {
        assert!(matches!(AcceptLanguage::parse(""), Err(Error::NoElements)));

        assert!(matches!(AcceptLanguage::parse(","), Err(Error::NoElements)));

        assert!(matches!(
            AcceptLanguage::parse(", , ,,,"),
            Err(Error::NoElements)
        ));
    }

    #[test]
    fn ascii_only() {
        assert!(matches!(
            AcceptLanguage::parse("ës"),
            Err(Error::InvalidCharacters)
        ));
    }

    #[test]
    fn invalid_tag() {
        assert!(matches!(
            AcceptLanguage::parse("no_underscores"),
            Err(Error::InvalidLanguageTag(_))
        ));
    }

    #[test]
    fn invalid_weight() {
        assert!(matches!(
            AcceptLanguage::parse("es;"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q="),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=2"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.1"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.12"),
            Err(Error::InvalidWeight)
        ));
        assert!(matches!(
            AcceptLanguage::parse("es;q=1.123"),
            Err(Error::InvalidWeight)
        ));

        // Up to three decimals allowed per RFC 7231
        assert!(matches!(
            AcceptLanguage::parse("es;q=0.1234"),
            Err(Error::InvalidWeight)
        ));
    }
}
<|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};

use cairo::{self, ImageSurface, MatrixTrait, PatternTrait};

use allowed_url::{Fragment, Href};
use aspect_ratio::AspectRatio;
use attributes::Attribute;
use drawing_ctx::DrawingCtx;
use error::{NodeError, RenderingError};
use float_eq_cairo::ApproxEqCairo;
use node::{CascadedValues, NodeResult, NodeTrait, RsvgNode};
use parsers::{ParseError, ParseValue};
use property_bag::PropertyBag;
use rect::IRect;
use surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use super::bounds::BoundsBuilder;
use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{Filter, FilterError, Primitive};

/// The `feImage` filter primitive.
pub struct Image {
    base: Primitive,
    aspect: Cell<AspectRatio>,
    href: RefCell<Option<Href>>,
}

impl Image {
    /// Constructs a new `Image` with empty properties.
    #[inline]
    pub fn new() -> Image {
        Image {
            base: Primitive::new::<Self>(),
            aspect: Cell::new(AspectRatio::default()),
            href: RefCell::new(None),
        }
    }

    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
        bounds: IRect,
        fragment: &Fragment,
    ) -> Result<ImageSurface, FilterError> {
        let acquired_drawable = draw_ctx
            .get_acquired_node(fragment)
            .ok_or(FilterError::InvalidInput)?;
        let drawable = acquired_drawable.get();

        let surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        draw_ctx.get_cairo_context().set_matrix(ctx.paffine());

        let node_being_filtered_values = ctx.get_computed_values_from_node_being_filtered();

        let cascaded = CascadedValues::new_from_values(&drawable, node_being_filtered_values);

        draw_ctx
            .draw_node_on_surface(
                &drawable,
                &cascaded,
                &surface,
                f64::from(ctx.source_graphic().width()),
                f64::from(ctx.source_graphic().height()),
            )
            .map_err(|e| {
                if let RenderingError::Cairo(status) = e {
                    FilterError::CairoError(status)
                } else {
                    // FIXME: this is just a dummy value; we should probably have a way to indicate
                    // an error in the underlying drawing process.
                    FilterError::CairoError(cairo::Status::InvalidStatus)
                }
            })?;

        // Clip the output to bounds.
        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            f64::from(bounds.x0),
            f64::from(bounds.y0),
            f64::from(bounds.x1 - bounds.x0),
            f64::from(bounds.y1 - bounds.y0),
        );
        cr.clip();
        cr.set_source_surface(&surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
        bounds_builder: BoundsBuilder<'_>,
        href: &Href,
    ) -> Result<ImageSurface, FilterError> {
        let surface = if let Href::PlainUrl(ref url) = *href {
            // FIXME: translate the error better here
            draw_ctx
                .lookup_image(&url)
                .map_err(|_| FilterError::InvalidInput)?
        } else {
            unreachable!();
        };

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        // TODO: this goes through a f64->i32->f64 conversion.
        let render_bounds = bounds_builder.into_irect_without_clipping(draw_ctx);
        let aspect = self.aspect.get();
        let (x, y, w, h) = aspect.compute(
            f64::from(surface.width()),
            f64::from(surface.height()),
            f64::from(render_bounds.x0),
            f64::from(render_bounds.y0),
            f64::from(render_bounds.x1 - render_bounds.x0),
            f64::from(render_bounds.y1 - render_bounds.y0),
        );

        if w.approx_eq_cairo(&0.0) || h.approx_eq_cairo(&0.0) {
            return Ok(output_surface);
        }

        let ptn = surface.to_cairo_pattern();
        let mut matrix = cairo::Matrix::new(
            w / f64::from(surface.width()),
            0f64,
            0f64,
            h / f64::from(surface.height()),
            x,
            y,
        );
        matrix.invert();
        ptn.set_matrix(matrix);

        let bounds = bounds_builder.into_irect(draw_ctx);
        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            f64::from(bounds.x0),
            f64::from(bounds.y0),
            f64::from(bounds.x1 - bounds.x0),
            f64::from(bounds.y1 - bounds.y0),
        );
        cr.clip();
        cr.set_source(&ptn);
        cr.paint();

        Ok(output_surface)
    }
}

impl NodeTrait for Image {
    fn set_atts(&self, node: &RsvgNode, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(node, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => self.aspect.set(attr.parse(value)?),

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    let href = Href::parse(value).map_err(|_| {
                        NodeError::parse_error(attr, ParseError::new("could not parse href"))
                    })?;

                    *self.href.borrow_mut() = Some(href);
                }

                _ => (),
            }
        }

        Ok(())
    }
}

impl Filter for Image {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let bounds_builder = self.base.get_bounds(ctx);
        let bounds = bounds_builder.into_irect(draw_ctx);

        let href_borrow = self.href.borrow();
        let href_opt = href_borrow.as_ref();

        if let Some(href) = href_opt {
            let output_surface = match *href {
                Href::PlainUrl(_) => {
                    self.render_external_image(ctx, draw_ctx, bounds_builder, href)?
                }
                Href::WithFragment(ref frag) => self.render_node(ctx, draw_ctx, bounds, frag)?,
            };

            Ok(FilterResult {
                name: self.base.result.borrow().clone(),
                output: FilterOutput {
                    surface: SharedImageSurface::new(output_surface, SurfaceType::SRgb)?,
                    bounds,
                },
            })
        } else {
            Err(FilterError::InvalidInput)
        }
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}
<commit_msg>feImage: Pass the bounding boxes to render_external_image()<commit_after>use std::cell::{Cell, RefCell};

use cairo::{self, ImageSurface, MatrixTrait, PatternTrait};

use allowed_url::{Fragment, Href};
use aspect_ratio::AspectRatio;
use attributes::Attribute;
use drawing_ctx::DrawingCtx;
use error::{NodeError, RenderingError};
use float_eq_cairo::ApproxEqCairo;
use node::{CascadedValues, NodeResult, NodeTrait, RsvgNode};
use parsers::{ParseError, ParseValue};
use property_bag::PropertyBag;
use rect::IRect;
use surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{Filter, FilterError, Primitive};

/// The `feImage` filter primitive.
pub struct Image {
    base: Primitive,
    aspect: Cell<AspectRatio>,
    href: RefCell<Option<Href>>,
}

impl Image {
    /// Constructs a new `Image` with empty properties.
    #[inline]
    pub fn new() -> Image {
        Image {
            base: Primitive::new::<Self>(),
            aspect: Cell::new(AspectRatio::default()),
            href: RefCell::new(None),
        }
    }

    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
        bounds: IRect,
        fragment: &Fragment,
    ) -> Result<ImageSurface, FilterError> {
        let acquired_drawable = draw_ctx
            .get_acquired_node(fragment)
            .ok_or(FilterError::InvalidInput)?;
        let drawable = acquired_drawable.get();

        let surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        draw_ctx.get_cairo_context().set_matrix(ctx.paffine());

        let node_being_filtered_values = ctx.get_computed_values_from_node_being_filtered();

        let cascaded = CascadedValues::new_from_values(&drawable, node_being_filtered_values);

        draw_ctx
            .draw_node_on_surface(
                &drawable,
                &cascaded,
                &surface,
                f64::from(ctx.source_graphic().width()),
                f64::from(ctx.source_graphic().height()),
            )
            .map_err(|e| {
                if let RenderingError::Cairo(status) = e {
                    FilterError::CairoError(status)
                } else {
                    // FIXME: this is just a dummy value; we should probably have a way to indicate
                    // an error in the underlying drawing process.
                    FilterError::CairoError(cairo::Status::InvalidStatus)
                }
            })?;

        // Clip the output to bounds.
        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            f64::from(bounds.x0),
            f64::from(bounds.y0),
            f64::from(bounds.x1 - bounds.x0),
            f64::from(bounds.y1 - bounds.y0),
        );
        cr.clip();
        cr.set_source_surface(&surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        draw_ctx: &DrawingCtx,
        bounds: &IRect,
        unclipped_bounds: &IRect,
        href: &Href,
    ) -> Result<ImageSurface, FilterError> {
        let surface = if let Href::PlainUrl(ref url) = *href {
            // FIXME: translate the error better here
            draw_ctx
                .lookup_image(&url)
                .map_err(|_| FilterError::InvalidInput)?
        } else {
            unreachable!();
        };

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        // TODO: this goes through a f64->i32->f64 conversion.
        let aspect = self.aspect.get();
        let (x, y, w, h) = aspect.compute(
            f64::from(surface.width()),
            f64::from(surface.height()),
            f64::from(unclipped_bounds.x0),
            f64::from(unclipped_bounds.y0),
            f64::from(unclipped_bounds.x1 - unclipped_bounds.x0),
            f64::from(unclipped_bounds.y1 - unclipped_bounds.y0),
        );

        if w.approx_eq_cairo(&0.0) || h.approx_eq_cairo(&0.0) {
            return Ok(output_surface);
        }

        let ptn = surface.to_cairo_pattern();
        let mut matrix = cairo::Matrix::new(
            w / f64::from(surface.width()),
            0f64,
            0f64,
            h / f64::from(surface.height()),
            x,
            y,
        );
        matrix.invert();
        ptn.set_matrix(matrix);

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            f64::from(bounds.x0),
            f64::from(bounds.y0),
            f64::from(bounds.x1 - bounds.x0),
            f64::from(bounds.y1 - bounds.y0),
        );
        cr.clip();
        cr.set_source(&ptn);
        cr.paint();

        Ok(output_surface)
    }
}

impl NodeTrait for Image {
    fn set_atts(&self, node: &RsvgNode, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(node, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => self.aspect.set(attr.parse(value)?),

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    let href = Href::parse(value).map_err(|_| {
                        NodeError::parse_error(attr, ParseError::new("could not parse href"))
                    })?;

                    *self.href.borrow_mut() = Some(href);
                }

                _ => (),
            }
        }

        Ok(())
    }
}

impl Filter for Image {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let bounds_builder = self.base.get_bounds(ctx);
        let bounds = bounds_builder.into_irect(draw_ctx);

        let href_borrow = self.href.borrow();
        let href_opt = href_borrow.as_ref();

        if let Some(href) = href_opt {
            let output_surface = match *href {
                Href::PlainUrl(_) => {
                    let unclipped_bounds = bounds_builder.into_irect_without_clipping(draw_ctx);
                    self.render_external_image(ctx, draw_ctx, &bounds, &unclipped_bounds, href)?
                }
                Href::WithFragment(ref frag) => self.render_node(ctx, draw_ctx, bounds, frag)?,
            };

            Ok(FilterResult {
                name: self.base.result.borrow().clone(),
                output: FilterOutput {
                    surface: SharedImageSurface::new(output_surface, SurfaceType::SRgb)?,
                    bounds,
                },
            })
        } else {
            Err(FilterError::InvalidInput)
        }
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}
<|endoftext|>


<commit_before>
#[ cfg( feature = "use_std" ) ]
mod former_impl;

///
/// Derive macro to generate former for a structure. Former is variation of Builder Pattern.
///

#[ cfg( feature = "use_std" ) ]
#[ proc_macro_derive( Former, attributes( perform, default ) ) ]
pub fn former( input : proc_macro::TokenStream ) -> proc_macro::TokenStream
{
  let result = former_impl::former( input );
  match result
  {
    Ok( stream ) => stream.into(),
    Err( err ) => err.to_compile_error().into(),
  }
}
<commit_msg>fixing meta modules<commit_after>
// #[ cfg( feature = "use_std" ) ]
mod former_impl;

///
/// Derive macro to generate former for a structure. Former is variation of Builder Pattern.
///

// #[ cfg( feature = "use_std" ) ]
#[ proc_macro_derive( Former, attributes( perform, default ) ) ]
pub fn former( input : proc_macro::TokenStream ) -> proc_macro::TokenStream
{
  let result = former_impl::former( input );
  match result
  {
    Ok( stream ) => stream.into(),
    Err( err ) => err.to_compile_error().into(),
  }
}
<|endoftext|>