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

//! A Doug Lea-style concurrent hash map using striped locks.

use rand;
use rand::Rng;
use std::cast;
use std::hash::{Hash, sip};
use std::ptr;
use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
use std::unstable::mutex::StaticNativeMutex;
use std::mem;
use std::slice;

/// When the size exceeds (number of buckets * LOAD_NUMERATOR/LOAD_DENOMINATOR), the hash table
/// grows.
static LOAD_NUMERATOR: uint = 3;

/// When the size exceeds (number of buckets * LOAD_NUMERATOR/LOAD_DENOMINATOR), the hash table
/// grows.
static LOAD_DENOMINATOR: uint = 4;

/// One bucket in the hash table.
struct Bucket<K,V> {
    next: Option<~Bucket<K,V>>,
    key: K,
    value: V,
}

/// A concurrent hash map using striped locks.
pub struct ConcurrentHashMap<K,V> {
    /// The first secret key value.
    k0: u64,
    /// The second key value.
    k1: u64,
    /// The number of elements in this hash table.
    size: AtomicUint,
    /// The striped locks.
    locks: ~[StaticNativeMutex],
    /// The buckets.
    buckets: ~[Option<Bucket<K,V>>],
}

impl<K:Hash + Eq,V> ConcurrentHashMap<K,V> {
    /// Creates a hash map with 16 locks and 4 buckets per lock.
    pub fn new() -> ConcurrentHashMap<K,V> {
        ConcurrentHashMap::with_locks_and_buckets(16, 4)
    }

    /// Creates a hash map with the given number of locks and buckets per lock.
    pub fn with_locks_and_buckets(lock_count: uint, buckets_per_lock: uint)
                                  -> ConcurrentHashMap<K,V> {
        let mut rand = rand::task_rng();
        ConcurrentHashMap {
            k0: rand.gen(),
            k1: rand.gen(),
            size: AtomicUint::new(0),
            locks: slice::from_fn(lock_count, |_| {
                unsafe {
                    StaticNativeMutex::new()
                }
            }),
            buckets: slice::from_fn(lock_count * buckets_per_lock, |_| None),
        }
    }

    /// Inserts the given value into the hash table, replacing the value with the previous value
    /// if any.
    pub fn insert(&self, key: K, value: V) {
        unsafe {
            let this: &mut ConcurrentHashMap<K,V> = cast::transmute_mut(self);

            loop {
                let (bucket_index, lock_index) = self.bucket_and_lock_indices(&key);
                if this.overloaded() {
                    this.locks[lock_index].unlock_noguard();
                    this.try_resize(self.buckets_per_lock() * 2);

                    // Have to retry because the bucket and lock indices will have shifted.
                    continue
                }

                this.insert_unlocked(key, value, Some(bucket_index));
                this.locks[lock_index].unlock_noguard();
                break
            }
        }
    }

    #[inline(always)]
    unsafe fn insert_unlocked(&self, key: K, value: V, opt_bucket_index: Option<uint>) {
        let this: &mut ConcurrentHashMap<K,V> = cast::transmute_mut(self);

        let bucket_index = match opt_bucket_index {
            Some(bucket_index) => bucket_index,
            None => self.bucket_index_unlocked(&key),
        };

        match this.buckets[bucket_index] {
            None => {
                this.buckets[bucket_index] = Some(Bucket {
                    next: None,
                    key: key,
                    value: value,
                });
                drop(this.size.fetch_add(1, SeqCst));
            }
            Some(ref mut bucket) => {
                // Search to try to find a value.
                let mut bucket: *mut Bucket<K,V> = bucket;
                loop {
                    if (*bucket).key == key {
                        (*bucket).value = value;
                        break
                    }

                    match (*bucket).next {
                        None => {}
                        Some(ref mut next_bucket) => {
                            bucket = &mut **next_bucket as *mut Bucket<K,V>;
                            continue
                        }
                    }

                    (*bucket).next = Some(~Bucket {
                        next: None,
                        key: key,
                        value: value,
                    });
                    drop(this.size.fetch_add(1, SeqCst));
                    break
                }
            }
        }
    }

    /// Removes the given key from the hash table.
    pub fn remove(&self, key: &K) {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self)
        };

        let (bucket_index, lock_index) = self.bucket_and_lock_indices(key);

        // Rebuild the bucket.
        let mut nuke_bucket = false;
        match this.buckets[bucket_index] {
            None => {}
            Some(ref mut bucket) if bucket.key == *key => {
                // Common case (assuming a sparse table): If the key is the first one in the
                // chain, just copy the next fields over.
                let next_opt = mem::replace(&mut bucket.next, None);
                match next_opt {
                    None => nuke_bucket = true,
                    Some(~next) => *bucket = next,
                }
                drop(this.size.fetch_sub(1, SeqCst))
            }
            Some(ref mut bucket) => {
                // Rarer case: If the key is elsewhere in the chain (or nowhere), then search for
                // it and just stitch up pointers.
                let mut prev: *mut Bucket<K,V> = bucket;
                unsafe {
                    loop {
                        match (*prev).next {
                            None => break,  // Not found.
                            Some(ref mut bucket) => {
                                // Continue the search.
                                if bucket.key != *key {
                                    prev = &mut **bucket as *mut Bucket<K,V>;
                                    continue
                                }
                            }
                        }

                        // If we got here, then we found the key. Now do a pointer stitch.
                        let ~Bucket {
                            next: next_next,
                            ..
                        } = (*prev).next.take_unwrap();
                        (*prev).next = next_next;
                        drop(this.size.fetch_sub(1, SeqCst));
                        break
                    }
                }
            }
        }
        if nuke_bucket {
            this.buckets[bucket_index] = None
        }

        unsafe {
            this.locks[lock_index].unlock_noguard()
        }
    }

    /// Returns an iterator over this concurrent map.
    pub fn iter<'a>(&'a self) -> ConcurrentHashMapIterator<'a,K,V> {
        ConcurrentHashMapIterator {
            map: self,
            bucket_index: -1,
            current_bucket: ptr::null(),
        }
    }

    /// Returns true if the given key is in the map and false otherwise.
    pub fn contains_key(&self, key: &K) -> bool {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self)
        };

        let (bucket_index, lock_index) = this.bucket_and_lock_indices(key);

        let result;
        match this.buckets[bucket_index] {
            None => result = false,
            Some(ref bucket) => {
                // Search to try to find a value.
                let mut bucket = bucket;
                loop {
                    if bucket.key == *key {
                        result = true;
                        break
                    }
                    match bucket.next {
                        None => {
                            result = false;
                            break
                        }
                        Some(ref next_bucket) => bucket = &**next_bucket,
                    }
                }
            }
        }

        unsafe {
            this.locks[lock_index].unlock_noguard()
        }

        result
    }

    /// Removes all entries from the map.
    pub fn clear(&self) {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self)
        };

        let (bucket_count, lock_count) = (this.buckets.len(), this.locks.len());
        let buckets_per_lock = bucket_count / lock_count;

        let (mut lock_index, mut stripe_index) = (0, 0);
        for bucket in this.buckets.mut_iter() {
            stripe_index += 1;
            if stripe_index == buckets_per_lock {
                unsafe {
                    this.locks[lock_index].unlock_noguard();
                }

                stripe_index = 0;
                lock_index += 1
            }
            if stripe_index == 0 {
                unsafe {
                    this.locks[lock_index].lock_noguard()
                }
            }

            *bucket = None
        }
    }

    /// Resizes the map to a new size. Takes all the locks (i.e. acquires an exclusive lock on the
    /// entire table) as it does so.
    ///
    /// This has no problem with invalidating iterators because iterators always hold onto at least
    /// one lock.
    fn try_resize(&self, new_buckets_per_lock: uint) {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self)
        };

        // Take a lock on all buckets.
        for lock in this.locks.mut_iter() {
            unsafe {
                lock.lock_noguard()
            }
        }

        // Check to make sure we aren't already at the right size. Someone else could have already
        // resized.
        let lock_count = this.locks.len();
        let new_bucket_count = lock_count * new_buckets_per_lock;
        if new_bucket_count > this.buckets.len() {
            // Create a new set of buckets.
            let mut buckets = slice::from_fn(new_bucket_count, |_| None);
            mem::swap(&mut this.buckets, &mut buckets);
            this.size.store(0, Relaxed);

            // Go through all the old buckets and insert the new data.
            for bucket in buckets.move_iter() {
                match bucket {
                    None => continue,
                    Some(Bucket {
                        key: key,
                        value: value,
                        next: mut bucket
                    }) => {
                        unsafe {
                            this.insert_unlocked(key, value, None)
                        }

                        loop {
                            match bucket {
                                None => break,
                                Some(~Bucket {
                                    key: key,
                                    value: value,
                                    next: next
                                }) => {
                                    unsafe {
                                        this.insert_unlocked(key, value, None)
                                    }

                                    bucket = next
                                }
                            }
                        }
                    }
                }
            }
        }

        // Release all our locks.
        for lock in this.locks.mut_iter() {
            unsafe {
                lock.unlock_noguard()
            }
        }
    }

    /// Returns the index of the bucket and the lock for the given key, respectively, taking the
    /// appropriate lock before returning. This is subtle: it contains a loop to deal with race
    /// conditions in which the bucket array might have resized.
    #[inline]
    fn bucket_and_lock_indices(&self, key: &K) -> (uint, uint) {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(cast::transmute_region(self))
        };

        let hash = sip::hash_with_keys(self.k0, self.k1, key);
        let lock_count = this.locks.len();
        let mut bucket_index;
        let mut lock_index;
        loop {
            let bucket_count = this.buckets.len();
            let buckets_per_lock = bucket_count / lock_count;
            bucket_index = hash as uint % bucket_count;
            lock_index = bucket_index / buckets_per_lock;
            unsafe {
                this.locks[lock_index].lock_noguard();
            }
            let new_bucket_count = this.buckets.len();
            if bucket_count == new_bucket_count {
                break
            }

            // If we got here, the hash table resized from under us: try again.
            unsafe {
                this.locks[lock_index].unlock_noguard()
            }
        }

        (bucket_index, lock_index)
    }

    /// Returns the index of the bucket. You must be holding at least one lock to call this
    /// function!
    #[inline]
    unsafe fn bucket_index_unlocked(&self, key: &K) -> uint {
        let hash = sip::hash_with_keys(self.k0, self.k1, key);
        hash as uint % self.buckets.len()
    }

    /// Returns true if this hash table is overloaded (at its current load factor, default 0.75)
    /// and false otherwise.
    #[inline]
    fn overloaded(&self) -> bool {
        self.size.load(SeqCst) >= (self.buckets.len() * LOAD_NUMERATOR / LOAD_DENOMINATOR)
    }

    /// Returns the number of buckets per lock.
    #[inline]
    fn buckets_per_lock(&self) -> uint {
        self.buckets.len() / self.locks.len()
    }

    /// Returns the number of elements in the hash table.
    #[inline]
    pub fn size(&self) -> uint {
        self.size.load(SeqCst)
    }
}

