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

use api::{LayoutPrimitiveInfo};
use internal_types::FastHashMap;
use malloc_size_of::MallocSizeOf;
use profiler::ResourceProfileCounter;
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::{mem, ops, u64};
use std::sync::atomic::{AtomicUsize, Ordering};
use util::VecHelper;

/*

 The interning module provides a generic data structure
 interning container. It is similar in concept to a
 traditional string interning container, but it is
 specialized to the WR thread model.

 There is an Interner structure, that lives in the
 scene builder thread, and a DataStore structure
 that lives in the frame builder thread.

 Hashing, interning and handle creation is done by
 the interner structure during scene building.

 Delta changes for the interner are pushed during
 a transaction to the frame builder. The frame builder
 is then able to access the content of the interned
 handles quickly, via array indexing.

 Epoch tracking ensures that the garbage collection
 step which the interner uses to remove items is
 only invoked on items that the frame builder thread
 is no longer referencing.

 Items in the data store are stored in a traditional
 free-list structure, for content access and memory
 usage efficiency.

 */

/// The epoch is incremented each time a scene is
/// built. The most recently used scene epoch is
/// stored inside each item and handle. This is
/// then used for cache invalidation (item) and
/// correctness validation (handle).
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
struct Epoch(u64);

impl Epoch {
    pub const INVALID: Self = Epoch(u64::MAX);
}

/// A list of updates to be applied to the data store,
/// provided by the interning structure.
pub struct UpdateList<S> {
    /// The current epoch of the scene builder.
    epoch: Epoch,
    /// The additions and removals to apply.
    updates: Vec<Update>,
    /// Actual new data to insert.
    data: Vec<S>,
}

lazy_static! {
    static ref NEXT_UID: AtomicUsize = AtomicUsize::new(0);
}

/// A globally, unique identifier
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct ItemUid {
    uid: usize,
}

impl ItemUid {
    pub fn next_uid() -> ItemUid {
        let uid = NEXT_UID.fetch_add(1, Ordering::Relaxed);
        ItemUid { uid }
    }
}

#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, MallocSizeOf)]
pub struct Handle<M: Copy> {
    index: u32,
    epoch: Epoch,
    uid: ItemUid,
    _marker: PhantomData<M>,
}

impl <M> Handle<M> where M: Copy {
    pub fn uid(&self) -> ItemUid {
        self.uid
    }
}

#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub enum UpdateKind {
    Insert,
    Remove,
    UpdateEpoch,
}

#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct Update {
    index: usize,
    kind: UpdateKind,
}

/// The data item is stored with an epoch, for validating
/// correct access patterns.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
struct Item<T: MallocSizeOf> {
    epoch: Epoch,
    data: T,
}

pub trait InternDebug {
    fn on_interned(&self, _uid: ItemUid) {}
}

/// The data store lives in the frame builder thread. It
/// contains a free-list of items for fast access.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct DataStore<S, T: MallocSizeOf, M> {
    items: Vec<Item<T>>,
    _source: PhantomData<S>,
    _marker: PhantomData<M>,
}

impl<S, T, M> ::std::default::Default for DataStore<S, T, M>
where
    S: Debug + MallocSizeOf,
    T: From<S> + MallocSizeOf,
    M: Debug
{
    fn default() -> Self {
        DataStore {
            items: Vec::new(),
            _source: PhantomData,
            _marker: PhantomData,
        }
    }
}

impl<S, T, M> DataStore<S, T, M>
where
    S: Debug + MallocSizeOf,
    T: From<S> + MallocSizeOf,
    M: Debug
{
    /// Apply any updates from the scene builder thread to
    /// this data store.
    pub fn apply_updates(
        &mut self,
        update_list: UpdateList<S>,
        profile_counter: &mut ResourceProfileCounter,
    ) {
        let mut data_iter = update_list.data.into_iter();
        for update in update_list.updates {
            match update.kind {
                UpdateKind::Insert => {
                    self.items.entry(update.index).set(Item {
                        data: T::from(data_iter.next().unwrap()),
                        epoch: update_list.epoch,
                    });
                }
                UpdateKind::Remove => {
                    self.items[update.index].epoch = Epoch::INVALID;
                }
                UpdateKind::UpdateEpoch => {
                    self.items[update.index].epoch = update_list.epoch;
                }
            }
        }

        let per_item_size = mem::size_of::<S>() + mem::size_of::<T>();
        profile_counter.set(self.items.len(), per_item_size * self.items.len());

        debug_assert!(data_iter.next().is_none());
    }
}

/// Retrieve an item from the store via handle
impl<S, T, M> ops::Index<Handle<M>> for DataStore<S, T, M>
where
    S: MallocSizeOf,
    T: MallocSizeOf,
    M: Copy
{
    type Output = T;
    fn index(&self, handle: Handle<M>) -> &T {
        let item = &self.items[handle.index as usize];
        assert_eq!(item.epoch, handle.epoch);
        &item.data
    }
}

/// Retrieve a mutable item from the store via handle
/// Retrieve an item from the store via handle
impl<S, T, M> ops::IndexMut<Handle<M>> for DataStore<S, T, M>
where
    S: MallocSizeOf,
    T: MallocSizeOf,
    M: Copy
{
    fn index_mut(&mut self, handle: Handle<M>) -> &mut T {
        let item = &mut self.items[handle.index as usize];
        assert_eq!(item.epoch, handle.epoch);
        &mut item.data
    }
}

/// The main interning data structure. This lives in the
/// scene builder thread, and handles hashing and interning
/// unique data structures. It also manages a free-list for
/// the items in the data store, which is synchronized via
/// an update list of additions / removals.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct Interner<S, D, M>
where
    S: Eq + Hash + Clone + Debug + MallocSizeOf,
    D: MallocSizeOf,
    M: Copy + MallocSizeOf,
{
    /// Uniquely map an interning key to a handle
    map: FastHashMap<S, Handle<M>>,
    /// List of free slots in the data store for re-use.
    free_list: Vec<usize>,
    /// Pending list of updates that need to be applied.
    updates: Vec<Update>,
    /// Pending new data to insert.
    update_data: Vec<S>,
    /// The current epoch for the interner.
    current_epoch: Epoch,
    /// The information associated with each interned
    /// item that can be accessed by the interner.
    local_data: Vec<Item<D>>,
}

impl<S, D, M> ::std::default::Default for Interner<S, D, M>
where
    S: Eq + Hash + Clone + Debug + MallocSizeOf,
    D: MallocSizeOf,
    M: Copy + Debug + MallocSizeOf,
{
    fn default() -> Self {
        Interner {
            map: FastHashMap::default(),
            free_list: Vec::new(),
            updates: Vec::new(),
            update_data: Vec::new(),
            current_epoch: Epoch(1),
            local_data: Vec::new(),
        }
    }
}

impl<S, D, M> Interner<S, D, M>
where
    S: Eq + Hash + Clone + Debug + InternDebug + MallocSizeOf,
    D: MallocSizeOf,
    M: Copy + Debug + MallocSizeOf
{
    /// Intern a data structure, and return a handle to
    /// that data. The handle can then be stored in the
    /// frame builder, and safely accessed via the data
    /// store that lives in the frame builder thread.
    /// The provided closure is invoked to build the
    /// local data about an interned structure if the
    /// key isn't already interned.
    pub fn intern<F>(
        &mut self,
        data: &S,
        f: F,
    ) -> Handle<M> where F: FnOnce() -> D {
        // Use get_mut rather than entry here to avoid
        // cloning the (sometimes large) key in the common
        // case, where the data already exists in the interner.
        if let Some(handle) = self.map.get_mut(data) {
            // Update the epoch in the data store. This
            // is not strictly needed for correctness, but
            // is used to ensure items are only accessed
            // via valid handles.
            if handle.epoch != self.current_epoch {
                self.updates.push(Update {
                    index: handle.index as usize,
                    kind: UpdateKind::UpdateEpoch,
                });
                self.local_data[handle.index as usize].epoch = self.current_epoch;
            }
            handle.epoch = self.current_epoch;
            return *handle;
        }

        // We need to intern a new data item. First, find out
        // if there is a spare slot in the free-list that we
        // can use. Otherwise, append to the end of the list.
        let index = match self.free_list.pop() {
            Some(index) => index,
            None => self.local_data.len(),
        };

        // Add a pending update to insert the new data.
        self.updates.push(Update {
            index,
            kind: UpdateKind::Insert,
        });
        self.update_data.alloc().init(data.clone());

        // Generate a handle for access via the data store.
        let handle = Handle {
            index: index as u32,
            epoch: self.current_epoch,
            uid: ItemUid::next_uid(),
            _marker: PhantomData,
        };

        #[cfg(debug_assertions)]
        data.on_interned(handle.uid);

        // Store this handle so the next time it is
        // interned, it gets re-used.
        self.map.insert(data.clone(), handle);

        // Create the local data for this item that is
        // being interned.
        self.local_data.entry(index).set(Item {
            epoch: self.current_epoch,
            data: f(),
        });

        handle
    }

    /// Retrieve the pending list of updates for an interner
    /// that need to be applied to the data store. Also run
    /// a GC step that removes old entries.
    pub fn end_frame_and_get_pending_updates(&mut self) -> UpdateList<S> {
        let mut updates = mem::replace(&mut self.updates, Vec::new());
        let data = mem::replace(&mut self.update_data, Vec::new());

        let free_list = &mut self.free_list;
        let current_epoch = self.current_epoch.0;

        // First, run a GC step. Walk through the handles, and
        // if we find any that haven't been used for some time,
        // remove them. If this ever shows up in profiles, we
        // can make the GC step partial (scan only part of the
        // map each frame). It also might make sense in the
        // future to adjust how long items remain in the cache
        // based on the current size of the list.
        self.map.retain(|_, handle| {
            if handle.epoch.0 + 10 < current_epoch {
                // To expire an item:
                //  - Add index to the free-list for re-use.
                //  - Add an update to the data store to invalidate this slow.
                //  - Remove from the hash map.
                free_list.push(handle.index as usize);
                updates.push(Update {
                    index: handle.index as usize,
                    kind: UpdateKind::Remove,
                });
                return false;
            }

            true
        });

        let updates = UpdateList {
            updates,
            data,
            epoch: self.current_epoch,
        };

        // Begin the next epoch
        self.current_epoch = Epoch(self.current_epoch.0 + 1);

        updates
    }
}