pub struct ConcurrentHashMapIterator<'a,K,V> {
    map: &'a ConcurrentHashMap<K,V>,
    bucket_index: int,
    current_bucket: *Bucket<K,V>,
}

impl<'a,K,V> Iterator<(&'a K, &'a V)> for ConcurrentHashMapIterator<'a,K,V> {
    fn next(&mut self) -> Option<(&'a K, &'a V)> {
        let map: &'a mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self.map)
        };

        let (bucket_count, lock_count) = (map.buckets.len(), map.locks.len());
        let buckets_per_lock = bucket_count / lock_count;

        // Go to the next bucket in the chain, if necessary.
        if self.current_bucket != ptr::null() {
            unsafe {
                self.current_bucket = match (*self.current_bucket).next {
                    None => ptr::null(),
                    Some(ref bucket) => {
                        let bucket: *Bucket<K,V> = &**bucket;
                        bucket
                    }
                }
            }
        }

        // Advance buckets, taking locks along the way if necessary.
        while self.current_bucket == ptr::null() {
            let bucket_index = self.bucket_index;
            let lock_index = if bucket_index < 0 {
                -1
            } else {
                bucket_index / (buckets_per_lock as int)
            };

            if bucket_index < 0 ||
                    bucket_index % (buckets_per_lock as int) == (buckets_per_lock as int) - 1 {
                // We're at the boundary between one lock and another. Drop the old lock if
                // necessary and acquire the new one, if necessary.
                if bucket_index != -1 {
                    unsafe {
                        map.locks[lock_index as uint].unlock_noguard()
                    }
                }
                if bucket_index != (bucket_count as int) - 1 {
                    unsafe {
                        map.locks[(lock_index + 1) as uint].lock_noguard()
                    }
                }
            }

            // If at end, return None.
            if self.bucket_index == (bucket_count as int) - 1 {
                return None
            }

            self.bucket_index += 1;

            self.current_bucket = match map.buckets[self.bucket_index as uint] {
                None => ptr::null(),
                Some(ref bucket) => {
                    let bucket: *Bucket<K,V> = bucket;
                    bucket
                }
            }
        }

        unsafe {
            Some((cast::transmute(&(*self.current_bucket).key),
                  cast::transmute(&(*self.current_bucket).value)))
        }
    }
}

#[cfg(test)]
pub mod test {
    use sync::Arc;
    use native;
    use std::comm;

    use concurrentmap::ConcurrentHashMap;

    #[test]
    pub fn smoke() {
        let m = Arc::new(ConcurrentHashMap::new());
        let (chan, port) = comm::channel();

        // Big enough to make it resize once.
        for i in range(0, 5) {
            let m = m.clone();
            let chan = chan.clone();
            native::task::spawn(proc() {
                for j in range(i * 20, (i * 20) + 20) {
                    m.insert(j, j * j);
                }
                chan.send(());
            })
        }
        for _ in range(0, 5) {
            port.recv();
        }

        let mut count = 0;
        for (&k, &v) in m.iter() {
            assert_eq!(k * k, v)
            count += 1;
        }
        assert_eq!(count, 100)
    }
}

<commit_msg>Use Vec in concurrentmap.rs.<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/. */

//! A Doug Lea-style concurrent hash map using striped locks.

use rand;
use rand::Rng;
use std::cast;
use std::hash::{Hash, sip};
use std::ptr;
use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
use std::unstable::mutex::StaticNativeMutex;
use std::mem;

/// When the size exceeds (number of buckets * LOAD_NUMERATOR/LOAD_DENOMINATOR), the hash table
/// grows.
static LOAD_NUMERATOR: uint = 3;

/// When the size exceeds (number of buckets * LOAD_NUMERATOR/LOAD_DENOMINATOR), the hash table
/// grows.
static LOAD_DENOMINATOR: uint = 4;

/// One bucket in the hash table.
struct Bucket<K,V> {
    next: Option<~Bucket<K,V>>,
    key: K,
    value: V,
}

/// A concurrent hash map using striped locks.
pub struct ConcurrentHashMap<K,V> {
    /// The first secret key value.
    k0: u64,
    /// The second key value.
    k1: u64,
    /// The number of elements in this hash table.
    size: AtomicUint,
    /// The striped locks.
    locks: Vec<StaticNativeMutex>,
    /// The buckets.
    buckets: Vec<Option<Bucket<K,V>>>,
}

impl<K:Hash + Eq,V> ConcurrentHashMap<K,V> {
    /// Creates a hash map with 16 locks and 4 buckets per lock.
    pub fn new() -> ConcurrentHashMap<K,V> {
        ConcurrentHashMap::with_locks_and_buckets(16, 4)
    }

    /// Creates a hash map with the given number of locks and buckets per lock.
    pub fn with_locks_and_buckets(lock_count: uint, buckets_per_lock: uint)
                                  -> ConcurrentHashMap<K,V> {
        let mut rand = rand::task_rng();
        ConcurrentHashMap {
            k0: rand.gen(),
            k1: rand.gen(),
            size: AtomicUint::new(0),
            locks: Vec::from_fn(lock_count, |_| {
                unsafe {
                    StaticNativeMutex::new()
                }
            }),
            buckets: Vec::from_fn(lock_count * buckets_per_lock, |_| None),
        }
    }

    /// Inserts the given value into the hash table, replacing the value with the previous value
    /// if any.
    pub fn insert(&self, key: K, value: V) {
        unsafe {
            let this: &mut ConcurrentHashMap<K,V> = cast::transmute_mut(self);

            loop {
                let (bucket_index, lock_index) = self.bucket_and_lock_indices(&key);
                if this.overloaded() {
                    this.locks.get(lock_index).unlock_noguard();
                    this.try_resize(self.buckets_per_lock() * 2);

                    // Have to retry because the bucket and lock indices will have shifted.
                    continue
                }

                this.insert_unlocked(key, value, Some(bucket_index));
                this.locks.get(lock_index).unlock_noguard();
                break
            }
        }
    }