/// Retrieve the local data for an item from the interner via handle
impl<S, D, M> ops::Index<Handle<M>> for Interner<S, D, M>
where
    S: Eq + Clone + Hash + Debug + MallocSizeOf,
    D: MallocSizeOf,
    M: Copy + Debug + MallocSizeOf
{
    type Output = D;
    fn index(&self, handle: Handle<M>) -> &D {
        let item = &self.local_data[handle.index as usize];
        assert_eq!(item.epoch, handle.epoch);
        &item.data
    }
}

/// Implement `Internable` for a type that wants participate in interning.
///
/// see DisplayListFlattener::add_interned_primitive<P>
pub trait Internable {
    type Marker: Copy + Debug + MallocSizeOf;
    type Source: Eq + Hash + Clone + Debug + MallocSizeOf;
    type StoreData: From<Self::Source> + MallocSizeOf;
    type InternData: MallocSizeOf;

    /// Build a new key from self with `info`.
    fn build_key(
        self,
        info: &LayoutPrimitiveInfo,
    ) -> Self::Source;
}
<commit_msg>Bug 1506449 - Use an Option<T> instead of Item<T> in DataStore. r=gw<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The interning module provides a generic data structure
//! interning container. It is similar in concept to a
//! traditional string interning container, but it is
//! specialized to the WR thread model.
//!
//! There is an Interner structure, that lives in the
//! scene builder thread, and a DataStore structure
//! that lives in the frame builder thread.
//!
//! Hashing, interning and handle creation is done by
//! the interner structure during scene building.
//!
//! Delta changes for the interner are pushed during
//! a transaction to the frame builder. The frame builder
//! is then able to access the content of the interned
//! handles quickly, via array indexing.
//!
//! Epoch tracking ensures that the garbage collection
//! step which the interner uses to remove items is
//! only invoked on items that the frame builder thread
//! is no longer referencing.
//!
//! Items in the data store are stored in a traditional
//! free-list structure, for content access and memory
//! usage efficiency.
//!
//! The epoch is incremented each time a scene is
//! built. The most recently used scene epoch is
//! stored inside each handle. This is then used for
//! cache invalidation.

use api::{LayoutPrimitiveInfo};
use internal_types::FastHashMap;
use malloc_size_of::MallocSizeOf;
use profiler::ResourceProfileCounter;
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::{mem, ops, u64};
use std::sync::atomic::{AtomicUsize, Ordering};
use util::VecHelper;

#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
struct Epoch(u64);

/// A list of updates to be applied to the data store,
/// provided by the interning structure.
pub struct UpdateList<S> {
    /// The additions and removals to apply.
    updates: Vec<Update>,
    /// Actual new data to insert.
    data: Vec<S>,
}

lazy_static! {
    static ref NEXT_UID: AtomicUsize = AtomicUsize::new(0);
}

/// A globally, unique identifier
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct ItemUid {
    uid: usize,
}

impl ItemUid {
    pub fn next_uid() -> ItemUid {
        let uid = NEXT_UID.fetch_add(1, Ordering::Relaxed);
        ItemUid { uid }
    }
}

#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, MallocSizeOf)]
pub struct Handle<M: Copy> {
    index: u32,
    epoch: Epoch,
    uid: ItemUid,
    _marker: PhantomData<M>,
}

impl <M> Handle<M> where M: Copy {
    pub fn uid(&self) -> ItemUid {
        self.uid
    }
}

#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub enum UpdateKind {
    Insert,
    Remove,
}

#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct Update {
    index: usize,
    kind: UpdateKind,
}

pub trait InternDebug {
    fn on_interned(&self, _uid: ItemUid) {}
}

/// The data store lives in the frame builder thread. It
/// contains a free-list of items for fast access.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct DataStore<S, T: MallocSizeOf, M> {
    items: Vec<Option<T>>,
    _source: PhantomData<S>,
    _marker: PhantomData<M>,
}

impl<S, T, M> ::std::default::Default for DataStore<S, T, M>
where
    S: Debug + MallocSizeOf,
    T: From<S> + MallocSizeOf,
    M: Debug
{
    fn default() -> Self {
        DataStore {
            items: Vec::new(),
            _source: PhantomData,
            _marker: PhantomData,
        }
    }
}

impl<S, T, M> DataStore<S, T, M>
where
    S: Debug + MallocSizeOf,
    T: From<S> + MallocSizeOf,
    M: Debug
{
    /// Apply any updates from the scene builder thread to
    /// this data store.
    pub fn apply_updates(
        &mut self,
        update_list: UpdateList<S>,
        profile_counter: &mut ResourceProfileCounter,
    ) {
        let mut data_iter = update_list.data.into_iter();
        for update in update_list.updates {
            match update.kind {
                UpdateKind::Insert => {
                    self.items.entry(update.index).
                        set(Some(T::from(data_iter.next().unwrap())));
                }
                UpdateKind::Remove => {
                    self.items[update.index] = None;
                }
            }
        }

        let per_item_size = mem::size_of::<S>() + mem::size_of::<T>();
        profile_counter.set(self.items.len(), per_item_size * self.items.len());

        debug_assert!(data_iter.next().is_none());
    }
}

/// Retrieve an item from the store via handle
impl<S, T, M> ops::Index<Handle<M>> for DataStore<S, T, M>
where
    S: MallocSizeOf,
    T: MallocSizeOf,
    M: Copy
{
    type Output = T;
    fn index(&self, handle: Handle<M>) -> &T {
        self.items[handle.index as usize].as_ref().expect("Bad datastore lookup")
    }
}

/// Retrieve a mutable item from the store via handle
/// Retrieve an item from the store via handle
impl<S, T, M> ops::IndexMut<Handle<M>> for DataStore<S, T, M>
where
    S: MallocSizeOf,
    T: MallocSizeOf,
    M: Copy
{
    fn index_mut(&mut self, handle: Handle<M>) -> &mut T {
        self.items[handle.index as usize].as_mut().expect("Bad datastore lookup")
    }
}

/// The main interning data structure. This lives in the
/// scene builder thread, and handles hashing and interning
/// unique data structures. It also manages a free-list for
/// the items in the data store, which is synchronized via
/// an update list of additions / removals.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct Interner<S, D, M>
where
    S: Eq + Hash + Clone + Debug + MallocSizeOf,
    D: MallocSizeOf,
    M: Copy + MallocSizeOf,
{
    /// Uniquely map an interning key to a handle
    map: FastHashMap<S, Handle<M>>,
    /// List of free slots in the data store for re-use.
    free_list: Vec<usize>,
    /// Pending list of updates that need to be applied.
    updates: Vec<Update>,
    /// Pending new data to insert.
    update_data: Vec<S>,
    /// The current epoch for the interner.
    current_epoch: Epoch,
    /// The information associated with each interned
    /// item that can be accessed by the interner.
    local_data: Vec<D>,
}

impl<S, D, M> ::std::default::Default for Interner<S, D, M>
where
    S: Eq + Hash + Clone + Debug + MallocSizeOf,
    D: MallocSizeOf,
    M: Copy + Debug + MallocSizeOf,
{
    fn default() -> Self {
        Interner {
            map: FastHashMap::default(),
            free_list: Vec::new(),
            updates: Vec::new(),
            update_data: Vec::new(),
            current_epoch: Epoch(1),
            local_data: Vec::new(),
        }
    }
}

impl<S, D, M> Interner<S, D, M>
where
    S: Eq + Hash + Clone + Debug + InternDebug + MallocSizeOf,
    D: MallocSizeOf,
    M: Copy + Debug + MallocSizeOf
{
    /// Intern a data structure, and return a handle to
    /// that data. The handle can then be stored in the
    /// frame builder, and safely accessed via the data
    /// store that lives in the frame builder thread.
    /// The provided closure is invoked to build the
    /// local data about an interned structure if the
    /// key isn't already interned.
    pub fn intern<F>(
        &mut self,
        data: &S,
        f: F,
    ) -> Handle<M> where F: FnOnce() -> D {
        // Use get_mut rather than entry here to avoid
        // cloning the (sometimes large) key in the common
        // case, where the data already exists in the interner.
        if let Some(handle) = self.map.get_mut(data) {
            handle.epoch = self.current_epoch;
            return *handle;
        }

        // We need to intern a new data item. First, find out
        // if there is a spare slot in the free-list that we
        // can use. Otherwise, append to the end of the list.
        let index = match self.free_list.pop() {
            Some(index) => index,
            None => self.local_data.len(),
        };

        // Add a pending update to insert the new data.
        self.updates.push(Update {
            index,
            kind: UpdateKind::Insert,
        });
        self.update_data.alloc().init(data.clone());

        // Generate a handle for access via the data store.
        let handle = Handle {
            index: index as u32,
            epoch: self.current_epoch,
            uid: ItemUid::next_uid(),
            _marker: PhantomData,
        };

        #[cfg(debug_assertions)]
        data.on_interned(handle.uid);

        // Store this handle so the next time it is
        // interned, it gets re-used.
        self.map.insert(data.clone(), handle);

        // Create the local data for this item that is
        // being interned.
        self.local_data.entry(index).set(f());

        handle
    }

    /// Retrieve the pending list of updates for an interner
    /// that need to be applied to the data store. Also run
    /// a GC step that removes old entries.
    pub fn end_frame_and_get_pending_updates(&mut self) -> UpdateList<S> {
        let mut updates = mem::replace(&mut self.updates, Vec::new());
        let data = mem::replace(&mut self.update_data, Vec::new());

        let free_list = &mut self.free_list;
        let current_epoch = self.current_epoch.0;

        // First, run a GC step. Walk through the handles, and
        // if we find any that haven't been used for some time,
        // remove them. If this ever shows up in profiles, we
        // can make the GC step partial (scan only part of the
        // map each frame). It also might make sense in the
        // future to adjust how long items remain in the cache
        // based on the current size of the list.
        self.map.retain(|_, handle| {
            if handle.epoch.0 + 10 < current_epoch {
                // To expire an item:
                //  - Add index to the free-list for re-use.
                //  - Add an update to the data store to invalidate this slow.
                //  - Remove from the hash map.
                free_list.push(handle.index as usize);
                updates.push(Update {
                    index: handle.index as usize,
                    kind: UpdateKind::Remove,
                });
                return false;
            }

            true
        });

        let updates = UpdateList {
            updates,
            data,
        };

        // Begin the next epoch
        self.current_epoch = Epoch(self.current_epoch.0 + 1);

        updates
    }
}

/// Retrieve the local data for an item from the interner via handle
impl<S, D, M> ops::Index<Handle<M>> for Interner<S, D, M>
where
    S: Eq + Clone + Hash + Debug + MallocSizeOf,
    D: MallocSizeOf,
    M: Copy + Debug + MallocSizeOf
{
    type Output = D;
    fn index(&self, handle: Handle<M>) -> &D {
        &self.local_data[handle.index as usize]
    }
}

/// Implement `Internable` for a type that wants participate in interning.
///
/// see DisplayListFlattener::add_interned_primitive<P>
pub trait Internable {
    type Marker: Copy + Debug + MallocSizeOf;
    type Source: Eq + Hash + Clone + Debug + MallocSizeOf;
    type StoreData: From<Self::Source> + MallocSizeOf;
    type InternData: MallocSizeOf;

    /// Build a new key from self with `info`.
    fn build_key(
        self,
        info: &LayoutPrimitiveInfo,
    ) -> Self::Source;
}
<|endoftext|>


<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.

//! Random number generators and adapters
//!
//! ## Background: Random number generators (RNGs)
//!
//! Computers cannot produce random numbers from nowhere. We classify
//! random number generators as follows:
//!
//! -   "True" random number generators (TRNGs) use hard-to-predict data sources
//!     (e.g. the high-resolution parts of event timings and sensor jitter) to
//!     harvest random bit-sequences, apply algorithms to remove bias and
//!     estimate available entropy, then combine these bits into a byte-sequence
//!     or an entropy pool. This job is usually done by the operating system or
//!     a hardware generator (HRNG).
//! -   "Pseudo"-random number generators (PRNGs) use algorithms to transform a
//!     seed into a sequence of pseudo-random numbers. These generators can be
//!     fast and produce well-distributed unpredictable random numbers (or not).
//!     They are usually deterministic: given algorithm and seed, the output
//!     sequence can be reproduced. They have finite period and eventually loop;
//!     with many algorithms this period is fixed and can be proven sufficiently
//!     long, while others are chaotic and the period depends on the seed.
//! -   "Cryptographically secure" pseudo-random number generators (CSPRNGs)
//!     are the sub-set of PRNGs which are secure. Security of the generator
//!     relies both on hiding the internal state and using a strong algorithm.
//!
//! ## Traits and functionality
//!
//! All RNGs implement the [`RngCore`] trait, as a consequence of which the
//! [`Rng`] extension trait is automatically implemented. Secure RNGs may
//! additionally implement the [`CryptoRng`] trait.
//!
//! All PRNGs require a seed to produce their random number sequence. The
//! [`SeedableRng`] trait provides three ways of constructing PRNGs:
//!
//! -   `from_seed` accepts a type specific to the PRNG
//! -   `from_rng` allows a PRNG to be seeded from any other RNG
//! -   `seed_from_u64` allows any PRNG to be seeded from a `u64` insecurely
//! -   `from_entropy` securely seeds a PRNG from fresh entropy
//!
//! Use the [`rand_core`] crate when implementing your own RNGs.
//!
//! ## Our generators
//!
//! This crate provides several random number generators:
//!
//! -   [`OsRng`] is an interface to the operating system's random number
//!     source. Typically the operating system uses a CSPRNG with entropy
//!     provided by a TRNG and some type of on-going re-seeding.
//! -   [`ThreadRng`], provided by the [`thread_rng`] function, is a handle to a
//!     thread-local CSPRNG with periodic seeding from [`OsRng`]. Because this
//!     is local, it is typically much faster than [`OsRng`]. It should be
//!     secure, though the paranoid may prefer [`OsRng`].
//! -   [`StdRng`] is a CSPRNG chosen for good performance and trust of security
//!     (based on reviews, maturity and usage). The current algorithm is ChaCha20,
//!     which is well established and rigorously analysed.
//!     [`StdRng`] provides the algorithm used by [`ThreadRng`] but without
//!     periodic reseeding.
//! -   [`SmallRng`] is an **insecure** PRNG designed to be fast, simple, require
//!     little memory, and have good output quality.
//!
//! The algorithms selected for [`StdRng`] and [`SmallRng`] may change in any
//! release and may be platform-dependent, therefore they should be considered
//! **not reproducible**.
//!
//! ## Additional generators
//!
//! **TRNGs**: The [`rdrand`] crate provides an interface to the RDRAND and
//! RDSEED instructions available in modern Intel and AMD CPUs.
//! The [`rand_jitter`] crate provides a user-space implementation of
//! entropy harvesting from CPU timer jitter, but is very slow and has
//! [security issues](https://github.com/rust-random/rand/issues/699).
//!
//! **PRNGs**: Several companion crates are available, providing individual or
//! families of PRNG algorithms. These provide the implementations behind
//! [`StdRng`] and [`SmallRng`] but can also be used directly, indeed *should*
//! be used directly when **reproducibility** matters.
//! Some suggestions are: [`rand_chacha`], [`rand_pcg`], [`rand_xoshiro`].
//! A full list can be found by searching for crates with the [`rng` tag].
//!
//! [`Rng`]: crate::Rng
//! [`RngCore`]: crate::RngCore
//! [`CryptoRng`]: crate::CryptoRng
//! [`SeedableRng`]: crate::SeedableRng
//! [`thread_rng`]: crate::thread_rng
//! [`rdrand`]: https://crates.io/crates/rdrand
//! [`rand_jitter`]: https://crates.io/crates/rand_jitter
//! [`rand_chacha`]: https://crates.io/crates/rand_chacha
//! [`rand_pcg`]: https://crates.io/crates/rand_pcg
//! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro
//! [`rng` tag]: https://crates.io/keywords/rng

#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg(feature = "std")] pub mod adapter;

pub mod mock; // Public so we don't export `StepRng` directly, making it a bit
              // more clear it is intended for testing.

#[cfg(all(feature = "small_rng", target_pointer_width = "64"))]
mod xoshiro256plusplus;
#[cfg(all(feature = "small_rng", not(target_pointer_width = "64")))]
mod xoshiro128plusplus;
#[cfg(feature = "small_rng")] mod small;

#[cfg(feature = "std_rng")] mod std;
#[cfg(all(feature = "std", feature = "std_rng"))] pub(crate) mod thread;

#[cfg(feature = "small_rng")] pub use self::small::SmallRng;
#[cfg(feature = "std_rng")] pub use self::std::StdRng;
#[cfg(all(feature = "std", feature = "std_rng"))] pub use self::thread::ThreadRng;