    #[inline(always)]
    unsafe fn insert_unlocked(&self, key: K, value: V, opt_bucket_index: Option<uint>) {
        let this: &mut ConcurrentHashMap<K,V> = cast::transmute_mut(self);

        let bucket_index = match opt_bucket_index {
            Some(bucket_index) => bucket_index,
            None => self.bucket_index_unlocked(&key),
        };

        match this.buckets.get_mut(bucket_index) {
            &None => {}
            &Some(ref mut bucket) => {
                // Search to try to find a value.
                let mut bucket: *mut Bucket<K,V> = bucket;
                loop {
                    if (*bucket).key == key {
                        (*bucket).value = value;
                        break
                    }

                    match (*bucket).next {
                        None => {}
                        Some(ref mut next_bucket) => {
                            bucket = &mut **next_bucket as *mut Bucket<K,V>;
                            continue
                        }
                    }

                    (*bucket).next = Some(~Bucket {
                        next: None,
                        key: key,
                        value: value,
                    });
                    drop(this.size.fetch_add(1, SeqCst));
                    break
                }
                return;
            }
        }
        *this.buckets.get_mut(bucket_index) = Some(Bucket {
            next: None,
            key: key,
            value: value,
        });
        drop(this.size.fetch_add(1, SeqCst));
    }

    /// Removes the given key from the hash table.
    pub fn remove(&self, key: &K) {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self)
        };

        let (bucket_index, lock_index) = self.bucket_and_lock_indices(key);

        // Rebuild the bucket.
        let mut nuke_bucket = false;
        match this.buckets.get_mut(bucket_index) {
            &None => {}
            &Some(ref mut bucket) if bucket.key == *key => {
                // Common case (assuming a sparse table): If the key is the first one in the
                // chain, just copy the next fields over.
                let next_opt = mem::replace(&mut bucket.next, None);
                match next_opt {
                    None => nuke_bucket = true,
                    Some(~next) => *bucket = next,
                }
                drop(this.size.fetch_sub(1, SeqCst))
            }
            &Some(ref mut bucket) => {
                // Rarer case: If the key is elsewhere in the chain (or nowhere), then search for
                // it and just stitch up pointers.
                let mut prev: *mut Bucket<K,V> = bucket;
                unsafe {
                    loop {
                        match (*prev).next {
                            None => break,  // Not found.
                            Some(ref mut bucket) => {
                                // Continue the search.
                                if bucket.key != *key {
                                    prev = &mut **bucket as *mut Bucket<K,V>;
                                    continue
                                }
                            }
                        }

                        // If we got here, then we found the key. Now do a pointer stitch.
                        let ~Bucket {
                            next: next_next,
                            ..
                        } = (*prev).next.take_unwrap();
                        (*prev).next = next_next;
                        drop(this.size.fetch_sub(1, SeqCst));
                        break
                    }
                }
            }
        }
        if nuke_bucket {
            *this.buckets.get_mut(bucket_index) = None
        }

        unsafe {
            this.locks.get(lock_index).unlock_noguard()
        }
    }

    /// Returns an iterator over this concurrent map.
    pub fn iter<'a>(&'a self) -> ConcurrentHashMapIterator<'a,K,V> {
        ConcurrentHashMapIterator {
            map: self,
            bucket_index: -1,
            current_bucket: ptr::null(),
        }
    }

    /// Returns true if the given key is in the map and false otherwise.
    pub fn contains_key(&self, key: &K) -> bool {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self)
        };

        let (bucket_index, lock_index) = this.bucket_and_lock_indices(key);

        let result;
        match this.buckets.get(bucket_index) {
            &None => result = false,
            &Some(ref bucket) => {
                // Search to try to find a value.
                let mut bucket = bucket;
                loop {
                    if bucket.key == *key {
                        result = true;
                        break
                    }
                    match bucket.next {
                        None => {
                            result = false;
                            break
                        }
                        Some(ref next_bucket) => bucket = &**next_bucket,
                    }
                }
            }
        }

        unsafe {
            this.locks.get(lock_index).unlock_noguard()
        }

        result
    }

    /// Removes all entries from the map.
    pub fn clear(&self) {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self)
        };

        let (bucket_count, lock_count) = (this.buckets.len(), this.locks.len());
        let buckets_per_lock = bucket_count / lock_count;

        let (mut lock_index, mut stripe_index) = (0, 0);
        for bucket in this.buckets.mut_iter() {
            stripe_index += 1;
            if stripe_index == buckets_per_lock {
                unsafe {
                    this.locks.get(lock_index).unlock_noguard();
                }

                stripe_index = 0;
                lock_index += 1
            }
            if stripe_index == 0 {
                unsafe {
                    this.locks.get(lock_index).lock_noguard()
                }
            }

            *bucket = None
        }
    }

    /// Resizes the map to a new size. Takes all the locks (i.e. acquires an exclusive lock on the
    /// entire table) as it does so.
    ///
    /// This has no problem with invalidating iterators because iterators always hold onto at least
    /// one lock.
    fn try_resize(&self, new_buckets_per_lock: uint) {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self)
        };

        // Take a lock on all buckets.
        for lock in this.locks.mut_iter() {
            unsafe {
                lock.lock_noguard()
            }
        }

        // Check to make sure we aren't already at the right size. Someone else could have already
        // resized.
        let lock_count = this.locks.len();
        let new_bucket_count = lock_count * new_buckets_per_lock;
        if new_bucket_count > this.buckets.len() {
            // Create a new set of buckets.
            let mut buckets = Vec::from_fn(new_bucket_count, |_| None);
            mem::swap(&mut this.buckets, &mut buckets);
            this.size.store(0, Relaxed);

            // Go through all the old buckets and insert the new data.
            for bucket in buckets.move_iter() {
                match bucket {
                    None => continue,
                    Some(Bucket {
                        key: key,
                        value: value,
                        next: mut bucket
                    }) => {
                        unsafe {
                            this.insert_unlocked(key, value, None)
                        }

                        loop {
                            match bucket {
                                None => break,
                                Some(~Bucket {
                                    key: key,
                                    value: value,
                                    next: next
                                }) => {
                                    unsafe {
                                        this.insert_unlocked(key, value, None)
                                    }

                                    bucket = next
                                }
                            }
                        }
                    }
                }
            }
        }

        // Release all our locks.
        for lock in this.locks.mut_iter() {
            unsafe {
                lock.unlock_noguard()
            }
        }
    }

    /// Returns the index of the bucket and the lock for the given key, respectively, taking the
    /// appropriate lock before returning. This is subtle: it contains a loop to deal with race
    /// conditions in which the bucket array might have resized.
    #[inline]
    fn bucket_and_lock_indices(&self, key: &K) -> (uint, uint) {
        let this: &mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(cast::transmute_region(self))
        };

        let hash = sip::hash_with_keys(self.k0, self.k1, key);
        let lock_count = this.locks.len();
        let mut bucket_index;
        let mut lock_index;
        loop {
            let bucket_count = this.buckets.len();
            let buckets_per_lock = bucket_count / lock_count;
            bucket_index = hash as uint % bucket_count;
            lock_index = bucket_index / buckets_per_lock;
            unsafe {
                this.locks.get(lock_index).lock_noguard();
            }
            let new_bucket_count = this.buckets.len();
            if bucket_count == new_bucket_count {
                break
            }

            // If we got here, the hash table resized from under us: try again.
            unsafe {
                this.locks.get(lock_index).unlock_noguard()
            }
        }

        (bucket_index, lock_index)
    }

    /// Returns the index of the bucket. You must be holding at least one lock to call this
    /// function!
    #[inline]
    unsafe fn bucket_index_unlocked(&self, key: &K) -> uint {
        let hash = sip::hash_with_keys(self.k0, self.k1, key);
        hash as uint % self.buckets.len()
    }

    /// Returns true if this hash table is overloaded (at its current load factor, default 0.75)
    /// and false otherwise.
    #[inline]
    fn overloaded(&self) -> bool {
        self.size.load(SeqCst) >= (self.buckets.len() * LOAD_NUMERATOR / LOAD_DENOMINATOR)
    }

    /// Returns the number of buckets per lock.
    #[inline]
    fn buckets_per_lock(&self) -> uint {
        self.buckets.len() / self.locks.len()
    }

    /// Returns the number of elements in the hash table.
    #[inline]
    pub fn size(&self) -> uint {
        self.size.load(SeqCst)
    }
}

pub struct ConcurrentHashMapIterator<'a,K,V> {
    map: &'a ConcurrentHashMap<K,V>,
    bucket_index: int,
    current_bucket: *Bucket<K,V>,
}

impl<'a,K,V> Iterator<(&'a K, &'a V)> for ConcurrentHashMapIterator<'a,K,V> {
    fn next(&mut self) -> Option<(&'a K, &'a V)> {
        let map: &'a mut ConcurrentHashMap<K,V> = unsafe {
            cast::transmute_mut(self.map)
        };

        let (bucket_count, lock_count) = (map.buckets.len(), map.locks.len());
        let buckets_per_lock = bucket_count / lock_count;

        // Go to the next bucket in the chain, if necessary.
        if self.current_bucket != ptr::null() {
            unsafe {
                self.current_bucket = match (*self.current_bucket).next {
                    None => ptr::null(),
                    Some(ref bucket) => {
                        let bucket: *Bucket<K,V> = &**bucket;
                        bucket
                    }
                }
            }
        }

        // Advance buckets, taking locks along the way if necessary.
        while self.current_bucket == ptr::null() {
            let bucket_index = self.bucket_index;
            let lock_index = if bucket_index < 0 {
                -1
            } else {
                bucket_index / (buckets_per_lock as int)
            };

            if bucket_index < 0 ||
                    bucket_index % (buckets_per_lock as int) == (buckets_per_lock as int) - 1 {
                // We're at the boundary between one lock and another. Drop the old lock if
                // necessary and acquire the new one, if necessary.
                if bucket_index != -1 {
                    unsafe {
                        map.locks.get(lock_index as uint).unlock_noguard()
                    }
                }
                if bucket_index != (bucket_count as int) - 1 {
                    unsafe {
                        map.locks.get((lock_index + 1) as uint).lock_noguard()
                    }
                }
            }

            // If at end, return None.
            if self.bucket_index == (bucket_count as int) - 1 {
                return None
            }

            self.bucket_index += 1;

            self.current_bucket = match map.buckets.get(self.bucket_index as uint) {
                &None => ptr::null(),
                &Some(ref bucket) => {
                    let bucket: *Bucket<K,V> = bucket;
                    bucket
                }
            }
        }

        unsafe {
            Some((cast::transmute(&(*self.current_bucket).key),
                  cast::transmute(&(*self.current_bucket).value)))
        }
    }
}

#[cfg(test)]
pub mod test {
    use sync::Arc;
    use native;
    use std::comm;

    use concurrentmap::ConcurrentHashMap;

    #[test]
    pub fn smoke() {
        let m = Arc::new(ConcurrentHashMap::new());
        let (chan, port) = comm::channel();

        // Big enough to make it resize once.
        for i in range(0, 5) {
            let m = m.clone();
            let chan = chan.clone();
            native::task::spawn(proc() {
                for j in range(i * 20, (i * 20) + 20) {
                    m.insert(j, j * j);
                }
                chan.send(());
            })
        }
        for _ in range(0, 5) {
            port.recv();
        }

        let mut count = 0;
        for (&k, &v) in m.iter() {
            assert_eq!(k * k, v)
            count += 1;
        }
        assert_eq!(count, 100)
    }
}

<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow.s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##,

E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:

```
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }

// Attempts to mutate closed-over data.  Error message reads:
// `cannot assign to data in a captured outer variable...`
fn mutable() {
    let mut x = 0u32;
    foo(|| x = 2);
}

// Attempts to take a mutable reference to closed-over data.  Error message
// reads: `cannot borrow data mutably in a captured outer variable...`
fn mut_addr() {
    let mut x = 0u32;
    foo(|| { let y = &mut x; });
}
```

The problem here is that foo is defined as accepting a parameter of type `Fn`.
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
they capture their context immutably.

If the definition of `foo` is under your control, the simplest solution is to
capture the data mutably. This can be done by defining `foo` to take FnMut
rather than Fn:

```
fn foo<F: FnMut()>(f: F) { }
```

Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
interior mutability through a shared reference. Our example's `mutable` function
could be redefined as below:

```
use std::cell::Cell;

fn mutable() {
    let x = Cell::new(0u32);
    foo(|| x.set(2));
}
```

You can read more about cell types in the API documentation:

https://doc.rust-lang.org/std/cell/
"##

}

register_diagnostics! {
    E0383, // partial reinitialization of uninitialized structure
    E0385, // {} in an aliasable location
    E0386, // {} in an immutable container
    E0388, // {} in a static location
    E0389  // {} in a `&` reference
}
<commit_msg>Add detailed diagnostics for E0383.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow.s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0383: r##"
This error occurs when an attempt is made to partially reinitialize a
structure that is currently uninitialized.

For example, this can happen when a transfer of ownership has taken place:

```
let mut t = Test { a: 1, b: None};
let mut u = Test { a: 2, b: Some(Box::new(t))}; // `t` is now uninitialized
                                                // because ownership has been
                                                // transferred
t.b = Some(Box::new(u)); // error, partial reinitialization of uninitialized
                         //        structure `t`
```

This error can be fixed by fully reinitializing the structure in question:

```
let mut t = Test { a: 1, b: None};
let mut u = Test { a: 2, b: Some(Box::new(t))};
t = Test { a: 1, b: Some(Box::new(u))};
```
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##,

E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:

```
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }

// Attempts to mutate closed-over data.  Error message reads:
// `cannot assign to data in a captured outer variable...`
fn mutable() {
    let mut x = 0u32;
    foo(|| x = 2);
}

// Attempts to take a mutable reference to closed-over data.  Error message
// reads: `cannot borrow data mutably in a captured outer variable...`
fn mut_addr() {
    let mut x = 0u32;
    foo(|| { let y = &mut x; });
}
```

The problem here is that foo is defined as accepting a parameter of type `Fn`.
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
they capture their context immutably.

If the definition of `foo` is under your control, the simplest solution is to
capture the data mutably. This can be done by defining `foo` to take FnMut
rather than Fn:

```
fn foo<F: FnMut()>(f: F) { }
```

Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
interior mutability through a shared reference. Our example's `mutable` function
could be redefined as below:

```
use std::cell::Cell;

fn mutable() {
    let x = Cell::new(0u32);
    foo(|| x.set(2));
}
```

You can read more about cell types in the API documentation:

https://doc.rust-lang.org/std/cell/
"##

}

register_diagnostics! {
    E0385, // {} in an aliasable location
    E0386, // {} in an immutable container
    E0388, // {} in a static location
    E0389  // {} in a `&` reference
}
<|endoftext|>


<commit_before><commit_msg>rollup merge of #17586 : Sawyer47/test-16465<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Used to cause an ICE

struct Foo<T>{
    x : T
}

type FooInt = Foo<int>;

impl Drop for FooInt {
//~^ ERROR cannot implement a destructor on a structure with type parameters
    fn drop(&mut self){}
}

fn main() {}
<|endoftext|>


<commit_before><commit_msg>Add regression test for #34194<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]

struct A {
    a: &'static (),
}

static B: &'static A = &A { a: &() };
static C: &'static A = &B;
//~^ ERROR cannot refer to other statics by value

fn main() {}
<|endoftext|>


<commit_before><commit_msg>Add a mir-opt test<commit_after>#![feature(never_type)]

pub enum Void {}

#[no_mangle]
pub fn process_never(input: *const !) {
   let _input = unsafe { &*input };
}

#[no_mangle]
pub fn process_void(input: *const Void) {
   let _input = unsafe { &*input };
   // In the future, this should end with `unreachable`, but we currently only do
   // unreachability analysis for `!`.
}

fn main() {}

// END RUST SOURCE
//
// START rustc.process_never.SimplifyLocals.after.mir
// bb0: {
//     StorageLive(_2);
//     _2 = &(*_1);
//     StorageDead(_2);
//     unreachable;
// }
// END rustc.process_never.SimplifyLocals.after.mir
//
// START rustc.process_void.SimplifyLocals.after.mir
// bb0: {
//     StorageLive(_2);
//     _2 = &(*_1);
//     StorageDead(_2);
//     return;
// }
// END rustc.process_void.SimplifyLocals.after.mir
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate toml;
extern crate rustc_serialize;

use std::collections::{BTreeMap, HashMap};
use std::env;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{PathBuf, Path};
use std::process::{Command, Stdio};