#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
#[cfg(feature = "getrandom")] pub use rand_core::OsRng;
<commit_msg>update StdRng docs after switch to ChaCha12 (#1028)<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.

//! Random number generators and adapters
//!
//! ## Background: Random number generators (RNGs)
//!
//! Computers cannot produce random numbers from nowhere. We classify
//! random number generators as follows:
//!
//! -   "True" random number generators (TRNGs) use hard-to-predict data sources
//!     (e.g. the high-resolution parts of event timings and sensor jitter) to
//!     harvest random bit-sequences, apply algorithms to remove bias and
//!     estimate available entropy, then combine these bits into a byte-sequence
//!     or an entropy pool. This job is usually done by the operating system or
//!     a hardware generator (HRNG).
//! -   "Pseudo"-random number generators (PRNGs) use algorithms to transform a
//!     seed into a sequence of pseudo-random numbers. These generators can be
//!     fast and produce well-distributed unpredictable random numbers (or not).
//!     They are usually deterministic: given algorithm and seed, the output
//!     sequence can be reproduced. They have finite period and eventually loop;
//!     with many algorithms this period is fixed and can be proven sufficiently
//!     long, while others are chaotic and the period depends on the seed.
//! -   "Cryptographically secure" pseudo-random number generators (CSPRNGs)
//!     are the sub-set of PRNGs which are secure. Security of the generator
//!     relies both on hiding the internal state and using a strong algorithm.
//!
//! ## Traits and functionality
//!
//! All RNGs implement the [`RngCore`] trait, as a consequence of which the
//! [`Rng`] extension trait is automatically implemented. Secure RNGs may
//! additionally implement the [`CryptoRng`] trait.
//!
//! All PRNGs require a seed to produce their random number sequence. The
//! [`SeedableRng`] trait provides three ways of constructing PRNGs:
//!
//! -   `from_seed` accepts a type specific to the PRNG
//! -   `from_rng` allows a PRNG to be seeded from any other RNG
//! -   `seed_from_u64` allows any PRNG to be seeded from a `u64` insecurely
//! -   `from_entropy` securely seeds a PRNG from fresh entropy
//!
//! Use the [`rand_core`] crate when implementing your own RNGs.
//!
//! ## Our generators
//!
//! This crate provides several random number generators:
//!
//! -   [`OsRng`] is an interface to the operating system's random number
//!     source. Typically the operating system uses a CSPRNG with entropy
//!     provided by a TRNG and some type of on-going re-seeding.
//! -   [`ThreadRng`], provided by the [`thread_rng`] function, is a handle to a
//!     thread-local CSPRNG with periodic seeding from [`OsRng`]. Because this
//!     is local, it is typically much faster than [`OsRng`]. It should be
//!     secure, though the paranoid may prefer [`OsRng`].
//! -   [`StdRng`] is a CSPRNG chosen for good performance and trust of security
//!     (based on reviews, maturity and usage). The current algorithm is ChaCha12,
//!     which is well established and rigorously analysed.
//!     [`StdRng`] provides the algorithm used by [`ThreadRng`] but without
//!     periodic reseeding.
//! -   [`SmallRng`] is an **insecure** PRNG designed to be fast, simple, require
//!     little memory, and have good output quality.
//!
//! The algorithms selected for [`StdRng`] and [`SmallRng`] may change in any
//! release and may be platform-dependent, therefore they should be considered
//! **not reproducible**.
//!
//! ## Additional generators
//!
//! **TRNGs**: The [`rdrand`] crate provides an interface to the RDRAND and
//! RDSEED instructions available in modern Intel and AMD CPUs.
//! The [`rand_jitter`] crate provides a user-space implementation of
//! entropy harvesting from CPU timer jitter, but is very slow and has
//! [security issues](https://github.com/rust-random/rand/issues/699).
//!
//! **PRNGs**: Several companion crates are available, providing individual or
//! families of PRNG algorithms. These provide the implementations behind
//! [`StdRng`] and [`SmallRng`] but can also be used directly, indeed *should*
//! be used directly when **reproducibility** matters.
//! Some suggestions are: [`rand_chacha`], [`rand_pcg`], [`rand_xoshiro`].
//! A full list can be found by searching for crates with the [`rng` tag].
//!
//! [`Rng`]: crate::Rng
//! [`RngCore`]: crate::RngCore
//! [`CryptoRng`]: crate::CryptoRng
//! [`SeedableRng`]: crate::SeedableRng
//! [`thread_rng`]: crate::thread_rng
//! [`rdrand`]: https://crates.io/crates/rdrand
//! [`rand_jitter`]: https://crates.io/crates/rand_jitter
//! [`rand_chacha`]: https://crates.io/crates/rand_chacha
//! [`rand_pcg`]: https://crates.io/crates/rand_pcg
//! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro
//! [`rng` tag]: https://crates.io/keywords/rng

#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg(feature = "std")] pub mod adapter;

pub mod mock; // Public so we don't export `StepRng` directly, making it a bit
              // more clear it is intended for testing.

#[cfg(all(feature = "small_rng", target_pointer_width = "64"))]
mod xoshiro256plusplus;
#[cfg(all(feature = "small_rng", not(target_pointer_width = "64")))]
mod xoshiro128plusplus;
#[cfg(feature = "small_rng")] mod small;

#[cfg(feature = "std_rng")] mod std;
#[cfg(all(feature = "std", feature = "std_rng"))] pub(crate) mod thread;

#[cfg(feature = "small_rng")] pub use self::small::SmallRng;
#[cfg(feature = "std_rng")] pub use self::std::StdRng;
#[cfg(all(feature = "std", feature = "std_rng"))] pub use self::thread::ThreadRng;

#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
#[cfg(feature = "getrandom")] pub use rand_core::OsRng;
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;

#[derive(Default)]
pub struct DecodeRegister {
    pub addr_init: u16,
    pub addr_intermediate: u16,
    pub addr_final: u16,

    pub value_init: u8,
    pub value_intermediate: u8,
    pub value_final: u8,

    pub info: OpcodeExecInfo,
}

#[allow(non_snake_case)]
#[derive(Default)]
pub struct CpuState {
    pub pc: u16,
    pub sp: u8,
    pub a:  u8,
    pub x:  u8,
    pub y:  u8,

    // flags
    pub C: bool, // carry
    pub Z: bool, // zero
    pub I: bool, // interrupt
    pub D: bool, // decimal
    pub B: bool, // break
             // bit 5 is not used by the nes and is always 1
    pub V: bool, // overflow
    pub S: bool, // sign/negative

    // these are not strictly 6502 registers, but are useful for modeling the cpu
    pub instruction_register: u8,
    pub decode_register:DecodeRegister,
}

impl CpuState {
    pub fn unpack_flags(self: &CpuState) -> u8 {
        ( (self.C as u8) << 0)
      | ( (self.Z as u8) << 1)
      | ( (self.I as u8) << 2)
      | ( (self.D as u8) << 3)
      | ( (self.B as u8) << 4)
      | ( (1           ) << 5) // flag 5 is unused
      | ( (self.V as u8) << 6)
      | ( (self.S as u8) << 7)
    }
    pub fn pack_flags(self: &mut CpuState,flags:u8) {
        self.C        = ( (flags >> 0) & 1) == 1;
        self.Z        = ( (flags >> 1) & 1) == 1;
        self.I        = ( (flags >> 2) & 1) == 1;
        self.D        = ( (flags >> 3) & 1) == 1;
        self.B        = ( (flags >> 4) & 1) == 1;
        // flags 5 is unused
        self.V        = ( (flags >> 6) & 1) == 1;
        self.S        = ( (flags >> 7) & 1) == 1;
    }
}
<commit_msg>values in the DecodeRegister are now optional types<commit_after>use cpu::common_defs::OpcodeExecInfo;
use std::option::Option;

#[derive(Default)]
pub struct DecodeRegister {
    pub addr_init: Option<u16>,
    pub addr_intermediate: Option<u16>,
    pub addr_final: Option<u16>,

    pub value_init: Option<u8>,
    pub value_intermediate: Option<u8>,
    pub value_final: Option<u8>,

    pub info: OpcodeExecInfo,
}

#[allow(non_snake_case)]
#[derive(Default)]
pub struct CpuState {
    pub pc: u16,
    pub sp: u8,
    pub a:  u8,
    pub x:  u8,
    pub y:  u8,

    // flags
    pub C: bool, // carry
    pub Z: bool, // zero
    pub I: bool, // interrupt
    pub D: bool, // decimal
    pub B: bool, // break
             // bit 5 is not used by the nes and is always 1
    pub V: bool, // overflow
    pub S: bool, // sign/negative

    // these are not strictly 6502 registers, but are useful for modeling the cpu
    pub instruction_register: u8,
    pub decode_register:DecodeRegister,
}

impl CpuState {
    pub fn unpack_flags(self: &CpuState) -> u8 {
        ( (self.C as u8) << 0)
      | ( (self.Z as u8) << 1)
      | ( (self.I as u8) << 2)
      | ( (self.D as u8) << 3)
      | ( (self.B as u8) << 4)
      | ( (1           ) << 5) // flag 5 is unused
      | ( (self.V as u8) << 6)
      | ( (self.S as u8) << 7)
    }
    pub fn pack_flags(self: &mut CpuState,flags:u8) {
        self.C        = ( (flags >> 0) & 1) == 1;
        self.Z        = ( (flags >> 1) & 1) == 1;
        self.I        = ( (flags >> 2) & 1) == 1;
        self.D        = ( (flags >> 3) & 1) == 1;
        self.B        = ( (flags >> 4) & 1) == 1;
        // flags 5 is unused
        self.V        = ( (flags >> 6) & 1) == 1;
        self.S        = ( (flags >> 7) & 1) == 1;
    }
}
<|endoftext|>


<commit_before>extern crate vk_api;
extern crate xml;

use std::fs::File;
use std::io::BufWriter;
use std::io::Write;

use xml::EventReader;
use xml::reader::XmlEvent;
use xml::name::OwnedName;
use xml::attribute::OwnedAttribute;

pub fn load_xml() {
    let output = File::create("output.txt").unwrap();
    let mut output = BufWriter::with_capacity(20000*1024, output);
    let vk_xml = EventReader::new(vk_api::VK_XML);

    let mut vk_elements = Vec::with_capacity(10);
    let mut delta = true;
    for event in vk_xml.into_iter() {
        let event = event.unwrap();
        match event {
            XmlEvent::StartElement{ name, attributes, .. } => {
                vk_elements.push(XmlElement::new_tag(name, attributes));
                delta = true;
            }

            XmlEvent::EndElement{ name } => {
                pop_element_stack(&mut vk_elements, name);
            }

            XmlEvent::Characters(chars) => {
                vk_elements.push(XmlElement::Characters(chars));
                delta = true;
            }

            _ => ()
        }

        if delta == true {
            write!(&mut output, "{:#?}\n", vk_elements).unwrap();
        }
        delta = false;
    }
}

fn pop_element_stack(vk_elements: &mut Vec<XmlElement>, end_name: OwnedName) {
    match vk_elements.pop() {
        Some(el) =>
            if let XmlElement::Characters(_) = el {
                pop_element_stack(vk_elements, end_name)
            },

        None => panic!("Invalid xml; Unexpected closing tag")
    }
}

#[derive(Debug)]
enum XmlElement {
    Tag {
        /// The name of the tag e.g. "hello" in <hello>
        name: String,
        /// The attributes contained within the specification xml.
        attributes: Vec<VkAttribute>
    },
    Characters( String )
}

impl XmlElement {
    fn new_tag(name: OwnedName, attributes: Vec<OwnedAttribute>) -> XmlElement {
        XmlElement::Tag {
            name: name.local_name,
            attributes: attributes.into_iter().map(
                |a| VkAttribute {
                    name: a.name.local_name,
                    value: a.value
                }).collect()
        }
    }
}

#[derive(Debug)]
struct VkAttribute{
    name: String,
    value: String
}<commit_msg>Changed XmlElement to use OwnedAttribute vector instead of VkAttribute vector<commit_after>extern crate vk_api;
extern crate xml;

use std::fs::File;
use std::io::BufWriter;
use std::io::Write;

use xml::EventReader;
use xml::reader::XmlEvent;
use xml::name::OwnedName;
use xml::attribute::OwnedAttribute;

pub fn load_xml() {
    let output = File::create("output.txt").unwrap();
    let mut output = BufWriter::with_capacity(20000*1024, output);
    let vk_xml = EventReader::new(vk_api::VK_XML);

    let mut vk_elements = Vec::with_capacity(10);
    let mut delta = true;
    for event in vk_xml.into_iter() {
        let event = event.unwrap();
        match event {
            XmlEvent::StartElement{ name, attributes, .. } => {
                vk_elements.push(XmlElement::new_tag(name, attributes));
                delta = true;
            }

            XmlEvent::EndElement{ name } => {
                pop_element_stack(&mut vk_elements, name);
            }

            XmlEvent::Characters(chars) => {
                vk_elements.push(XmlElement::Characters(chars));
                delta = true;
            }

            _ => ()
        }

        if delta == true {
            write!(&mut output, "{:#?}\n", vk_elements).unwrap();
        }
        delta = false;
    }
}

fn pop_element_stack(vk_elements: &mut Vec<XmlElement>, end_name: OwnedName) {
    match vk_elements.pop() {
        Some(el) =>
            if let XmlElement::Characters(_) = el {
                pop_element_stack(vk_elements, end_name)
            },

        None => panic!("Invalid xml; Unexpected closing tag")
    }
}

#[derive(Debug)]
enum XmlElement {
    Tag {
        /// The name of the tag e.g. "hello" in <hello>
        name: String,
        /// The attributes contained within the specification xml.
        attributes: Vec<OwnedAttribute>
    },
    Characters( String )
}

impl XmlElement {
    fn new_tag(name: OwnedName, attributes: Vec<OwnedAttribute>) -> XmlElement {
        XmlElement::Tag {
            name: name.local_name,
            attributes: attributes
        }
    }
}<|endoftext|>


<commit_before>extern crate clap;
#[macro_use] extern crate log;
extern crate toml;

extern crate libimagstore;

pub mod cli;
pub mod error;
pub mod lister;
pub mod listers;
pub mod result;

<commit_msg>Enable lints<commit_after>#![deny(
    dead_code,
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
#[macro_use] extern crate log;
extern crate toml;

extern crate libimagstore;

pub mod cli;
pub mod error;
pub mod lister;
pub mod listers;
pub mod result;

<|endoftext|>


<commit_before>use std::path::PathBuf;

use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;
use std::path::Components;

use libimagerror::into::IntoError;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    base: Option<PathBuf>,
    id:   PathBuf,
}

impl StoreId {

    pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
        StoreId::new_baseless(id).map(|mut sid| { sid.base = base; sid })
    }

    pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
        if id.is_absolute() {
            Err(SEK::StoreIdLocalPartAbsoluteError.into_error())
        } else {
            Ok(StoreId {
                base: None,
                id: id
            })
        }
    }

    pub fn without_base(mut self) -> StoreId {
        self.base = None;
        self
    }

    pub fn with_base(mut self, base: PathBuf) -> Self {
        self.base = Some(base);
        self
    }

    pub fn storified(self, store: &Store) -> StoreId {
        StoreId {
            base: Some(store.path().clone()),
            id: self.id
        }
    }

    pub fn exists(&self) -> bool {
        let pb : PathBuf = self.clone().into();
        pb.exists()
    }

    pub fn is_file(&self) -> bool {
        true
    }

    pub fn is_dir(&self) -> bool {
        false
    }

    pub fn to_str(&self) -> Result<String> {
        if self.base.is_some() {
            let mut base = self.base.as_ref().cloned().unwrap();
            base.push(self.id.clone());
            base
        } else {
            self.id.clone()
        }
        .to_str()
        .map(String::from)
        .ok_or(SEK::StoreIdHandlingError.into_error())
    }

    /// Returns the components of the `id` part of the StoreId object.
    ///
    /// Can be used to check whether a StoreId points to an entry in a specific collection of
    /// StoreIds.
    pub fn components(&self) -> Components {
        self.id.components()
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        let mut base = self.base.unwrap_or(PathBuf::from("/"));
        base.push(self.id);
        base
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.id.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.id.to_string_lossy()),
        }
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> Result<StoreId>;
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> Result<StoreId> {
        Ok(self)
    }
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> Result<StoreId> {
        StoreId::new_baseless(self)
    }
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;
            use $crate::store::Result;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(name);
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> Result<$crate::storeid::StoreId> {
                    StoreId::new(None, self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().unwrap().to_str().unwrap(), "test/test");
    }

}
<commit_msg>Add StoreId::is_in_collection()<commit_after>use std::path::PathBuf;

use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;
use std::path::Components;

use libimagerror::into::IntoError;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    base: Option<PathBuf>,
    id:   PathBuf,
}

impl StoreId {

    pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
        StoreId::new_baseless(id).map(|mut sid| { sid.base = base; sid })
    }

    pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
        if id.is_absolute() {
            Err(SEK::StoreIdLocalPartAbsoluteError.into_error())
        } else {
            Ok(StoreId {
                base: None,
                id: id
            })
        }
    }

    pub fn without_base(mut self) -> StoreId {
        self.base = None;
        self
    }

    pub fn with_base(mut self, base: PathBuf) -> Self {
        self.base = Some(base);
        self
    }

    pub fn storified(self, store: &Store) -> StoreId {
        StoreId {
            base: Some(store.path().clone()),
            id: self.id
        }
    }

    pub fn exists(&self) -> bool {
        let pb : PathBuf = self.clone().into();
        pb.exists()
    }

    pub fn is_file(&self) -> bool {
        true
    }

    pub fn is_dir(&self) -> bool {
        false
    }

    pub fn to_str(&self) -> Result<String> {
        if self.base.is_some() {
            let mut base = self.base.as_ref().cloned().unwrap();
            base.push(self.id.clone());
            base
        } else {
            self.id.clone()
        }
        .to_str()
        .map(String::from)
        .ok_or(SEK::StoreIdHandlingError.into_error())
    }

    /// Returns the components of the `id` part of the StoreId object.
    ///
    /// Can be used to check whether a StoreId points to an entry in a specific collection of
    /// StoreIds.
    pub fn components(&self) -> Components {
        self.id.components()
    }

    /// Check whether a StoreId points to an entry in a specific collection.
    ///
    /// A "collection" here is simply a directory. So `foo/bar/baz` is an entry which is in
    /// collection ["foo", "bar"].
    ///
    /// # Warning
    ///
    /// The collection specification _has_ to start with the module name. Otherwise this function
    /// may return false negatives.
    ///
    pub fn is_in_collection(&self, colls: &[&str]) -> bool {
        use std::path::Component;

        self.id
            .components()
            .zip(colls)
            .map(|(component, pred_coll)| match component {
                Component::Normal(ref s) => s.to_str().map(|ref s| s == pred_coll).unwrap_or(false),
                _ => false
            })
            .all(|x| x) && colls.last().map(|last| !self.id.ends_with(last)).unwrap_or(false)
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        let mut base = self.base.unwrap_or(PathBuf::from("/"));
        base.push(self.id);
        base
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.id.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.id.to_string_lossy()),
        }
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> Result<StoreId>;
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> Result<StoreId> {
        Ok(self)
    }
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> Result<StoreId> {
        StoreId::new_baseless(self)
    }
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;
            use $crate::store::Result;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(name);
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> Result<$crate::storeid::StoreId> {
                    StoreId::new(None, self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().unwrap().to_str().unwrap(), "test/test");
    }

    #[test]
    fn storeid_in_collection() {
        let p = module_path::ModuleEntryPath::new("1/2/3/4/5/6/7/8/9/0").into_storeid().unwrap();

        assert!(p.is_in_collection(&["test", "1"]));
        assert!(p.is_in_collection(&["test", "1", "2"]));
        assert!(p.is_in_collection(&["test", "1", "2", "3"]));
        assert!(p.is_in_collection(&["test", "1", "2", "3", "4"]));
        assert!(p.is_in_collection(&["test", "1", "2", "3", "4", "5"]));
        assert!(p.is_in_collection(&["test", "1", "2", "3", "4", "5", "6"]));
        assert!(p.is_in_collection(&["test", "1", "2", "3", "4", "5", "6", "7"]));
        assert!(p.is_in_collection(&["test", "1", "2", "3", "4", "5", "6", "7", "8"]));
        assert!(p.is_in_collection(&["test", "1", "2", "3", "4", "5", "6", "7", "8", "9"]));

        // "0" is the filename, not a collection
        assert!(!p.is_in_collection(&["test", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]));

        assert!(!p.is_in_collection(&["test", "0", "2", "3", "4", "5", "6", "7", "8", "9", "0"]));
        assert!(!p.is_in_collection(&["test", "1", "2", "3", "4", "5", "6", "8"]));
        assert!(!p.is_in_collection(&["test", "1", "2", "3", "leet", "5", "6", "7"]));
    }

}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::rc::Rc;