static HOSTS: &'static [&'static str] = &[
    "aarch64-unknown-linux-gnu",
    "arm-unknown-linux-gnueabi",
    "arm-unknown-linux-gnueabihf",
    "armv7-unknown-linux-gnueabihf",
    "i686-apple-darwin",
    "i686-pc-windows-gnu",
    "i686-pc-windows-msvc",
    "i686-unknown-linux-gnu",
    "mips-unknown-linux-gnu",
    "mips64-unknown-linux-gnuabi64",
    "mips64el-unknown-linux-gnuabi64",
    "mipsel-unknown-linux-gnu",
    "powerpc-unknown-linux-gnu",
    "powerpc64-unknown-linux-gnu",
    "powerpc64le-unknown-linux-gnu",
    "s390x-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-pc-windows-gnu",
    "x86_64-pc-windows-msvc",
    "x86_64-unknown-freebsd",
    "x86_64-unknown-linux-gnu",
    "x86_64-unknown-netbsd",
];

static TARGETS: &'static [&'static str] = &[
    "aarch64-apple-ios",
    "aarch64-linux-android",
    "aarch64-unknown-linux-gnu",
    "arm-linux-androideabi",
    "arm-unknown-linux-gnueabi",
    "arm-unknown-linux-gnueabihf",
    "arm-unknown-linux-musleabi",
    "arm-unknown-linux-musleabihf",
    "armv7-apple-ios",
    "armv7-linux-androideabi",
    "armv7-unknown-linux-gnueabihf",
    "armv7-unknown-linux-musleabihf",
    "armv7s-apple-ios",
    "asmjs-unknown-emscripten",
    "i386-apple-ios",
    "i586-pc-windows-msvc",
    "i586-unknown-linux-gnu",
    "i686-apple-darwin",
    "i686-linux-android",
    "i686-pc-windows-gnu",
    "i686-pc-windows-msvc",
    "i686-unknown-freebsd",
    "i686-unknown-linux-gnu",
    "i686-unknown-linux-musl",
    "mips-unknown-linux-gnu",
    "mips-unknown-linux-musl",
    "mips64-unknown-linux-gnuabi64",
    "mips64el-unknown-linux-gnuabi64",
    "mipsel-unknown-linux-gnu",
    "mipsel-unknown-linux-musl",
    "powerpc-unknown-linux-gnu",
    "powerpc64-unknown-linux-gnu",
    "powerpc64le-unknown-linux-gnu",
    "s390x-unknown-linux-gnu",
    "sparc64-unknown-linux-gnu",
    "wasm32-unknown-emscripten",
    "x86_64-apple-darwin",
    "x86_64-apple-ios",
    "x86_64-pc-windows-gnu",
    "x86_64-pc-windows-msvc",
    "x86_64-rumprun-netbsd",
    "x86_64-unknown-freebsd",
    "x86_64-unknown-linux-gnu",
    "x86_64-unknown-linux-musl",
    "x86_64-unknown-netbsd",
];

static MINGW: &'static [&'static str] = &[
    "i686-pc-windows-gnu",
    "x86_64-pc-windows-gnu",
];

struct Manifest {
    manifest_version: String,
    date: String,
    pkg: HashMap<String, Package>,
}

#[derive(RustcEncodable)]
struct Package {
    version: String,
    target: HashMap<String, Target>,
}

#[derive(RustcEncodable)]
struct Target {
    available: bool,
    url: Option<String>,
    hash: Option<String>,
    components: Option<Vec<Component>>,
    extensions: Option<Vec<Component>>,
}

#[derive(RustcEncodable)]
struct Component {
    pkg: String,
    target: String,
}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

struct Builder {
    channel: String,
    input: PathBuf,
    output: PathBuf,
    gpg_passphrase: String,
    digests: HashMap<String, String>,
    s3_address: String,
    date: String,
    rust_version: String,
    cargo_version: String,
}

fn main() {
    let mut args = env::args().skip(1);
    let input = PathBuf::from(args.next().unwrap());
    let output = PathBuf::from(args.next().unwrap());
    let date = args.next().unwrap();
    let channel = args.next().unwrap();
    let s3_address = args.next().unwrap();
    let mut passphrase = String::new();
    t!(io::stdin().read_to_string(&mut passphrase));

    Builder {
        channel: channel,
        input: input,
        output: output,
        gpg_passphrase: passphrase,
        digests: HashMap::new(),
        s3_address: s3_address,
        date: date,
        rust_version: String::new(),
        cargo_version: String::new(),
    }.build();
}

impl Builder {
    fn build(&mut self) {
        self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu");
        self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu");

        self.digest_and_sign();
        let Manifest { manifest_version, date, pkg } = self.build_manifest();

        // Unfortunately we can't use derive(RustcEncodable) here because the
        // version field is called `manifest-version`, not `manifest_version`.
        // In lieu of that just create the table directly here with a `BTreeMap`
        // and wrap it up in a `Value::Table`.
        let mut manifest = BTreeMap::new();
        manifest.insert("manifest-version".to_string(),
                        toml::Value::String(manifest_version));
        manifest.insert("date".to_string(), toml::Value::String(date));
        manifest.insert("pkg".to_string(), toml::encode(&pkg));
        let manifest = toml::Value::Table(manifest).to_string();

        let filename = format!("channel-rust-{}.toml", self.channel);
        self.write_manifest(&manifest, &filename);

        if self.channel != "beta" && self.channel != "nightly" {
            self.write_manifest(&manifest, "channel-rust-stable.toml");
        }
    }

    fn digest_and_sign(&mut self) {
        for file in t!(self.input.read_dir()).map(|e| t!(e).path()) {
            let filename = file.file_name().unwrap().to_str().unwrap();
            let digest = self.hash(&file);
            self.sign(&file);
            assert!(self.digests.insert(filename.to_string(), digest).is_none());
        }
    }

    fn build_manifest(&mut self) -> Manifest {
        let mut manifest = Manifest {
            manifest_version: "2".to_string(),
            date: self.date.to_string(),
            pkg: HashMap::new(),
        };

        self.package("rustc", &mut manifest.pkg, HOSTS);
        self.package("cargo", &mut manifest.pkg, HOSTS);
        self.package("rust-mingw", &mut manifest.pkg, MINGW);
        self.package("rust-std", &mut manifest.pkg, TARGETS);
        self.package("rust-docs", &mut manifest.pkg, TARGETS);
        self.package("rust-src", &mut manifest.pkg, &["*"]);

        let mut pkg = Package {
            version: self.cached_version("rust").to_string(),
            target: HashMap::new(),
        };
        for host in HOSTS {
            let filename = self.filename("rust", host);
            let digest = match self.digests.remove(&filename) {
                Some(digest) => digest,
                None => {
                    pkg.target.insert(host.to_string(), Target {
                        available: false,
                        url: None,
                        hash: None,
                        components: None,
                        extensions: None,
                    });
                    continue
                }
            };
            let mut components = Vec::new();
            let mut extensions = Vec::new();

            // rustc/rust-std/cargo are all required, and so is rust-mingw if it's
            // available for the target.
            components.extend(vec![
                Component { pkg: "rustc".to_string(), target: host.to_string() },
                Component { pkg: "rust-std".to_string(), target: host.to_string() },
                Component { pkg: "cargo".to_string(), target: host.to_string() },
            ]);
            if host.contains("pc-windows-gnu") {
                components.push(Component {
                    pkg: "rust-mingw".to_string(),
                    target: host.to_string(),
                });
            }

            // Docs, other standard libraries, and the source package are all
            // optional.
            extensions.push(Component {
                pkg: "rust-docs".to_string(),
                target: host.to_string(),
            });
            for target in TARGETS {
                if target != host {
                    extensions.push(Component {
                        pkg: "rust-std".to_string(),
                        target: target.to_string(),
                    });
                }
            }
            extensions.push(Component {
                pkg: "rust-src".to_string(),
                target: "*".to_string(),
            });

            pkg.target.insert(host.to_string(), Target {
                available: true,
                url: Some(self.url("rust", host)),
                hash: Some(to_hex(digest.as_ref())),
                components: Some(components),
                extensions: Some(extensions),
            });
        }
        manifest.pkg.insert("rust".to_string(), pkg);

        return manifest
    }

    fn package(&mut self,
               pkgname: &str,
               dst: &mut HashMap<String, Package>,
               targets: &[&str]) {
        let targets = targets.iter().map(|name| {
            let filename = self.filename(pkgname, name);
            let digest = match self.digests.remove(&filename) {
                Some(digest) => digest,
                None => {
                    return (name.to_string(), Target {
                        available: false,
                        url: None,
                        hash: None,
                        components: None,
                        extensions: None,
                    })
                }
            };

            (name.to_string(), Target {
                available: true,
                url: Some(self.url(pkgname, name)),
                hash: Some(digest),
                components: None,
                extensions: None,
            })
        }).collect();

        dst.insert(pkgname.to_string(), Package {
            version: self.cached_version(pkgname).to_string(),
            target: targets,
        });
    }