use automation::Automation;
use partial::Partial;
use tree::node::{ANode, NodeInputSlot, YNode};
use tree::send::{AASend, AYSend, Send, YYSend};
use tree::tree::Tree;

use render::render_spec::RenderSpec;

use super::partial_renderer::PartialRenderer;

/// Tracks all the partials/automations that have ever entered the node.
/// This information is needed in order to evaluate the output whenever
/// a new input arrives.
struct ANodeState {
    left: Vec<Automation>,
    right: Vec<Automation>,
    aasends: Vec<AASend>,
    aysends: Vec<AYSend>,
}

/// Tracks all the partials/automations that have ever entered the node.
/// This information is needed in order to evaluate the output whenever
/// a new input arrives.
struct YNodeState {
    left: Vec<Partial>,
    right: Vec<Automation>,
    yysends: Vec<YYSend>,
}

struct OutputState {
    node: Rc<YNode>,
    renderer: PartialRenderer,
}

struct TreeRenderer {
    render_spec: RenderSpec,
    anode_states: HashMap<Rc<ANode>, ANodeState>,
    ynode_states: HashMap<Rc<YNode>, YNodeState>,
    outputs: Vec<OutputState>,
    // In order to return a slice from the step() function, we need to allocate
    // some buffer space
    output_buff: Vec<f32>,
}

impl TreeRenderer {
    pub fn new(render_spec: RenderSpec) -> TreeRenderer {
        TreeRenderer{
            render_spec: render_spec,
            anode_states: HashMap::new(),
            ynode_states: HashMap::new(),
            outputs: vec![],
            output_buff: vec![],
        }
    }
    /// Get the ANodeState associated with a node,
    /// and create it if it doesn't already exist.
    fn get_anode_state(&mut self, node: &Rc<ANode>) -> &mut ANodeState {
        self.anode_states.entry(node.clone()).or_insert_with(|| ANodeState::new())
    }
    /// Get the YNodeState associated with a node,
    /// and create it if it doesn't already exist.
    fn get_ynode_state(&mut self, node: &Rc<YNode>) -> &mut YNodeState {
        self.ynode_states.entry(node.clone()).or_insert_with(|| YNodeState::new())
    }
    /// Send a partial to the input of any nodes connected to the output of the
    /// given node.
    fn broadcast_partial(&mut self, from: &Rc<YNode>, partial: Partial) {
        // need to clone the State's sends to avoid mutability problems
        let sends = self.get_ynode_state(from).yysends.clone();
        for ref send in sends.iter() {
            self.ynode_input_left(send.dest(), partial);
        }
    }
    /// Send an Automation to the input of any nodes connected to the output of
    /// the given node.
    fn broadcast_autom(&mut self, from: &Rc<ANode>, autom: Automation) {
        // need to clone the State's sends to avoid mutability problems
        let aasends = self.get_anode_state(from).aasends.clone();
        let aysends = self.get_anode_state(from).aysends.clone();
        // send automation input to the YNodes:
        for ref send in aysends.iter() {
            self.ynode_input_right(send.dest(), autom);
        }
        // send the automation to the other ANodes:
        for ref send in aasends.iter() {
            self.anode_input(send.dest(), send.dest_slot(), autom);
        }
    }
    /// Add a partial to the YNode's left slot
    fn ynode_input_left(&mut self, node: &Rc<YNode>, partial: Partial) {
        let right;
        {
            let mut state = self.get_ynode_state(node);
            state.left.push(partial);
            // need to clone the State's right-hand-side to avoid mut issues
            right = state.right.clone();
        }
        // compute any new outputs & broadcast them.
        for autom in right.iter() {
            self.broadcast_partial(node, autom.apply_to_partial(partial));
        }
    }
    fn ynode_input_right(&mut self, node: &Rc<YNode>, autom: Automation) {
        let left;
        {
            let mut state = self.get_ynode_state(node);
            state.right.push(autom);
            // need to clone the State's left-hand-side to avoid mut issues
            left = state.left.clone();
        }
        // compute any new outputs & broadcast them.
        for partial in left.iter() {
            self.broadcast_partial(node, autom.apply_to_partial(*partial));
        }
    }
    fn anode_input(&mut self, node: &Rc<ANode>, slot: NodeInputSlot,
      autom: Automation) {
        match slot {
            NodeInputSlot::Left => {
                let right;
                {
                    let mut state = self.get_anode_state(node);
                    state.left.push(autom);
                    right = state.right.clone();
                }
                // all the automations in the right bin affect the new autom
                for autom_right in right.iter() {
                    self.broadcast_autom(node, autom_right.apply_to_autom(autom));
                }
            },
            NodeInputSlot::Right => {
                let left;
                {
                    let mut state = self.get_anode_state(node);
                    state.right.push(autom);
                    left = state.left.clone();
                }
                // this new autom affects all automations in the left bin
                for autom_left in left.iter() {
                    self.broadcast_autom(node, autom.apply_to_autom(*autom_left));
                }
            },
        };
    }
}

impl Tree for TreeRenderer {
    /// Connect two nodes in the tree.
    /// If the send is ASrcSend / YSrcSend, this is the same as feeding
    /// external stimuli into the tree.
    fn add_send(&mut self, send: Send) {
        match send {
            Send::AASend(send) => {
                self.get_anode_state(send.src()).add_aasend(send);
            },
            Send::AYSend(send) => {
                self.get_anode_state(send.src()).add_aysend(send);
            },
            Send::YYSend(send) => {
                self.get_ynode_state(send.src()).add_yysend(send);
            },
            Send::ASrcSend(send) => {
                self.broadcast_autom(send.dest(), *send.src());
            },
            Send::YSrcSend(send) => {
                self.broadcast_partial(send.dest(), *send.src());
            },
        }
    }

    /// set the nodes for which we are interested in the output PCM signals.
    /// Future calls to `step()` will return an array of samples corresponding
    /// to these nodes.
    fn watch_nodes(&mut self, outputs: &[Rc<YNode>]) {
        self.outputs = outputs.iter().map(|node|
            OutputState::new(self.render_spec.clone(), node.clone())
        ).collect();
    }
    /// Return the next buffer of samples related to the watched nodes.
    fn step(&mut self) -> &[f32] {
        // Todo: Make use of `Vec::resize once stabilized (Projected for Rust 1.5)
        self.output_buff = self.outputs.iter_mut().map(
            |output| output.step()
        ).collect();
        &self.output_buff
    }
}

impl ANodeState {
    fn new() -> ANodeState {
        ANodeState{ left:vec![], right: vec![], aasends: vec![], aysends:vec![] }
    }
    fn add_aasend(&mut self, send: AASend) {
        self.aasends.push(send);
    }
    fn add_aysend(&mut self, send: AYSend) {
        self.aysends.push(send);
    }
}

impl YNodeState {
    fn new() -> YNodeState {
        YNodeState{ left:vec![], right: vec![], yysends: vec![] }
    }
    fn add_yysend(&mut self, send: YYSend) {
        self.yysends.push(send);
    }
}

impl OutputState {
    fn new(spec: RenderSpec, node: Rc<YNode>) -> OutputState {
        OutputState{ node: node, renderer: PartialRenderer::new(spec) }
    }
    fn node(&self) -> &Rc<YNode> {
        &self.node
    }
    fn step(&mut self) -> f32 {
        self.renderer.step()
    }
}

<commit_msg>Feed partials on to the PartialRenderers, when appropriate [Rendering complete?]<commit_after>use std::collections::hash_map::HashMap;
use std::rc::Rc;

use automation::Automation;
use partial::Partial;
use tree::node::{ANode, NodeInputSlot, YNode};
use tree::send::{AASend, AYSend, Send, YYSend};
use tree::tree::Tree;

use render::render_spec::RenderSpec;

use super::partial_renderer::PartialRenderer;

/// Tracks all the partials/automations that have ever entered the node.
/// This information is needed in order to evaluate the output whenever
/// a new input arrives.
struct ANodeState {
    left: Vec<Automation>,
    right: Vec<Automation>,
    aasends: Vec<AASend>,
    aysends: Vec<AYSend>,
}

/// Tracks all the partials/automations that have ever entered the node.
/// This information is needed in order to evaluate the output whenever
/// a new input arrives.
struct YNodeState {
    left: Vec<Partial>,
    right: Vec<Automation>,
    yysends: Vec<YYSend>,
}

struct OutputState {
    node: Rc<YNode>,
    renderer: PartialRenderer,
}

struct TreeRenderer {
    render_spec: RenderSpec,
    anode_states: HashMap<Rc<ANode>, ANodeState>,
    ynode_states: HashMap<Rc<YNode>, YNodeState>,
    outputs: Vec<OutputState>,
    // In order to return a slice from the step() function, we need to allocate
    // some buffer space
    output_buff: Vec<f32>,
}

impl TreeRenderer {
    pub fn new(render_spec: RenderSpec) -> TreeRenderer {
        TreeRenderer{
            render_spec: render_spec,
            anode_states: HashMap::new(),
            ynode_states: HashMap::new(),
            outputs: vec![],
            output_buff: vec![],
        }
    }
    /// Get the ANodeState associated with a node,
    /// and create it if it doesn't already exist.
    fn get_anode_state(&mut self, node: &Rc<ANode>) -> &mut ANodeState {
        self.anode_states.entry(node.clone()).or_insert_with(|| ANodeState::new())
    }
    /// Get the YNodeState associated with a node,
    /// and create it if it doesn't already exist.
    fn get_ynode_state(&mut self, node: &Rc<YNode>) -> &mut YNodeState {
        self.ynode_states.entry(node.clone()).or_insert_with(|| YNodeState::new())
    }
    /// Send a partial to the input of any nodes connected to the output of the
    /// given node.
    fn broadcast_partial(&mut self, from: &Rc<YNode>, partial: Partial) {
        // need to clone the State's sends to avoid mutability problems
        let sends = self.get_ynode_state(from).yysends.clone();
        for ref send in sends.iter() {
            self.ynode_input_left(send.dest(), partial);
        }
        // If we are operating on an output node, send this to the PartialRenderer
        if let Some(output) =
            self.outputs.iter_mut().find(|output_state|
                output_state.node() == from
            ) {
            output.feed(partial);
        }
    }
    /// Send an Automation to the input of any nodes connected to the output of
    /// the given node.
    fn broadcast_autom(&mut self, from: &Rc<ANode>, autom: Automation) {
        // need to clone the State's sends to avoid mutability problems
        let aasends = self.get_anode_state(from).aasends.clone();
        let aysends = self.get_anode_state(from).aysends.clone();
        // send automation input to the YNodes:
        for ref send in aysends.iter() {
            self.ynode_input_right(send.dest(), autom);
        }
        // send the automation to the other ANodes:
        for ref send in aasends.iter() {
            self.anode_input(send.dest(), send.dest_slot(), autom);
        }
    }
    /// Add a partial to the YNode's left slot
    fn ynode_input_left(&mut self, node: &Rc<YNode>, partial: Partial) {
        let right;
        {
            let mut state = self.get_ynode_state(node);
            state.left.push(partial);
            // need to clone the State's right-hand-side to avoid mut issues
            right = state.right.clone();
        }
        // compute any new outputs & broadcast them.
        for autom in right.iter() {
            self.broadcast_partial(node, autom.apply_to_partial(partial));
        }
    }
    fn ynode_input_right(&mut self, node: &Rc<YNode>, autom: Automation) {
        let left;
        {
            let mut state = self.get_ynode_state(node);
            state.right.push(autom);
            // need to clone the State's left-hand-side to avoid mut issues
            left = state.left.clone();
        }
        // compute any new outputs & broadcast them.
        for partial in left.iter() {
            self.broadcast_partial(node, autom.apply_to_partial(*partial));
        }
    }
    fn anode_input(&mut self, node: &Rc<ANode>, slot: NodeInputSlot,
      autom: Automation) {
        match slot {
            NodeInputSlot::Left => {
                let right;
                {
                    let mut state = self.get_anode_state(node);
                    state.left.push(autom);
                    right = state.right.clone();
                }
                // all the automations in the right bin affect the new autom
                for autom_right in right.iter() {
                    self.broadcast_autom(node, autom_right.apply_to_autom(autom));
                }
            },
            NodeInputSlot::Right => {
                let left;
                {
                    let mut state = self.get_anode_state(node);
                    state.right.push(autom);
                    left = state.left.clone();
                }
                // this new autom affects all automations in the left bin
                for autom_left in left.iter() {
                    self.broadcast_autom(node, autom.apply_to_autom(*autom_left));
                }
            },
        };
    }
}

impl Tree for TreeRenderer {
    /// Connect two nodes in the tree.
    /// If the send is ASrcSend / YSrcSend, this is the same as feeding
    /// external stimuli into the tree.
    fn add_send(&mut self, send: Send) {
        match send {
            Send::AASend(send) => {
                self.get_anode_state(send.src()).add_aasend(send);
            },
            Send::AYSend(send) => {
                self.get_anode_state(send.src()).add_aysend(send);
            },
            Send::YYSend(send) => {
                self.get_ynode_state(send.src()).add_yysend(send);
            },
            Send::ASrcSend(send) => {
                self.broadcast_autom(send.dest(), *send.src());
            },
            Send::YSrcSend(send) => {
                self.broadcast_partial(send.dest(), *send.src());
            },
        }
    }

    /// set the nodes for which we are interested in the output PCM signals.
    /// Future calls to `step()` will return an array of samples corresponding
    /// to these nodes.
    fn watch_nodes(&mut self, outputs: &[Rc<YNode>]) {
        self.outputs = outputs.iter().map(|node|
            OutputState::new(self.render_spec.clone(), node.clone())
        ).collect();
    }
    /// Return the next buffer of samples related to the watched nodes.
    fn step(&mut self) -> &[f32] {
        // Todo: Make use of `Vec::resize once stabilized (Projected for Rust 1.5)
        self.output_buff = self.outputs.iter_mut().map(
            |output| output.step()
        ).collect();
        &self.output_buff
    }
}

impl ANodeState {
    fn new() -> ANodeState {
        ANodeState{ left:vec![], right: vec![], aasends: vec![], aysends:vec![] }
    }
    fn add_aasend(&mut self, send: AASend) {
        self.aasends.push(send);
    }
    fn add_aysend(&mut self, send: AYSend) {
        self.aysends.push(send);
    }
}

impl YNodeState {
    fn new() -> YNodeState {
        YNodeState{ left:vec![], right: vec![], yysends: vec![] }
    }
    fn add_yysend(&mut self, send: YYSend) {
        self.yysends.push(send);
    }
}

impl OutputState {
    fn new(spec: RenderSpec, node: Rc<YNode>) -> OutputState {
        OutputState{ node: node, renderer: PartialRenderer::new(spec) }
    }
    fn node(&self) -> &Rc<YNode> {
        &self.node
    }
    fn step(&mut self) -> f32 {
        self.renderer.step()
    }
    fn feed(&mut self, partial: Partial) {
        self.renderer.feed(partial);
    }
}

<|endoftext|>


<commit_before>//! Shim which is passed to Cargo as "rustc" when running the bootstrap.
//!
//! This shim will take care of some various tasks that our build process
//! requires that Cargo can't quite do through normal configuration:
//!
//! 1. When compiling build scripts and build dependencies, we need a guaranteed
//!    full standard library available. The only compiler which actually has
//!    this is the snapshot, so we detect this situation and always compile with
//!    the snapshot compiler.
//! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling
//!    (and this slightly differs based on a whether we're using a snapshot or
//!    not), so we do that all here.
//!
//! This may one day be replaced by RUSTFLAGS, but the dynamic nature of
//! switching compilers for the bootstrap and for build scripts will probably
//! never get replaced.

use std::env;
use std::io;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::time::Instant;