    fn url(&self, component: &str, target: &str) -> String {
        format!("{}/{}/{}",
                self.s3_address,
                self.date,
                self.filename(component, target))
    }

    fn filename(&self, component: &str, target: &str) -> String {
        if component == "rust-src" {
            format!("rust-src-{}.tar.gz", self.channel)
        } else if component == "cargo" {
            format!("cargo-nightly-{}.tar.gz", target)
        } else {
            format!("{}-{}-{}.tar.gz", component, self.channel, target)
        }
    }

    fn cached_version(&self, component: &str) -> &str {
        if component == "cargo" {
            &self.cargo_version
        } else {
            &self.rust_version
        }
    }

    fn version(&self, component: &str, target: &str) -> String {
        let mut cmd = Command::new("tar");
        let filename = self.filename(component, target);
        cmd.arg("xf")
           .arg(self.input.join(&filename))
           .arg(format!("{}/version", filename.replace(".tar.gz", "")))
           .arg("-O");
        let version = t!(cmd.output());
        if !version.status.success() {
            panic!("failed to learn version:\n\n{:?}\n\n{}\n\n{}",
                   cmd,
                   String::from_utf8_lossy(&version.stdout),
                   String::from_utf8_lossy(&version.stderr));
        }
        String::from_utf8_lossy(&version.stdout).trim().to_string()
    }

    fn hash(&self, path: &Path) -> String {
        let sha = t!(Command::new("shasum")
                        .arg("-a").arg("256")
                        .arg(path.file_name().unwrap())
                        .current_dir(path.parent().unwrap())
                        .output());
        assert!(sha.status.success());

        let filename = path.file_name().unwrap().to_str().unwrap();
        let sha256 = self.output.join(format!("{}.sha256", filename));
        t!(t!(File::create(&sha256)).write_all(&sha.stdout));

        let stdout = String::from_utf8_lossy(&sha.stdout);
        stdout.split_whitespace().next().unwrap().to_string()
    }

    fn sign(&self, path: &Path) {
        let filename = path.file_name().unwrap().to_str().unwrap();
        let asc = self.output.join(format!("{}.asc", filename));
        println!("signing: {:?}", path);
        let mut cmd = Command::new("gpg");
        cmd.arg("--no-tty")
            .arg("--yes")
            .arg("--passphrase-fd").arg("0")
            .arg("--armor")
            .arg("--output").arg(&asc)
            .arg("--detach-sign").arg(path)
            .stdin(Stdio::piped());
        let mut child = t!(cmd.spawn());
        t!(child.stdin.take().unwrap().write_all(self.gpg_passphrase.as_bytes()));
        assert!(t!(child.wait()).success());
    }

    fn write_manifest(&self, manifest: &str, name: &str) {
        let dst = self.output.join(name);
        t!(t!(File::create(&dst)).write_all(manifest.as_bytes()));
        self.hash(&dst);
        self.sign(&dst);
    }
}

fn to_hex(digest: &[u8]) -> String {
    let mut ret = String::new();
    for byte in digest {
        ret.push(hex((byte & 0xf0) >> 4));
        ret.push(hex(byte & 0xf));
    }
    return ret;

    fn hex(b: u8) -> char {
        match b {
            0...9 => (b'0' + b) as char,
            _ => (b'a' + b - 10) as char,
        }
    }
}
<commit_msg>Add save-analysis data to nightly manifests.<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate toml;
extern crate rustc_serialize;

use std::collections::{BTreeMap, HashMap};
use std::env;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{PathBuf, Path};
use std::process::{Command, Stdio};

static HOSTS: &'static [&'static str] = &[
    "aarch64-unknown-linux-gnu",
    "arm-unknown-linux-gnueabi",
    "arm-unknown-linux-gnueabihf",
    "armv7-unknown-linux-gnueabihf",
    "i686-apple-darwin",
    "i686-pc-windows-gnu",
    "i686-pc-windows-msvc",
    "i686-unknown-linux-gnu",
    "mips-unknown-linux-gnu",
    "mips64-unknown-linux-gnuabi64",
    "mips64el-unknown-linux-gnuabi64",
    "mipsel-unknown-linux-gnu",
    "powerpc-unknown-linux-gnu",
    "powerpc64-unknown-linux-gnu",
    "powerpc64le-unknown-linux-gnu",
    "s390x-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-pc-windows-gnu",
    "x86_64-pc-windows-msvc",
    "x86_64-unknown-freebsd",
    "x86_64-unknown-linux-gnu",
    "x86_64-unknown-netbsd",
];

static TARGETS: &'static [&'static str] = &[
    "aarch64-apple-ios",
    "aarch64-linux-android",
    "aarch64-unknown-linux-gnu",
    "arm-linux-androideabi",
    "arm-unknown-linux-gnueabi",
    "arm-unknown-linux-gnueabihf",
    "arm-unknown-linux-musleabi",
    "arm-unknown-linux-musleabihf",
    "armv7-apple-ios",
    "armv7-linux-androideabi",
    "armv7-unknown-linux-gnueabihf",
    "armv7-unknown-linux-musleabihf",
    "armv7s-apple-ios",
    "asmjs-unknown-emscripten",
    "i386-apple-ios",
    "i586-pc-windows-msvc",
    "i586-unknown-linux-gnu",
    "i686-apple-darwin",
    "i686-linux-android",
    "i686-pc-windows-gnu",
    "i686-pc-windows-msvc",
    "i686-unknown-freebsd",
    "i686-unknown-linux-gnu",
    "i686-unknown-linux-musl",
    "mips-unknown-linux-gnu",
    "mips-unknown-linux-musl",
    "mips64-unknown-linux-gnuabi64",
    "mips64el-unknown-linux-gnuabi64",
    "mipsel-unknown-linux-gnu",
    "mipsel-unknown-linux-musl",
    "powerpc-unknown-linux-gnu",
    "powerpc64-unknown-linux-gnu",
    "powerpc64le-unknown-linux-gnu",
    "s390x-unknown-linux-gnu",
    "sparc64-unknown-linux-gnu",
    "wasm32-unknown-emscripten",
    "x86_64-apple-darwin",
    "x86_64-apple-ios",
    "x86_64-pc-windows-gnu",
    "x86_64-pc-windows-msvc",
    "x86_64-rumprun-netbsd",
    "x86_64-unknown-freebsd",
    "x86_64-unknown-linux-gnu",
    "x86_64-unknown-linux-musl",
    "x86_64-unknown-netbsd",
];

static MINGW: &'static [&'static str] = &[
    "i686-pc-windows-gnu",
    "x86_64-pc-windows-gnu",
];

struct Manifest {
    manifest_version: String,
    date: String,
    pkg: HashMap<String, Package>,
}

#[derive(RustcEncodable)]
struct Package {
    version: String,
    target: HashMap<String, Target>,
}

#[derive(RustcEncodable)]
struct Target {
    available: bool,
    url: Option<String>,
    hash: Option<String>,
    components: Option<Vec<Component>>,
    extensions: Option<Vec<Component>>,
}

#[derive(RustcEncodable)]
struct Component {
    pkg: String,
    target: String,
}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

struct Builder {
    channel: String,
    input: PathBuf,
    output: PathBuf,
    gpg_passphrase: String,
    digests: HashMap<String, String>,
    s3_address: String,
    date: String,
    rust_version: String,
    cargo_version: String,
}

fn main() {
    let mut args = env::args().skip(1);
    let input = PathBuf::from(args.next().unwrap());
    let output = PathBuf::from(args.next().unwrap());
    let date = args.next().unwrap();
    let channel = args.next().unwrap();
    let s3_address = args.next().unwrap();
    let mut passphrase = String::new();
    t!(io::stdin().read_to_string(&mut passphrase));

    Builder {
        channel: channel,
        input: input,
        output: output,
        gpg_passphrase: passphrase,
        digests: HashMap::new(),
        s3_address: s3_address,
        date: date,
        rust_version: String::new(),
        cargo_version: String::new(),
    }.build();
}

impl Builder {
    fn build(&mut self) {
        self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu");
        self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu");

        self.digest_and_sign();
        let Manifest { manifest_version, date, pkg } = self.build_manifest();

        // Unfortunately we can't use derive(RustcEncodable) here because the
        // version field is called `manifest-version`, not `manifest_version`.
        // In lieu of that just create the table directly here with a `BTreeMap`
        // and wrap it up in a `Value::Table`.
        let mut manifest = BTreeMap::new();
        manifest.insert("manifest-version".to_string(),
                        toml::Value::String(manifest_version));
        manifest.insert("date".to_string(), toml::Value::String(date));
        manifest.insert("pkg".to_string(), toml::encode(&pkg));
        let manifest = toml::Value::Table(manifest).to_string();

        let filename = format!("channel-rust-{}.toml", self.channel);
        self.write_manifest(&manifest, &filename);

        if self.channel != "beta" && self.channel != "nightly" {
            self.write_manifest(&manifest, "channel-rust-stable.toml");
        }
    }

    fn digest_and_sign(&mut self) {
        for file in t!(self.input.read_dir()).map(|e| t!(e).path()) {
            let filename = file.file_name().unwrap().to_str().unwrap();
            let digest = self.hash(&file);
            self.sign(&file);
            assert!(self.digests.insert(filename.to_string(), digest).is_none());
        }
    }

    fn build_manifest(&mut self) -> Manifest {
        let mut manifest = Manifest {
            manifest_version: "2".to_string(),
            date: self.date.to_string(),
            pkg: HashMap::new(),
        };

        self.package("rustc", &mut manifest.pkg, HOSTS);
        self.package("cargo", &mut manifest.pkg, HOSTS);
        self.package("rust-mingw", &mut manifest.pkg, MINGW);
        self.package("rust-std", &mut manifest.pkg, TARGETS);
        self.package("rust-docs", &mut manifest.pkg, TARGETS);
        self.package("rust-src", &mut manifest.pkg, &["*"]);

        if self.channel == "rust-nightly" {
            self.package("analysis", &mut manifest.pkg, TARGETS);
        }

        let mut pkg = Package {
            version: self.cached_version("rust").to_string(),
            target: HashMap::new(),
        };
        for host in HOSTS {
            let filename = self.filename("rust", host);
            let digest = match self.digests.remove(&filename) {
                Some(digest) => digest,
                None => {
                    pkg.target.insert(host.to_string(), Target {
                        available: false,
                        url: None,
                        hash: None,
                        components: None,
                        extensions: None,
                    });
                    continue
                }
            };
            let mut components = Vec::new();
            let mut extensions = Vec::new();

            // rustc/rust-std/cargo are all required, and so is rust-mingw if it's
            // available for the target.
            components.extend(vec![
                Component { pkg: "rustc".to_string(), target: host.to_string() },
                Component { pkg: "rust-std".to_string(), target: host.to_string() },
                Component { pkg: "cargo".to_string(), target: host.to_string() },
            ]);
            if host.contains("pc-windows-gnu") {
                components.push(Component {
                    pkg: "rust-mingw".to_string(),
                    target: host.to_string(),
                });
            }

            // Docs, other standard libraries, and the source package are all
            // optional.
            extensions.push(Component {
                pkg: "rust-docs".to_string(),
                target: host.to_string(),
            });
            for target in TARGETS {
                if target != host {
                    extensions.push(Component {
                        pkg: "rust-std".to_string(),
                        target: target.to_string(),
                    });
                }
                if self.channel == "nightly" {
                    extensions.push(Component {
                        pkg: "rust-analysis".to_string(),
                        target: target.to_string(),
                    });
                }
            }
            extensions.push(Component {
                pkg: "rust-src".to_string(),
                target: "*".to_string(),
            });

            pkg.target.insert(host.to_string(), Target {
                available: true,
                url: Some(self.url("rust", host)),
                hash: Some(to_hex(digest.as_ref())),
                components: Some(components),
                extensions: Some(extensions),
            });
        }
        manifest.pkg.insert("rust".to_string(), pkg);

        return manifest
    }

    fn package(&mut self,
               pkgname: &str,
               dst: &mut HashMap<String, Package>,
               targets: &[&str]) {
        let targets = targets.iter().map(|name| {
            let filename = self.filename(pkgname, name);
            let digest = match self.digests.remove(&filename) {
                Some(digest) => digest,
                None => {
                    return (name.to_string(), Target {
                        available: false,
                        url: None,
                        hash: None,
                        components: None,
                        extensions: None,
                    })
                }
            };

            (name.to_string(), Target {
                available: true,
                url: Some(self.url(pkgname, name)),
                hash: Some(digest),
                components: None,
                extensions: None,
            })
        }).collect();

        dst.insert(pkgname.to_string(), Package {
            version: self.cached_version(pkgname).to_string(),
            target: targets,
        });
    }

    fn url(&self, component: &str, target: &str) -> String {
        format!("{}/{}/{}",
                self.s3_address,
                self.date,
                self.filename(component, target))
    }

    fn filename(&self, component: &str, target: &str) -> String {
        if component == "rust-src" {
            format!("rust-src-{}.tar.gz", self.channel)
        } else if component == "cargo" {
            format!("cargo-nightly-{}.tar.gz", target)
        } else {
            format!("{}-{}-{}.tar.gz", component, self.channel, target)
        }
    }

    fn cached_version(&self, component: &str) -> &str {
        if component == "cargo" {
            &self.cargo_version
        } else {
            &self.rust_version
        }
    }

    fn version(&self, component: &str, target: &str) -> String {
        let mut cmd = Command::new("tar");
        let filename = self.filename(component, target);
        cmd.arg("xf")
           .arg(self.input.join(&filename))
           .arg(format!("{}/version", filename.replace(".tar.gz", "")))
           .arg("-O");
        let version = t!(cmd.output());
        if !version.status.success() {
            panic!("failed to learn version:\n\n{:?}\n\n{}\n\n{}",
                   cmd,
                   String::from_utf8_lossy(&version.stdout),
                   String::from_utf8_lossy(&version.stderr));
        }
        String::from_utf8_lossy(&version.stdout).trim().to_string()
    }

    fn hash(&self, path: &Path) -> String {
        let sha = t!(Command::new("shasum")
                        .arg("-a").arg("256")
                        .arg(path.file_name().unwrap())
                        .current_dir(path.parent().unwrap())
                        .output());
        assert!(sha.status.success());

        let filename = path.file_name().unwrap().to_str().unwrap();
        let sha256 = self.output.join(format!("{}.sha256", filename));
        t!(t!(File::create(&sha256)).write_all(&sha.stdout));

        let stdout = String::from_utf8_lossy(&sha.stdout);
        stdout.split_whitespace().next().unwrap().to_string()
    }

    fn sign(&self, path: &Path) {
        let filename = path.file_name().unwrap().to_str().unwrap();
        let asc = self.output.join(format!("{}.asc", filename));
        println!("signing: {:?}", path);
        let mut cmd = Command::new("gpg");
        cmd.arg("--no-tty")
            .arg("--yes")
            .arg("--passphrase-fd").arg("0")
            .arg("--armor")
            .arg("--output").arg(&asc)
            .arg("--detach-sign").arg(path)
            .stdin(Stdio::piped());
        let mut child = t!(cmd.spawn());
        t!(child.stdin.take().unwrap().write_all(self.gpg_passphrase.as_bytes()));
        assert!(t!(child.wait()).success());
    }

    fn write_manifest(&self, manifest: &str, name: &str) {
        let dst = self.output.join(name);
        t!(t!(File::create(&dst)).write_all(manifest.as_bytes()));
        self.hash(&dst);
        self.sign(&dst);
    }
}