fn main() {
    let args = env::args_os().skip(1).collect::<Vec<_>>();

    // Detect whether or not we're a build script depending on whether --target
    // is passed (a bit janky...)
    let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
    let version = args.iter().find(|w| &**w == "-vV");

    let verbose = match env::var("RUSTC_VERBOSE") {
        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
        Err(_) => 0,
    };

    // Use a different compiler for build scripts, since there may not yet be a
    // libstd for the real compiler to use. However, if Cargo is attempting to
    // determine the version of the compiler, the real compiler needs to be
    // used. Currently, these two states are differentiated based on whether
    // --target and -vV is/isn't passed.
    let (rustc, libdir) = if target.is_none() && version.is_none() {
        ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
    } else {
        ("RUSTC_REAL", "RUSTC_LIBDIR")
    };
    let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
    let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
    let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);

    let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
    let mut dylib_path = bootstrap::util::dylib_path();
    dylib_path.insert(0, PathBuf::from(&libdir));

    let mut cmd = Command::new(rustc);
    cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());

    // Get the name of the crate we're compiling, if any.
    let crate_name =
        args.windows(2).find(|args| args[0] == "--crate-name").and_then(|args| args[1].to_str());

    if let Some(crate_name) = crate_name {
        if let Some(target) = env::var_os("RUSTC_TIME") {
            if target == "all"
                || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
            {
                cmd.arg("-Ztime");
            }
        }
    }

    // Print backtrace in case of ICE
    if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
        cmd.env("RUST_BACKTRACE", "1");
    }

    if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") {
        cmd.args(lint_flags.split_whitespace());
    }

    if target.is_some() {
        // The stage0 compiler has a special sysroot distinct from what we
        // actually downloaded, so we just always pass the `--sysroot` option,
        // unless one is already set.
        if !args.iter().any(|arg| arg == "--sysroot") {
            cmd.arg("--sysroot").arg(&sysroot);
        }

        // If we're compiling specifically the `panic_abort` crate then we pass
        // the `-C panic=abort` option. Note that we do not do this for any
        // other crate intentionally as this is the only crate for now that we
        // ship with panic=abort.
        //
        // This... is a bit of a hack how we detect this. Ideally this
        // information should be encoded in the crate I guess? Would likely
        // require an RFC amendment to RFC 1513, however.
        //
        // `compiler_builtins` are unconditionally compiled with panic=abort to
        // workaround undefined references to `rust_eh_unwind_resume` generated
        // otherwise, see issue https://github.com/rust-lang/rust/issues/43095.
        if crate_name == Some("panic_abort")
            || crate_name == Some("compiler_builtins") && stage != "0"
        {
            cmd.arg("-C").arg("panic=abort");
        }
    } else {
        // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
        // here, but rather Cargo should know what flags to pass rustc itself.

        // Override linker if necessary.
        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
            cmd.arg(format!("-Clinker={}", host_linker));
        }

        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
            if s == "true" {
                cmd.arg("-C").arg("target-feature=+crt-static");
            }
            if s == "false" {
                cmd.arg("-C").arg("target-feature=-crt-static");
            }
        }
    }

    if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
        cmd.arg("--remap-path-prefix").arg(&map);
    }

    // Force all crates compiled by this compiler to (a) be unstable and (b)
    // allow the `rustc_private` feature to link to other unstable crates
    // also in the sysroot. We also do this for host crates, since those
    // may be proc macros, in which case we might ship them.
    if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) {
        cmd.arg("-Z").arg("force-unstable-if-unmarked");
    }

    if verbose > 1 {
        eprintln!(
            "rustc command: {:?}={:?} {:?}",
            bootstrap::util::dylib_path_var(),
            env::join_paths(&dylib_path).unwrap(),
            cmd,
        );
        eprintln!("sysroot: {:?}", sysroot);
        eprintln!("libdir: {:?}", libdir);
    }

    if let Some(mut on_fail) = on_fail {
        let e = match cmd.status() {
            Ok(s) if s.success() => std::process::exit(0),
            e => e,
        };
        println!("\nDid not run successfully: {:?}\n{:?}\n-------------", e, cmd);
        exec_cmd(&mut on_fail).expect("could not run the backup command");
        std::process::exit(1);
    }

    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some() {
        if let Some(crate_name) = crate_name {
            let start = Instant::now();
            let status = cmd.status().unwrap_or_else(|_| panic!("\n\n failed to run {:?}", cmd));
            let dur = start.elapsed();

            let is_test = args.iter().any(|a| a == "--test");
            eprintln!(
                "[RUSTC-TIMING] {} test:{} {}.{:03}",
                crate_name,
                is_test,
                dur.as_secs(),
                dur.subsec_millis()
            );

            match status.code() {
                Some(i) => std::process::exit(i),
                None => {
                    eprintln!("rustc exited with {}", status);
                    std::process::exit(0xfe);
                }
            }
        }
    }

    let code = exec_cmd(&mut cmd).unwrap_or_else(|_| panic!("\n\n failed to run {:?}", cmd));
    std::process::exit(code);
}

#[cfg(unix)]
fn exec_cmd(cmd: &mut Command) -> io::Result<i32> {
    use std::os::unix::process::CommandExt;
    Err(cmd.exec())
}

#[cfg(not(unix))]
fn exec_cmd(cmd: &mut Command) -> io::Result<i32> {
    cmd.status().map(|status| status.code().unwrap())
}
<commit_msg>rustbuild: fix bad usage of UNIX exec() in rustc wrapper<commit_after>//! Shim which is passed to Cargo as "rustc" when running the bootstrap.
//!
//! This shim will take care of some various tasks that our build process
//! requires that Cargo can't quite do through normal configuration:
//!
//! 1. When compiling build scripts and build dependencies, we need a guaranteed
//!    full standard library available. The only compiler which actually has
//!    this is the snapshot, so we detect this situation and always compile with
//!    the snapshot compiler.
//! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling
//!    (and this slightly differs based on a whether we're using a snapshot or
//!    not), so we do that all here.
//!
//! This may one day be replaced by RUSTFLAGS, but the dynamic nature of
//! switching compilers for the bootstrap and for build scripts will probably
//! never get replaced.

use std::env;
use std::io;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::time::Instant;

fn main() {
    let args = env::args_os().skip(1).collect::<Vec<_>>();

    // Detect whether or not we're a build script depending on whether --target
    // is passed (a bit janky...)
    let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
    let version = args.iter().find(|w| &**w == "-vV");

    let verbose = match env::var("RUSTC_VERBOSE") {
        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
        Err(_) => 0,
    };

    // Use a different compiler for build scripts, since there may not yet be a
    // libstd for the real compiler to use. However, if Cargo is attempting to
    // determine the version of the compiler, the real compiler needs to be
    // used. Currently, these two states are differentiated based on whether
    // --target and -vV is/isn't passed.
    let (rustc, libdir) = if target.is_none() && version.is_none() {
        ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
    } else {
        ("RUSTC_REAL", "RUSTC_LIBDIR")
    };
    let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
    let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
    let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);

    let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
    let mut dylib_path = bootstrap::util::dylib_path();
    dylib_path.insert(0, PathBuf::from(&libdir));

    let mut cmd = Command::new(rustc);
    cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());

    // Get the name of the crate we're compiling, if any.
    let crate_name =
        args.windows(2).find(|args| args[0] == "--crate-name").and_then(|args| args[1].to_str());

    if let Some(crate_name) = crate_name {
        if let Some(target) = env::var_os("RUSTC_TIME") {
            if target == "all"
                || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
            {
                cmd.arg("-Ztime");
            }
        }
    }

    // Print backtrace in case of ICE
    if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
        cmd.env("RUST_BACKTRACE", "1");
    }

    if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") {
        cmd.args(lint_flags.split_whitespace());
    }

    if target.is_some() {
        // The stage0 compiler has a special sysroot distinct from what we
        // actually downloaded, so we just always pass the `--sysroot` option,
        // unless one is already set.
        if !args.iter().any(|arg| arg == "--sysroot") {
            cmd.arg("--sysroot").arg(&sysroot);
        }

        // If we're compiling specifically the `panic_abort` crate then we pass
        // the `-C panic=abort` option. Note that we do not do this for any
        // other crate intentionally as this is the only crate for now that we
        // ship with panic=abort.
        //
        // This... is a bit of a hack how we detect this. Ideally this
        // information should be encoded in the crate I guess? Would likely
        // require an RFC amendment to RFC 1513, however.
        //
        // `compiler_builtins` are unconditionally compiled with panic=abort to
        // workaround undefined references to `rust_eh_unwind_resume` generated
        // otherwise, see issue https://github.com/rust-lang/rust/issues/43095.
        if crate_name == Some("panic_abort")
            || crate_name == Some("compiler_builtins") && stage != "0"
        {
            cmd.arg("-C").arg("panic=abort");
        }
    } else {
        // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
        // here, but rather Cargo should know what flags to pass rustc itself.

        // Override linker if necessary.
        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
            cmd.arg(format!("-Clinker={}", host_linker));
        }

        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
            if s == "true" {
                cmd.arg("-C").arg("target-feature=+crt-static");
            }
            if s == "false" {
                cmd.arg("-C").arg("target-feature=-crt-static");
            }
        }
    }

    if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
        cmd.arg("--remap-path-prefix").arg(&map);
    }

    // Force all crates compiled by this compiler to (a) be unstable and (b)
    // allow the `rustc_private` feature to link to other unstable crates
    // also in the sysroot. We also do this for host crates, since those
    // may be proc macros, in which case we might ship them.
    if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) {
        cmd.arg("-Z").arg("force-unstable-if-unmarked");
    }

    if verbose > 1 {
        eprintln!(
            "rustc command: {:?}={:?} {:?}",
            bootstrap::util::dylib_path_var(),
            env::join_paths(&dylib_path).unwrap(),
            cmd,
        );
        eprintln!("sysroot: {:?}", sysroot);
        eprintln!("libdir: {:?}", libdir);
    }

    if let Some(mut on_fail) = on_fail {
        let e = match cmd.status() {
            Ok(s) if s.success() => std::process::exit(0),
            e => e,
        };
        println!("\nDid not run successfully: {:?}\n{:?}\n-------------", e, cmd);
        exec_cmd(&mut on_fail).expect("could not run the backup command");
        std::process::exit(1);
    }

    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some() {
        if let Some(crate_name) = crate_name {
            let start = Instant::now();
            let status = cmd.status().unwrap_or_else(|_| panic!("\n\n failed to run {:?}", cmd));
            let dur = start.elapsed();

            let is_test = args.iter().any(|a| a == "--test");
            eprintln!(
                "[RUSTC-TIMING] {} test:{} {}.{:03}",
                crate_name,
                is_test,
                dur.as_secs(),
                dur.subsec_millis()
            );

            match status.code() {
                Some(i) => std::process::exit(i),
                None => {
                    eprintln!("rustc exited with {}", status);
                    std::process::exit(0xfe);
                }
            }
        }
    }

    let code = exec_cmd(&mut cmd).unwrap_or_else(|_| panic!("\n\n failed to run {:?}", cmd));
    std::process::exit(code);
}

fn exec_cmd(cmd: &mut Command) -> io::Result<i32> {
    cmd.status().map(|status| status.code().unwrap())
}
<|endoftext|>