fn to_hex(digest: &[u8]) -> String {
    let mut ret = String::new();
    for byte in digest {
        ret.push(hex((byte & 0xf0) >> 4));
        ret.push(hex(byte & 0xf));
    }
    return ret;

    fn hex(b: u8) -> char {
        match b {
            0...9 => (b'0' + b) as char,
            _ => (b'a' + b - 10) as char,
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>add broken_sendreceive example<commit_after>#[macro_use]
extern crate log;
extern crate fern;
extern crate time;
extern crate mqtt;

use std::thread;
use std::char;
use mqtt::async::{PersistenceType, Qos, MqttError, AsyncClient, AsyncConnectOptions};

fn conf_logger() {
    let logger_config = fern::DispatchConfig {
        format: Box::new(|msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
            let t = time::now();
            let ms = t.tm_nsec/1000_000;
            format!("{}.{:3} [{}] {}", t.strftime("%Y-%m-%dT%H:%M:%S").unwrap(), ms, level, msg)
        }),
        output: vec![fern::OutputConfig::stderr()],
        level: log::LogLevelFilter::Trace,
    };

    if let Err(e) = fern::init_global_logger(logger_config, log::LogLevelFilter::Trace) {
        panic!("Failed to initialize global logger: {}", e);
    }
}

fn setup_mqtt(server_address: &str, topic: &str, client_id: &str) -> Result<AsyncClient, MqttError> {
    let connect_options = AsyncConnectOptions::new();
    let mut client = try!(AsyncClient::new(server_address, client_id, PersistenceType::Nothing));
    try!(client.connect(&connect_options));
    try!(client.subscribe(topic, Qos::FireAndForget));
    Ok(client)
}

fn main() {
    // setup fern logger
    conf_logger();

    // start processing
    info!("sendreceive test started");
    let mut data = Vec::new();
    let topic = "TestTopic";
    match setup_mqtt("tcp://localhost:1883", &topic, "TestClientId") {
        Ok(mut client) => {
            for i in 0..10 {
                info!("data len: {}", i);
                data.push(char::from_digit(i % 10, 10).unwrap() as u8);
                client.send(&data, &topic, Qos::FireAndForget).unwrap();
                for message in client.messages() {
                    info!("{:?}", message);
                }
                thread::sleep_ms(200);
            }},
        Err(e) => error!("{}", e)
    }
    info!("sendreceive test ended");
}
<|endoftext|>


<commit_before>use super::*;
use redox::*;

impl Editor {
    /// Execute a instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use super::Key::*;
        use super::Mode::*;
        use super::PrimitiveMode::*;
        use super::CommandMode::*;

        let n = para.d();
        match cmd {
            Ctrl(b) => self.key_state.ctrl = b,
            Alt(b) => self.key_state.alt = b,
            Shift(b) => self.key_state.shift = b,
            _ => {},
        }

        if cmd == Char(' ') && self.key_state.shift {
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
        } else if self.key_state.alt {
            let new_pos = self.to_motion(Inst(para, cmd));
            self.goto(new_pos);
        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd {
                    Char('i') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    },
                    Char('o') => {
                        // TODO: Autoindent (keep the same indentation level)
                        let y = self.y();
                        let ind = self.get_indent(y);
                        let last = ind.len();
                        self.text.insert(y + 1, ind);
                        self.goto((last, y + 1));
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));
                    }
                    Char('h') => self.goto_left(n),
                    Char('j') => self.goto_down(n),
                    Char('k') => self.goto_up(n),
                    Char('l') => self.goto_right(n),
                    Char('J') => self.goto_down(15),
                    Char('K') => self.goto_up(15),
                    Char('x') => self.delete(),
                    Char('X') => {
                        self.goto_previous();
                        self.delete();
                    },
                    Char('L') => self.goto_ln_end(),
                    Char('H') => self.cursor_mut().x = 0,
                    Char('r') => {
                        loop {
                            if let EventOption::Key(k) = self.window.poll()
                                                         .unwrap_or(Event::new())
                                                         .to_option() {
                                if k.pressed {
                                    let x = self.x();
                                    let y = self.y();
                                    self.text[y][x] = k.character;
                                    break;
                                }
                            }
                        }
                    },
                    Char('R') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    },
                    Char('d') => {
                        let ins = self.next_inst();
                        let motion = self.to_motion(ins);
                        self.remove_rb(motion);
                    },
                    Char('G') => {
                        let last = self.text.len() - 1;
                        self.goto((0, last));
                    },
                    Char('g') => {
                        if let Parameter::Int(n) = para {
                            self.goto((0, n - 1));
                        } else {
                            let inst = self.next_inst();
                            let new = self.to_motion(inst);
                            self.cursor_mut().x = new.0;
                            self.cursor_mut().y = new.1;
                        }

                    },
//                    ????
//                    Char('K') => {
//                        self.goto((0, 0));
//                    },
//                    Char('J') => {
//                        self.goto((0, self.text.len() - 1));
//                    },
                    Char(' ') => self.goto_next(),
                    _ => {},
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd, opt);
                },
            }
        }
    }
}
<commit_msg>Add cursor branching<commit_after>use super::*;
use redox::*;

impl Editor {
    /// Execute a instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use super::Key::*;
        use super::Mode::*;
        use super::PrimitiveMode::*;
        use super::CommandMode::*;

        let n = para.d();
        match cmd {
            Ctrl(b) => self.key_state.ctrl = b,
            Alt(b) => self.key_state.alt = b,
            Shift(b) => self.key_state.shift = b,
            _ => {},
        }

        if cmd == Char(' ') && self.key_state.shift {
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
        } else if self.key_state.alt && cmd == Key::Char(' ') {
            self.next_cursor();
        } else if self.key_state.alt {
            let new_pos = self.to_motion(Inst(para, cmd));
            self.goto(new_pos);
        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd {
                    Char('i') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    },
                    Char('o') => {
                        // TODO: Autoindent (keep the same indentation level)
                        let y = self.y();
                        let ind = self.get_indent(y);
                        let last = ind.len();
                        self.text.insert(y + 1, ind);
                        self.goto((last, y + 1));
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));
                    }
                    Char('h') => self.goto_left(n),
                    Char('j') => self.goto_down(n),
                    Char('k') => self.goto_up(n),
                    Char('l') => self.goto_right(n),
                    Char('J') => self.goto_down(15),
                    Char('K') => self.goto_up(15),
                    Char('x') => self.delete(),
                    Char('X') => {
                        self.goto_previous();
                        self.delete();
                    },
                    Char('L') => self.goto_ln_end(),
                    Char('H') => self.cursor_mut().x = 0,
                    Char('r') => {
                        loop {
                            if let EventOption::Key(k) = self.window.poll()
                                                         .unwrap_or(Event::new())
                                                         .to_option() {
                                if k.pressed {
                                    let x = self.x();
                                    let y = self.y();
                                    self.text[y][x] = k.character;
                                    break;
                                }
                            }
                        }
                    },
                    Char('R') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    },
                    Char('d') => {
                        let ins = self.next_inst();
                        let motion = self.to_motion(ins);
                        self.remove_rb(motion);
                    },
                    Char('G') => {
                        let last = self.text.len() - 1;
                        self.goto((0, last));
                    },
                    Char('g') => {
                        if let Parameter::Int(n) = para {
                            self.goto((0, n - 1));
                        } else {
                            let inst = self.next_inst();
                            let new = self.to_motion(inst);
                            self.cursor_mut().x = new.0;
                            self.cursor_mut().y = new.1;
                        }

                    },
                    Char('b') => {
                        // Branch cursor
                        let cursor = self.cursor().clone();
                        self.cursors.push(cursor);
                    },
//                    ????
//                    Char('K') => {
//                        self.goto((0, 0));
//                    },
//                    Char('J') => {
//                        self.goto((0, self.text.len() - 1));
//                    },
                    Char(' ') => self.goto_next(),
                    _ => {},
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd, opt);
                },
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -Z trace-macros

#![recursion_limit="4"]

macro_rules! my_faulty_macro {
    () => {
        my_faulty_macro!(bcd);
    };
}

macro_rules! pat_macro {
    () => {
        pat_macro!(A{a:a, b:0, c:_, ..});
    };
    ($a:pat) => {
        $a
    };
}

macro_rules! my_recursive_macro {
    () => {
        my_recursive_macro!();
    };
}

macro_rules! my_macro {
    () => {

    };
}

fn main() {
    my_faulty_macro!();
    my_recursive_macro!();
    test!();
    non_exisiting!();
    derive!(Debug);
    let a = pat_macro!();
}

#[my_macro]
fn use_bang_macro_as_attr(){}

#[derive(Debug)]
fn use_derive_macro_as_attr(){}
<commit_msg>Fix tidy error<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -Z trace-macros

#![recursion_limit="4"]

macro_rules! my_faulty_macro {
    () => {
        my_faulty_macro!(bcd);
    };
}

macro_rules! pat_macro {
    () => {
        pat_macro!(A{a:a, b:0, c:_, ..});
    };
    ($a:pat) => {
        $a
    };
}

macro_rules! my_recursive_macro {
    () => {
        my_recursive_macro!();
    };
}

macro_rules! my_macro {
    () => {

    };
}

fn main() {
    my_faulty_macro!();
    my_recursive_macro!();
    test!();
    non_exisiting!();
    derive!(Debug);
    let a = pat_macro!();
}

#[my_macro]
fn use_bang_macro_as_attr(){}

#[derive(Debug)]
fn use_derive_macro_as_attr(){}
<|endoftext|>