<commit_before>//! Concurrent, atomic options.

use std::{mem, ptr};
use std::sync::atomic::{self, AtomicPtr};

use local;
use garbage::Garbage;
use guard::Guard;

/// A concurrently accessible and updatable optional pointer.
///
/// This acts as a kind of concurrent `Option<T>`.  It can be compared to `std::cell::RefCell` in
/// some ways: It allows accessing, referencing, updating, etc., however contrary to `RefCell`,
/// this is concurrent and has no aliasing restrictions. It is futher distinguished from
/// `std::sync::AtomicPtr` in that it allows references to the inner data without the ABA problem
/// or any variant thereof.
///
/// It conviniently wraps this crates API in a seemless manner.
#[derive(Default)]
pub struct AtomicOption<T> {
    /// The inner atomic pointer.
    inner: AtomicPtr<T>,
}

impl<T> AtomicOption<T> {
    //// Create a new concurrent option.
    pub fn new(init: Option<Box<T>>) -> AtomicOption<T> {
        AtomicOption {
            // Convert the box to a raw pointer.
            inner: AtomicPtr::new(init.map_or(ptr::null_mut(), Box::into_raw)),
        }
    }

    /// Get a reference to the current content of the option.
    ///
    /// This returns a `Guard<T>`, which "protects" the inner value such that it is not dropped
    /// before the guard is no longer active. This is all handled automatically through RAII.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn load(&self, ordering: atomic::Ordering) -> Option<Guard<T>> {
        // Load the inner and wrap it in a guard.
        Guard::maybe_new(|| unsafe {
            self.inner.load(ordering).as_ref()
        })
    }

    /// Store a new value in the option.
    ///
    /// The old value of `self` will eventually be dropped, at some point after all the guarding
    /// references are gone.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn store(&self, new: Option<Box<T>>, ordering: atomic::Ordering) {
        // Transform the optional box to a (possibly null) pointer.
        // TODO: Use coercions.
        let new = new.map_or(ptr::null_mut(), |new| Box::into_raw(new));
        // Swap the contents with the new value.
        let ptr = self.inner.swap(new, ordering);
        if !ptr.is_null() {
            // Queue the deletion of the content.
            local::add_garbage(unsafe { Garbage::new_box(ptr) });
        }
    }

    /// Swap the old value with a new.
    ///
    /// This returns a `Guard<T>` as readers of the old values might exist. The old value will be
    /// queued for destruction.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Performance
    ///
    /// This is slower than `store` as it requires initializing a new guard, which requires at
    /// least two atomic operations. Thus, when possible, you should use `store`.
    pub fn swap(&self, new: Option<Box<T>>, ordering: atomic::Ordering) -> Option<Guard<T>> {
        // Convert `new` into a raw pointer.
        // TODO: Use coercions.
        let new_ptr = new.map_or(ptr::null_mut(), Box::into_raw);

        // Create the guard. It is very important that this is done before the garbage is added,
        // otherwise we might introduce premature frees.
        Guard::maybe_new(|| unsafe {
            // Swap the atomic pointer with the new one.
            self.inner.swap(new_ptr, ordering).as_ref()
        }).map(|guard| {
            // Since the pointer is now unreachable from the option, it can safely be queued for
            // deletion.
            local::add_garbage(unsafe { Garbage::new_box(&*guard) });

            guard
        })
    }

    /// Store a value if the current matches a particular value.
    ///
    /// This compares `self` to `old`. If they match, the value is set to `new` and `Ok(())` is
    /// returned. Otherwise, `Err(new)` is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn compare_and_store(&self, old: Option<*const T>, mut new: Option<Box<T>>, ordering: atomic::Ordering)
    -> Result<(), Option<Box<T>>> {
        // Convert the paramteres to raw pointers.
        // TODO: Use coercions.
        let new_ptr = new.as_mut().map_or(ptr::null_mut(), |x| &mut **x);
        let old_ptr = old.map_or(ptr::null_mut(), |x| x as *mut T);

        // Compare-and-swap the value.
        let ptr = self.inner.compare_and_swap(old_ptr, new_ptr, ordering);

        // Check if the CAS was successful.
        if ptr == old_ptr {
            // It was. `self` is now `new`.

            // Ensure that the destructor of `new` is not run.
            mem::forget(new);

            // Queue the deletion of now-unreachable `old` (unless it's `None`).
            if !old_ptr.is_null() {
                local::add_garbage(unsafe { Garbage::new_box(old_ptr) });
            }

            Ok(())
        } else {
            // It failed.
            Err(new)
        }
    }

    /// Swap a value if it matches.
    ///
    /// This compares `self` to `old`. If they match, it is swapped with `new` and a guard to the
    /// old value is returned wrapped in `Ok`. If not, a tuple containing the guard to the actual
    /// (non-matching) value and the box of `new` — wrapped in `Err` — is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Performance
    ///
    /// This is slower than `compare_and_set` as it requires initializing a new guard, which
    /// requires at least two atomic operations. Thus, when possible, you should use
    /// `compare_and_set`.
    pub fn compare_and_swap(&self, old: Option<*const T>, mut new: Option<Box<T>>, ordering: atomic::Ordering)
    -> Result<Option<Guard<T>>, (Option<Guard<T>>, Option<Box<T>>)> {
        // Convert the paramteres to raw pointers.
        // TODO: Use coercions.
        let new_ptr = new.as_mut().map_or(ptr::null_mut(), |x| &mut **x);
        let old_ptr = old.map_or(ptr::null_mut(), |x| x as *mut T);

        // Create the guard beforehand to avoid premature frees.
        let guard = Guard::maybe_new(|| {
            // The guard is active, so we can do the CAS now.
            unsafe { self.inner.compare_and_swap(old_ptr, new_ptr, ordering).as_ref() }
        });

        // Convert the guard to a raw pointer.
        // TODO: Use coercions.
        let guard_ptr = guard.as_ref().map_or(ptr::null_mut(), |x| &**x as *const T as *mut T);

        // Check if the CAS was successful.
        if guard_ptr == old_ptr {
            // It was. `self` is now `new`.

            // Ensure that the destructor of `new` is not run.
            mem::forget(new);

            // Queue the deletion of now-unreachable `old` (unless it's `None`).
            if !old_ptr.is_null() {
                local::add_garbage(unsafe { Garbage::new_box(old_ptr) });
            }

            Ok(guard)
        } else {
            // It failed; cast the raw pointer back to a box and return.
            Err((guard, new))
        }
    }
}

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

    use std::sync::{atomic, Arc};
    use std::thread;

    #[test]
    fn basic_properties() {
        let opt = AtomicOption::default();
        assert!(opt.load(atomic::Relaxed).is_none());
        assert!(opt.swap(None, atomic::Relaxed).is_none());
        assert!(opt.load(atomic::Relaxed).is_none());
        assert!(opt.swap(Some(Box::new(42)), atomic::Relaxed).is_none());
        assert_eq!(*opt.load(atomic::Relaxed).unwrap(), 42);
        assert_eq!(*opt.swap(Some(Box::new(43)), atomic::Relaxed).unwrap(), 42);
        assert_eq!(*opt.load(atomic::Relaxed).unwrap(), 43);
    }

    #[test]
    fn cas() {
        let bx1 = Box::new(1);
        let ptr1 = &*bx1;
        let bx2 = Box::new(1);
        let ptr2 = &*bx2;

        let opt = AtomicOption::new(Some(bx1));
        assert_eq!(&*opt.compare_and_swap(Some(ptr2), None, atomic::Ordering::Relaxed).unwrap_err().0.unwrap(), ptr1);
        assert_eq!(opt.load(atomic::Relaxed), ptr1);

        assert_eq!(&*opt.compare_and_swap(None, Some(Box::new(2)), atomic::Ordering::Relaxed).unwrap_err().0.unwrap(), ptr1);
        assert_eq!(opt.load(atomic::Relaxed), ptr1);

        opt.compare_and_swap(Some(ptr1), None, atomic::Ordering::Relaxed).unwrap();
        assert!(opt.load(atomic::Relaxed).is_none());

        opt.compare_and_swap(None, Some(bx2), atomic::Ordering::Relaxed).unwrap();
        assert_eq!(opt.load(atomic::Relaxed), ptr2);

        opt.compare_and_store(Some(ptr2), None, atomic::Ordering::Relaxed).unwrap();
        opt.compare_and_store(Some(Box::new(2)), None, atomic::Ordering::Relaxed).unwrap_err();

        assert!(opt.load(atomic::Relaxed).is_none());

        // To check that GC doesn't segfault or something.
        ::gc();
        ::gc();
        ::gc();
        ::gc();
    }

    #[test]
    fn spam() {
        let opt = Arc::new(concurrent::Option::default());

        let j = Vec::new();
        for i in 0..16 {
            let opt = opt.clone();
            j.push(thread::spawn(move || {
                for i in 0..1_000_000 {
                    let x = opt.load(atomic::Ordering::Relaxed);
                    opt.store(Some(Box::new(i)));
                }
                opt
            }))
        }

        for i in j {
            i.join().unwrap();
        }

        assert_eq!(*opt.load(atomic::Ordering::Relaxed).unwrap(), 1_000_000);
    }
}
<commit_msg>Add test for dtors in `concurrent`.<commit_after>//! Concurrent, atomic options.

use std::{mem, ptr};
use std::sync::atomic::{self, AtomicPtr};

use local;
use garbage::Garbage;
use guard::Guard;

/// A concurrently accessible and updatable optional pointer.
///
/// This acts as a kind of concurrent `Option<T>`.  It can be compared to `std::cell::RefCell` in
/// some ways: It allows accessing, referencing, updating, etc., however contrary to `RefCell`,
/// this is concurrent and has no aliasing restrictions. It is futher distinguished from
/// `std::sync::AtomicPtr` in that it allows references to the inner data without the ABA problem
/// or any variant thereof.
///
/// It conviniently wraps this crates API in a seemless manner.
#[derive(Default)]
pub struct AtomicOption<T> {
    /// The inner atomic pointer.
    inner: AtomicPtr<T>,
}

impl<T> AtomicOption<T> {
    //// Create a new concurrent option.
    pub fn new(init: Option<Box<T>>) -> AtomicOption<T> {
        AtomicOption {
            // Convert the box to a raw pointer.
            inner: AtomicPtr::new(init.map_or(ptr::null_mut(), Box::into_raw)),
        }
    }

    /// Get a reference to the current content of the option.
    ///
    /// This returns a `Guard<T>`, which "protects" the inner value such that it is not dropped
    /// before the guard is no longer active. This is all handled automatically through RAII.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn load(&self, ordering: atomic::Ordering) -> Option<Guard<T>> {
        // Load the inner and wrap it in a guard.
        Guard::maybe_new(|| unsafe {
            self.inner.load(ordering).as_ref()
        })
    }

    /// Store a new value in the option.
    ///
    /// The old value of `self` will eventually be dropped, at some point after all the guarding
    /// references are gone.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn store(&self, new: Option<Box<T>>, ordering: atomic::Ordering) {
        // Transform the optional box to a (possibly null) pointer.
        // TODO: Use coercions.
        let new = new.map_or(ptr::null_mut(), |new| Box::into_raw(new));
        // Swap the contents with the new value.
        let ptr = self.inner.swap(new, ordering);
        if !ptr.is_null() {
            // Queue the deletion of the content.
            local::add_garbage(unsafe { Garbage::new_box(ptr) });
        }
    }

    /// Swap the old value with a new.
    ///
    /// This returns a `Guard<T>` as readers of the old values might exist. The old value will be
    /// queued for destruction.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Performance
    ///
    /// This is slower than `store` as it requires initializing a new guard, which requires at
    /// least two atomic operations. Thus, when possible, you should use `store`.
    pub fn swap(&self, new: Option<Box<T>>, ordering: atomic::Ordering) -> Option<Guard<T>> {
        // Convert `new` into a raw pointer.
        // TODO: Use coercions.
        let new_ptr = new.map_or(ptr::null_mut(), Box::into_raw);

        // Create the guard. It is very important that this is done before the garbage is added,
        // otherwise we might introduce premature frees.
        Guard::maybe_new(|| unsafe {
            // Swap the atomic pointer with the new one.
            self.inner.swap(new_ptr, ordering).as_ref()
        }).map(|guard| {
            // Since the pointer is now unreachable from the option, it can safely be queued for
            // deletion.
            local::add_garbage(unsafe { Garbage::new_box(&*guard) });

            guard
        })
    }

    /// Store a value if the current matches a particular value.
    ///
    /// This compares `self` to `old`. If they match, the value is set to `new` and `Ok(())` is
    /// returned. Otherwise, `Err(new)` is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    pub fn compare_and_store(&self, old: Option<*const T>, mut new: Option<Box<T>>, ordering: atomic::Ordering)
    -> Result<(), Option<Box<T>>> {
        // Convert the paramteres to raw pointers.
        // TODO: Use coercions.
        let new_ptr = new.as_mut().map_or(ptr::null_mut(), |x| &mut **x);
        let old_ptr = old.map_or(ptr::null_mut(), |x| x as *mut T);

        // Compare-and-swap the value.
        let ptr = self.inner.compare_and_swap(old_ptr, new_ptr, ordering);

        // Check if the CAS was successful.
        if ptr == old_ptr {
            // It was. `self` is now `new`.

            // Ensure that the destructor of `new` is not run.
            mem::forget(new);

            // Queue the deletion of now-unreachable `old` (unless it's `None`).
            if !old_ptr.is_null() {
                local::add_garbage(unsafe { Garbage::new_box(old_ptr) });
            }

            Ok(())
        } else {
            // It failed.
            Err(new)
        }
    }

    /// Swap a value if it matches.
    ///
    /// This compares `self` to `old`. If they match, it is swapped with `new` and a guard to the
    /// old value is returned wrapped in `Ok`. If not, a tuple containing the guard to the actual
    /// (non-matching) value and the box of `new` — wrapped in `Err` — is returned.
    ///
    /// The `ordering` defines what constraints the atomic operation has. Refer to the LLVM
    /// documentation for more information.
    ///
    /// # Performance
    ///
    /// This is slower than `compare_and_set` as it requires initializing a new guard, which
    /// requires at least two atomic operations. Thus, when possible, you should use
    /// `compare_and_set`.
    pub fn compare_and_swap(&self, old: Option<*const T>, mut new: Option<Box<T>>, ordering: atomic::Ordering)
    -> Result<Option<Guard<T>>, (Option<Guard<T>>, Option<Box<T>>)> {
        // Convert the paramteres to raw pointers.
        // TODO: Use coercions.
        let new_ptr = new.as_mut().map_or(ptr::null_mut(), |x| &mut **x);
        let old_ptr = old.map_or(ptr::null_mut(), |x| x as *mut T);

        // Create the guard beforehand to avoid premature frees.
        let guard = Guard::maybe_new(|| {
            // The guard is active, so we can do the CAS now.
            unsafe { self.inner.compare_and_swap(old_ptr, new_ptr, ordering).as_ref() }
        });

        // Convert the guard to a raw pointer.
        // TODO: Use coercions.
        let guard_ptr = guard.as_ref().map_or(ptr::null_mut(), |x| &**x as *const T as *mut T);

        // Check if the CAS was successful.
        if guard_ptr == old_ptr {
            // It was. `self` is now `new`.

            // Ensure that the destructor of `new` is not run.
            mem::forget(new);

            // Queue the deletion of now-unreachable `old` (unless it's `None`).
            if !old_ptr.is_null() {
                local::add_garbage(unsafe { Garbage::new_box(old_ptr) });
            }

            Ok(guard)
        } else {
            // It failed; cast the raw pointer back to a box and return.
            Err((guard, new))
        }
    }
}

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

    use std::sync::{atomic, Arc};
    use std::thread;

    #[test]
    fn basic_properties() {
        let opt = AtomicOption::default();
        assert!(opt.load(atomic::Relaxed).is_none());
        assert!(opt.swap(None, atomic::Relaxed).is_none());
        assert!(opt.load(atomic::Relaxed).is_none());
        assert!(opt.swap(Some(Box::new(42)), atomic::Relaxed).is_none());
        assert_eq!(*opt.load(atomic::Relaxed).unwrap(), 42);
        assert_eq!(*opt.swap(Some(Box::new(43)), atomic::Relaxed).unwrap(), 42);
        assert_eq!(*opt.load(atomic::Relaxed).unwrap(), 43);
    }

    #[test]
    fn cas() {
        let bx1 = Box::new(1);
        let ptr1 = &*bx1;
        let bx2 = Box::new(1);
        let ptr2 = &*bx2;

        let opt = AtomicOption::new(Some(bx1));
        assert_eq!(&*opt.compare_and_swap(Some(ptr2), None, atomic::Ordering::Relaxed).unwrap_err().0.unwrap(), ptr1);
        assert_eq!(opt.load(atomic::Relaxed), ptr1);

        assert_eq!(&*opt.compare_and_swap(None, Some(Box::new(2)), atomic::Ordering::Relaxed).unwrap_err().0.unwrap(), ptr1);
        assert_eq!(opt.load(atomic::Relaxed), ptr1);

        opt.compare_and_swap(Some(ptr1), None, atomic::Ordering::Relaxed).unwrap();
        assert!(opt.load(atomic::Relaxed).is_none());

        opt.compare_and_swap(None, Some(bx2), atomic::Ordering::Relaxed).unwrap();
        assert_eq!(opt.load(atomic::Relaxed), ptr2);

        opt.compare_and_store(Some(ptr2), None, atomic::Ordering::Relaxed).unwrap();
        opt.compare_and_store(Some(Box::new(2)), None, atomic::Ordering::Relaxed).unwrap_err();

        assert!(opt.load(atomic::Relaxed).is_none());

        // To check that GC doesn't segfault or something.
        ::gc();
        ::gc();
        ::gc();
        ::gc();
    }

    #[test]
    fn spam() {
        let opt = Arc::new(concurrent::Option::default());

        let j = Vec::new();
        for i in 0..16 {
            let opt = opt.clone();
            j.push(thread::spawn(move || {
                for i in 0..1_000_000 {
                    let x = opt.load(atomic::Ordering::Relaxed);
                    opt.store(Some(Box::new(i)));
                }
                opt
            }))
        }

        ::gc();

        for i in j {
            i.join().unwrap();
        }

        assert_eq!(*opt.load(atomic::Ordering::Relaxed).unwrap(), 1_000_000);
    }

    #[test]
    fn drop() {
        #[begin(Clone)]
        struct Dropper {
            d: Arc<AtomicUsize>,
        }

        impl Drop for Dropper {
            fn drop(&mut self) {
                self.d.fetch_add(1, atomic::Ordering::Relaxed);
            }
        }

        let drops = Arc::new(AtomicUsize::default());
        let opt = Arc::new(concurrent::Option::default());

        let j = Vec::new();
        for i in 0..16 {
            let d = Dropper {
                d: drops.clone(),
            };

            let opt = opt.clone();

            j.push(thread::spawn(move || {
                for _ in 0..1_000_000 {
                    opt.store(Some(d.clone()));
                }
            }))
        }

        for i in j {
            i.join().unwrap();
        }

        opt.store(None);

        ::gc();

        assert_eq!(drops.load(atomic::Ordering::Relaxed), 16_000_000);
    }
}
<|endoftext|>


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

use rand;
use rand::Rng;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::hash_state::DefaultState;
use std::default::Default;
use std::hash::{Hash, Hasher, SipHasher};
use std::slice::Iter;

pub struct HashCache<K, V> {
    entries: HashMap<K, V, DefaultState<SipHasher>>,
}

impl<K, V> HashCache<K, V>
    where K: Clone + PartialEq + Eq + Hash,
          V: Clone,
{
    pub fn new() -> HashCache<K, V> {
        HashCache {
          entries: HashMap::with_hash_state(<DefaultState<SipHasher> as Default>::default()),
        }
    }

    pub fn insert(&mut self, key: K, value: V) {
        self.entries.insert(key, value);
    }

    pub fn find(&self, key: &K) -> Option<V> {
        match self.entries.get(key) {
            Some(v) => Some(v.clone()),
            None => None,
        }
    }

    pub fn find_or_create<F>(&mut self, key: &K, blk: F) -> V where F: Fn(&K) -> V {
        match self.entries.entry(key.clone()) {
            Occupied(occupied) => {
                (*occupied.get()).clone()
            }
            Vacant(vacant) => {
                (*vacant.insert(blk(key))).clone()
            }
        }
    }

    pub fn evict_all(&mut self) {
        self.entries.clear();
    }
}

pub struct LRUCache<K, V> {
    entries: Vec<(K, V)>,
    cache_size: usize,
}

impl<K: Clone + PartialEq, V: Clone> LRUCache<K, V> {
    pub fn new(size: usize) -> LRUCache<K, V> {
        LRUCache {
          entries: vec!(),
          cache_size: size,
        }
    }

    #[inline]
    pub fn touch(&mut self, pos: usize) -> V {
        let last_index = self.entries.len() - 1;
        if pos != last_index {
            let entry = self.entries.remove(pos);
            self.entries.push(entry);
        }
        self.entries[last_index].1.clone()
    }

    pub fn iter(&self) -> Iter<(K, V)> {
        self.entries.iter()
    }

    pub fn insert(&mut self, key: K, val: V) {
        if self.entries.len() == self.cache_size {
            self.entries.remove(0);
        }
        self.entries.push((key, val));
    }

    pub fn find(&mut self, key: &K) -> Option<V> {
        match self.entries.iter().position(|&(ref k, _)| key == k) {
            Some(pos) => Some(self.touch(pos)),
            None      => None,
        }
    }

    pub fn find_or_create<F>(&mut self, key: &K, blk: F) -> V where F: Fn(&K) -> V {
        match self.entries.iter().position(|&(ref k, _)| *k == *key) {
            Some(pos) => self.touch(pos),
            None => {
                let val = blk(key);
                self.insert(key.clone(), val.clone());
                val
            }
        }
    }

    pub fn evict_all(&mut self) {
        self.entries.clear();
    }
}

pub struct SimpleHashCache<K, V> {
    entries: Vec<Option<(K, V)>>,
    k0: u64,
    k1: u64,
}

impl<K: Clone + Eq + Hash, V: Clone> SimpleHashCache<K, V> {
    pub fn new(cache_size: usize) -> SimpleHashCache<K, V> {
        let mut r = rand::thread_rng();
        SimpleHashCache {
            entries: vec![None; cache_size],
            k0: r.gen(),
            k1: r.gen(),
        }
    }

    #[inline]
    fn to_bucket(&self, h: usize) -> usize {
        h % self.entries.len()
    }

    #[inline]
    fn bucket_for_key<Q: Hash>(&self, key: &Q) -> usize {
        let mut hasher = SipHasher::new_with_keys(self.k0, self.k1);
        key.hash(&mut hasher);
        self.to_bucket(hasher.finish() as usize)
    }

    pub fn insert(&mut self, key: K, value: V) {
        let bucket_index = self.bucket_for_key(&key);
        self.entries[bucket_index] = Some((key, value));
    }

    pub fn find<Q>(&self, key: &Q) -> Option<V> where Q: PartialEq<K> + Hash + Eq {
        let bucket_index = self.bucket_for_key(key);
        match self.entries[bucket_index] {
            Some((ref existing_key, ref value)) if key == existing_key => Some((*value).clone()),
            _ => None,
        }
    }

    pub fn find_or_create<F>(&mut self, key: &K, blk: F) -> V where F: Fn(&K) -> V {
        match self.find(key) {
            Some(value) => return value,
            None => {}
        }
        let value = blk(key);
        self.insert((*key).clone(), value.clone());
        value
    }

    pub fn evict_all(&mut self) {
        for slot in &mut self.entries {
            *slot = None
        }
    }
}
<commit_msg>HashCache: Apply trait bounds on type itself, rather than only the impl<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use rand;
use rand::Rng;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::hash_state::DefaultState;
use std::default::Default;
use std::hash::{Hash, Hasher, SipHasher};
use std::slice::Iter;

pub struct HashCache<K, V>
    where K: Clone + PartialEq + Eq + Hash,
          V: Clone,
{
    entries: HashMap<K, V, DefaultState<SipHasher>>,
}

impl<K, V> HashCache<K, V>
    where K: Clone + PartialEq + Eq + Hash,
          V: Clone,
{
    pub fn new() -> HashCache<K, V> {
        HashCache {
          entries: HashMap::with_hash_state(<DefaultState<SipHasher> as Default>::default()),
        }
    }

    pub fn insert(&mut self, key: K, value: V) {
        self.entries.insert(key, value);
    }

    pub fn find(&self, key: &K) -> Option<V> {
        match self.entries.get(key) {
            Some(v) => Some(v.clone()),
            None => None,
        }
    }

    pub fn find_or_create<F>(&mut self, key: &K, blk: F) -> V where F: Fn(&K) -> V {
        match self.entries.entry(key.clone()) {
            Occupied(occupied) => {
                (*occupied.get()).clone()
            }
            Vacant(vacant) => {
                (*vacant.insert(blk(key))).clone()
            }
        }
    }

    pub fn evict_all(&mut self) {
        self.entries.clear();
    }
}

pub struct LRUCache<K, V> {
    entries: Vec<(K, V)>,
    cache_size: usize,
}

impl<K: Clone + PartialEq, V: Clone> LRUCache<K, V> {
    pub fn new(size: usize) -> LRUCache<K, V> {
        LRUCache {
          entries: vec!(),
          cache_size: size,
        }
    }

    #[inline]
    pub fn touch(&mut self, pos: usize) -> V {
        let last_index = self.entries.len() - 1;
        if pos != last_index {
            let entry = self.entries.remove(pos);
            self.entries.push(entry);
        }
        self.entries[last_index].1.clone()
    }

    pub fn iter(&self) -> Iter<(K, V)> {
        self.entries.iter()
    }

    pub fn insert(&mut self, key: K, val: V) {
        if self.entries.len() == self.cache_size {
            self.entries.remove(0);
        }
        self.entries.push((key, val));
    }

    pub fn find(&mut self, key: &K) -> Option<V> {
        match self.entries.iter().position(|&(ref k, _)| key == k) {
            Some(pos) => Some(self.touch(pos)),
            None      => None,
        }
    }

    pub fn find_or_create<F>(&mut self, key: &K, blk: F) -> V where F: Fn(&K) -> V {
        match self.entries.iter().position(|&(ref k, _)| *k == *key) {
            Some(pos) => self.touch(pos),
            None => {
                let val = blk(key);
                self.insert(key.clone(), val.clone());
                val
            }
        }
    }

    pub fn evict_all(&mut self) {
        self.entries.clear();
    }
}

pub struct SimpleHashCache<K, V> {
    entries: Vec<Option<(K, V)>>,
    k0: u64,
    k1: u64,
}

impl<K: Clone + Eq + Hash, V: Clone> SimpleHashCache<K, V> {
    pub fn new(cache_size: usize) -> SimpleHashCache<K, V> {
        let mut r = rand::thread_rng();
        SimpleHashCache {
            entries: vec![None; cache_size],
            k0: r.gen(),
            k1: r.gen(),
        }
    }

    #[inline]
    fn to_bucket(&self, h: usize) -> usize {
        h % self.entries.len()
    }

    #[inline]
    fn bucket_for_key<Q: Hash>(&self, key: &Q) -> usize {
        let mut hasher = SipHasher::new_with_keys(self.k0, self.k1);
        key.hash(&mut hasher);
        self.to_bucket(hasher.finish() as usize)
    }

    pub fn insert(&mut self, key: K, value: V) {
        let bucket_index = self.bucket_for_key(&key);
        self.entries[bucket_index] = Some((key, value));
    }

    pub fn find<Q>(&self, key: &Q) -> Option<V> where Q: PartialEq<K> + Hash + Eq {
        let bucket_index = self.bucket_for_key(key);
        match self.entries[bucket_index] {
            Some((ref existing_key, ref value)) if key == existing_key => Some((*value).clone()),
            _ => None,
        }
    }

    pub fn find_or_create<F>(&mut self, key: &K, blk: F) -> V where F: Fn(&K) -> V {
        match self.find(key) {
            Some(value) => return value,
            None => {}
        }
        let value = blk(key);
        self.insert((*key).clone(), value.clone());
        value
    }

    pub fn evict_all(&mut self) {
        for slot in &mut self.entries {
            *slot = None
        }
    }
}
<|endoftext|>


<commit_before>extern crate mysqlclient_sys as ffi;

mod iterator;
mod metadata;

use std::ffi::CStr;
use std::os::raw as libc;
use std::ptr::NonNull;

use self::iterator::*;
use self::metadata::*;
use super::bind::Binds;
use crate::mysql::MysqlTypeMetadata;
use crate::result::{DatabaseErrorKind, QueryResult};

pub struct Statement {
    stmt: NonNull<ffi::MYSQL_STMT>,
    input_binds: Option<Binds>,
}

impl Statement {
    pub(crate) fn new(stmt: NonNull<ffi::MYSQL_STMT>) -> Self {
        Statement {
            stmt: stmt,
            input_binds: None,
        }
    }

    pub fn prepare(&self, query: &str) -> QueryResult<()> {
        unsafe {
            ffi::mysql_stmt_prepare(
                self.stmt.as_ptr(),
                query.as_ptr() as *const libc::c_char,
                query.len() as libc::c_ulong,
            );
        }
        self.did_an_error_occur()
    }

    pub fn bind<Iter>(&mut self, binds: Iter) -> QueryResult<()>
    where
        Iter: IntoIterator<Item = (MysqlTypeMetadata, Option<Vec<u8>>)>,
    {
        let mut input_binds = Binds::from_input_data(binds);
        input_binds.with_mysql_binds(|bind_ptr| {
            // This relies on the invariant that the current value of `self.input_binds`
            // will not change without this function being called
            unsafe {
                ffi::mysql_stmt_bind_param(self.stmt.as_ptr(), bind_ptr);
            }
        });
        self.input_binds = Some(input_binds);
        self.did_an_error_occur()
    }

    /// This function should be called instead of `results` on queries which
    /// have no return value. It should never be called on a statement on
    /// which `results` has previously been called?
    pub unsafe fn execute(&self) -> QueryResult<()> {
        ffi::mysql_stmt_execute(self.stmt.as_ptr());
        self.did_an_error_occur()?;
        ffi::mysql_stmt_store_result(self.stmt.as_ptr());
        self.did_an_error_occur()?;
        Ok(())
    }

    pub fn affected_rows(&self) -> usize {
        let affected_rows = unsafe { ffi::mysql_stmt_affected_rows(self.stmt.as_ptr()) };
        affected_rows as usize
    }

    /// This function should be called instead of `execute` for queries which
    /// have a return value. After calling this function, `execute` can never
    /// be called on this statement.
    pub unsafe fn results(
        &mut self,
        types: Vec<MysqlTypeMetadata>,
    ) -> QueryResult<StatementIterator> {
        StatementIterator::new(self, types)
    }

    /// This function should be called instead of `execute` for queries which
    /// have a return value. After calling this function, `execute` can never
    /// be called on this statement.
    pub unsafe fn named_results(&mut self) -> QueryResult<NamedStatementIterator> {
        NamedStatementIterator::new(self)
    }

    fn last_error_message(&self) -> String {
        unsafe { CStr::from_ptr(ffi::mysql_stmt_error(self.stmt.as_ptr())) }
            .to_string_lossy()
            .into_owned()
    }

    /// If the pointers referenced by the `MYSQL_BIND` structures are invalidated,
    /// you must call this function again before calling `mysql_stmt_fetch`.
    pub unsafe fn bind_result(&self, binds: *mut ffi::MYSQL_BIND) -> QueryResult<()> {
        ffi::mysql_stmt_bind_result(self.stmt.as_ptr(), binds);
        self.did_an_error_occur()
    }

    pub unsafe fn fetch_column(
        &self,
        bind: &mut ffi::MYSQL_BIND,
        idx: usize,
        offset: usize,
    ) -> QueryResult<()> {
        ffi::mysql_stmt_fetch_column(
            self.stmt.as_ptr(),
            bind,
            idx as libc::c_uint,
            offset as libc::c_ulong,
        );
        self.did_an_error_occur()
    }

    fn metadata(&self) -> QueryResult<StatementMetadata> {
        use crate::result::Error::DeserializationError;

        let result_ptr = unsafe { ffi::mysql_stmt_result_metadata(self.stmt.as_ptr()).as_mut() };
        self.did_an_error_occur()?;
        result_ptr
            .map(StatementMetadata::new)
            .ok_or_else(|| DeserializationError("No metadata exists".into()))
    }

    fn did_an_error_occur(&self) -> QueryResult<()> {
        use crate::result::Error::DatabaseError;

        let error_message = self.last_error_message();
        if error_message.is_empty() {
            Ok(())
        } else {
            Err(DatabaseError(
                self.last_error_type(),
                Box::new(error_message),
            ))
        }
    }

    fn last_error_type(&self) -> DatabaseErrorKind {
        let last_error_number = unsafe { ffi::mysql_stmt_errno(self.stmt.as_ptr()) };
        // These values are not exposed by the C API, but are documented
        // at https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
        // and are from the ANSI SQLSTATE standard
        match last_error_number {
            1062 | 1586 | 1859 => DatabaseErrorKind::UniqueViolation,
            1216 | 1217 | 1451 | 1452 | 1830 | 1834 => DatabaseErrorKind::ForeignKeyViolation,
            1792 => DatabaseErrorKind::ReadOnlyTransaction,
            _ => DatabaseErrorKind::__Unknown,
        }
    }
}

impl Drop for Statement {
    fn drop(&mut self) {
        unsafe { ffi::mysql_stmt_close(self.stmt.as_ptr()) };
    }
}
<commit_msg>Error code link is dead, replace it with '8.0' version<commit_after>extern crate mysqlclient_sys as ffi;

mod iterator;
mod metadata;

use std::ffi::CStr;
use std::os::raw as libc;
use std::ptr::NonNull;

use self::iterator::*;
use self::metadata::*;
use super::bind::Binds;
use crate::mysql::MysqlTypeMetadata;
use crate::result::{DatabaseErrorKind, QueryResult};

pub struct Statement {
    stmt: NonNull<ffi::MYSQL_STMT>,
    input_binds: Option<Binds>,
}

impl Statement {
    pub(crate) fn new(stmt: NonNull<ffi::MYSQL_STMT>) -> Self {
        Statement {
            stmt: stmt,
            input_binds: None,
        }
    }

    pub fn prepare(&self, query: &str) -> QueryResult<()> {
        unsafe {
            ffi::mysql_stmt_prepare(
                self.stmt.as_ptr(),
                query.as_ptr() as *const libc::c_char,
                query.len() as libc::c_ulong,
            );
        }
        self.did_an_error_occur()
    }

    pub fn bind<Iter>(&mut self, binds: Iter) -> QueryResult<()>
    where
        Iter: IntoIterator<Item = (MysqlTypeMetadata, Option<Vec<u8>>)>,
    {
        let mut input_binds = Binds::from_input_data(binds);
        input_binds.with_mysql_binds(|bind_ptr| {
            // This relies on the invariant that the current value of `self.input_binds`
            // will not change without this function being called
            unsafe {
                ffi::mysql_stmt_bind_param(self.stmt.as_ptr(), bind_ptr);
            }
        });
        self.input_binds = Some(input_binds);
        self.did_an_error_occur()
    }

    /// This function should be called instead of `results` on queries which
    /// have no return value. It should never be called on a statement on
    /// which `results` has previously been called?
    pub unsafe fn execute(&self) -> QueryResult<()> {
        ffi::mysql_stmt_execute(self.stmt.as_ptr());
        self.did_an_error_occur()?;
        ffi::mysql_stmt_store_result(self.stmt.as_ptr());
        self.did_an_error_occur()?;
        Ok(())
    }

    pub fn affected_rows(&self) -> usize {
        let affected_rows = unsafe { ffi::mysql_stmt_affected_rows(self.stmt.as_ptr()) };
        affected_rows as usize
    }

    /// This function should be called instead of `execute` for queries which
    /// have a return value. After calling this function, `execute` can never
    /// be called on this statement.
    pub unsafe fn results(
        &mut self,
        types: Vec<MysqlTypeMetadata>,
    ) -> QueryResult<StatementIterator> {
        StatementIterator::new(self, types)
    }

    /// This function should be called instead of `execute` for queries which
    /// have a return value. After calling this function, `execute` can never
    /// be called on this statement.
    pub unsafe fn named_results(&mut self) -> QueryResult<NamedStatementIterator> {
        NamedStatementIterator::new(self)
    }

    fn last_error_message(&self) -> String {
        unsafe { CStr::from_ptr(ffi::mysql_stmt_error(self.stmt.as_ptr())) }
            .to_string_lossy()
            .into_owned()
    }

    /// If the pointers referenced by the `MYSQL_BIND` structures are invalidated,
    /// you must call this function again before calling `mysql_stmt_fetch`.
    pub unsafe fn bind_result(&self, binds: *mut ffi::MYSQL_BIND) -> QueryResult<()> {
        ffi::mysql_stmt_bind_result(self.stmt.as_ptr(), binds);
        self.did_an_error_occur()
    }

    pub unsafe fn fetch_column(
        &self,
        bind: &mut ffi::MYSQL_BIND,
        idx: usize,
        offset: usize,
    ) -> QueryResult<()> {
        ffi::mysql_stmt_fetch_column(
            self.stmt.as_ptr(),
            bind,
            idx as libc::c_uint,
            offset as libc::c_ulong,
        );
        self.did_an_error_occur()
    }

    fn metadata(&self) -> QueryResult<StatementMetadata> {
        use crate::result::Error::DeserializationError;

        let result_ptr = unsafe { ffi::mysql_stmt_result_metadata(self.stmt.as_ptr()).as_mut() };
        self.did_an_error_occur()?;
        result_ptr
            .map(StatementMetadata::new)
            .ok_or_else(|| DeserializationError("No metadata exists".into()))
    }

    fn did_an_error_occur(&self) -> QueryResult<()> {
        use crate::result::Error::DatabaseError;

        let error_message = self.last_error_message();
        if error_message.is_empty() {
            Ok(())
        } else {
            Err(DatabaseError(
                self.last_error_type(),
                Box::new(error_message),
            ))
        }
    }

    fn last_error_type(&self) -> DatabaseErrorKind {
        let last_error_number = unsafe { ffi::mysql_stmt_errno(self.stmt.as_ptr()) };
        // These values are not exposed by the C API, but are documented
        // at https://dev.mysql.com/doc/refman/8.0/en/server-error-reference.html
        // and are from the ANSI SQLSTATE standard
        match last_error_number {
            1062 | 1586 | 1859 => DatabaseErrorKind::UniqueViolation,
            1216 | 1217 | 1451 | 1452 | 1830 | 1834 => DatabaseErrorKind::ForeignKeyViolation,
            1792 => DatabaseErrorKind::ReadOnlyTransaction,
            _ => DatabaseErrorKind::__Unknown,
        }
    }
}

impl Drop for Statement {
    fn drop(&mut self) {
        unsafe { ffi::mysql_stmt_close(self.stmt.as_ptr()) };
    }
}
<|endoftext|>


<commit_before>//! Endpoints for managing room aliases.

use iron::{Chain, Handler, IronResult, Request, Response};
use iron::status::Status;
use router::Router;

use db::DB;
use error::APIError;
use middleware::AccessTokenAuth;
use modifier::SerializableResponse;
use room_alias::RoomAlias;

#[derive(Debug, Serialize)]
struct GetDirectoryRoomResponse {
    room_id: String,
    servers: Vec<String>,
}

/// The /directory/room/{roomAlias} endpoint when using the GET method.
pub struct GetDirectoryRoom;

impl GetDirectoryRoom {
    /// Create a `DirectoryRoom`.
    pub fn chain() -> Chain {
        let mut chain = Chain::new(GetDirectoryRoom);

        chain.link_before(AccessTokenAuth);

        chain
    }
}

impl Handler for GetDirectoryRoom {
    fn handle(&self, request: &mut Request) -> IronResult<Response> {
        let params = request.extensions.get::<Router>().expect("Params object is missing").clone();

        let room_alias_name = params.find("room_alias").ok_or(APIError::not_found())?;

        let connection = DB::from_request(request)?;

        let room_alias = RoomAlias::find_by_alias(&connection, room_alias_name)?;

        let response = GetDirectoryRoomResponse {
            room_id: room_alias.room_id,
            servers: room_alias.servers,
        };

        Ok(Response::with((Status::Ok, SerializableResponse(response))))
    }
}

#[cfg(test)]
mod tests {
    use test::Test;
    use iron::status::Status;

    #[test]
    fn get_room_alias() {
        let test = Test::new();
        let access_token = test.create_access_token();

        let create_room_path = format!("/_matrix/client/r0/createRoom?access_token={}",
                                       access_token);
        let response = test.post(&create_room_path, r#"{"room_alias_name": "my_room"}"#);
        let room_id = response.json().find("room_id").unwrap().as_string();

        let get_room_alias_path = format!(
            "/_matrix/client/r0/directory/room/my_room?access_token={}", access_token
        );
        let response = test.get(&get_room_alias_path);

        assert_eq!(response.json().find("room_id").unwrap().as_string(), room_id);
        assert!(response.json().find("servers").unwrap().is_array());
    }

    #[test]
    fn get_unknown_room_alias() {
        let test = Test::new();
        let access_token = test.create_access_token();

        let create_room_path = format!("/_matrix/client/r0/createRoom?access_token={}",
                                       access_token);
        let _ = test.post(&create_room_path, r#"{"room_alias_name": "my_room"}"#);

        let get_room_alias_path = format!(
            "/_matrix/client/r0/directory/room/no_room?access_token={}", access_token
        );
        let response = test.get(&get_room_alias_path);

        assert_eq!(response.status, Status::NotFound);
        assert_eq!(
            response.json().find("errcode").unwrap().as_string().unwrap(),
            "M_NOT_FOUND"
        );
    }
}
<commit_msg>Revert ae2ced5 and fix tests<commit_after>//! Endpoints for managing room aliases.

use iron::{Chain, Handler, IronResult, Request, Response};
use iron::status::Status;
use router::Router;

use db::DB;
use error::APIError;
use modifier::SerializableResponse;
use room_alias::RoomAlias;

#[derive(Debug, Serialize)]
struct GetDirectoryRoomResponse {
    room_id: String,
    servers: Vec<String>,
}

/// The /directory/room/{roomAlias} endpoint when using the GET method.
pub struct GetDirectoryRoom;

impl GetDirectoryRoom {
    /// Create a `DirectoryRoom`.
    pub fn chain() -> Chain {
        Chain::new(GetDirectoryRoom)
    }
}

impl Handler for GetDirectoryRoom {
    fn handle(&self, request: &mut Request) -> IronResult<Response> {
        let params = request.extensions.get::<Router>().expect("Params object is missing").clone();

        let room_alias_name = params.find("room_alias").ok_or(APIError::not_found())?;

        let connection = DB::from_request(request)?;

        let room_alias = RoomAlias::find_by_alias(&connection, room_alias_name)?;

        let response = GetDirectoryRoomResponse {
            room_id: room_alias.room_id,
            servers: room_alias.servers,
        };

        Ok(Response::with((Status::Ok, SerializableResponse(response))))
    }
}

#[cfg(test)]
mod tests {
    use test::Test;
    use iron::status::Status;

    #[test]
    fn get_room_alias() {
        let test = Test::new();
        let access_token = test.create_access_token();

        let create_room_path = format!("/_matrix/client/r0/createRoom?access_token={}",
                                       access_token);
        let response = test.post(&create_room_path, r#"{"room_alias_name": "my_room"}"#);
        let room_id = response.json().find("room_id").unwrap().as_string();

        let response = test.get("/_matrix/client/r0/directory/room/my_room");

        assert_eq!(response.json().find("room_id").unwrap().as_string(), room_id);
        assert!(response.json().find("servers").unwrap().is_array());
    }

    #[test]
    fn get_unknown_room_alias() {
        let test = Test::new();
        let access_token = test.create_access_token();

        let create_room_path = format!("/_matrix/client/r0/createRoom?access_token={}",
                                       access_token);
        let _ = test.post(&create_room_path, r#"{"room_alias_name": "my_room"}"#);

        let response = test.get("/_matrix/client/r0/directory/room/no_room");

        assert_eq!(response.status, Status::NotFound);
        assert_eq!(
            response.json().find("errcode").unwrap().as_string().unwrap(),
            "M_NOT_FOUND"
        );
    }
}
<|endoftext|>


<commit_before>// Copyright Dan Schatzberg, 2015. This file is part of Genesis.

// Genesis is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Genesis is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with Genesis.  If not, see <http://www.gnu.org/licenses/>.
use super::serial;
use core::mem::{size_of, transmute};
use core::slice;
use fixedvec::FixedVec;
use mem::PAddr;
use multiboot::{self, MemoryType, Multiboot};
use spin;

unsafe fn early_paddr_to_slice<'a>(p: multiboot::PAddr,
                                   sz: usize)
                                   -> Option<&'a [u8]> {
    if (sz < (1 << 30)) && ((p + sz as u64) < (1 << 30)) {
        let ptr = transmute(p + 0xFFFFFFFFC0000000);
        Some(slice::from_raw_parts(ptr, sz))
    } else {
        None
    }
}

#[derive(Clone, Copy, Debug, Default)]
struct MemoryRegion {
    start: PAddr,
    end: PAddr,
}

lazy_static! {
    static ref REGIONS: spin::RwLock<FixedVec<'static, MemoryRegion>> = {
        const REGIONS_SIZE: usize = 4096;
        static mut REGIONS_MEM: [u8; REGIONS_SIZE] = [0; REGIONS_SIZE];
        let region_slice = unsafe {
            let ptr = transmute(REGIONS_MEM.as_mut_ptr());
            let sz = REGIONS_SIZE / size_of::<MemoryRegion>();
            slice::from_raw_parts_mut(ptr, sz)
        };

        spin::RwLock::new(FixedVec::new(region_slice))
    };
}

/// Initial Rust entry point.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) -> ! {
    unsafe {
        serial::init();
    }
    debug!("Serial Initialized");
    info!("Multiboot Structure loaded at {:#X}", multiboot_addr);
    let mb = unsafe {
                 Multiboot::new(multiboot_addr.as_u64(), early_paddr_to_slice)
             }
             .expect("Could not access a Multiboot structure");
    let mem_regions = mb.memory_regions()
                        .expect("Could not find Multiboot memory map");

    let mut vec = REGIONS.write();

    for region in mem_regions {
        let start = PAddr::from_u64(region.base_address());
        let end = PAddr::from_u64(region.base_address() + region.length());
        let mem_type = match region.memory_type() {
            MemoryType::RAM => "RAM",
            MemoryType::Unusable => "Unusable",
        };
        info!("{:#17X} - {:#17X}: {}", start, end, mem_type);
        if region.memory_type() == MemoryType::RAM {
            if let Err(e) = vec.push(MemoryRegion {
                start: start,
                end: end,
            }) {
                warn!("Could not store usable region {:#?}: {:?}", region, e);
            }
        }
    }

    for region in vec.iter() {
        debug!("{:?}", region);
    }

    loop {}
}
<commit_msg>Refactor memory discovery<commit_after>// Copyright Dan Schatzberg, 2015. This file is part of Genesis.

// Genesis is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Genesis is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with Genesis.  If not, see <http://www.gnu.org/licenses/>.
use super::serial;
use core::mem::{size_of, transmute};
use core::slice;
use fixedvec::FixedVec;
use mem::PAddr;
use multiboot::{self, MemoryType, Multiboot};
use spin;

unsafe fn early_paddr_to_slice<'a>(p: multiboot::PAddr,
                                   sz: usize)
                                   -> Option<&'a [u8]> {
    if (sz < (1 << 30)) && ((p + sz as u64) < (1 << 30)) {
        let ptr = transmute(p + 0xFFFFFFFFC0000000);
        Some(slice::from_raw_parts(ptr, sz))
    } else {
        None
    }
}

#[derive(Clone, Copy, Debug, Default)]
struct MemoryRegion {
    start: PAddr,
    end: PAddr,
}

lazy_static! {
    static ref REGIONS: spin::RwLock<FixedVec<'static, MemoryRegion>> = {
        const REGIONS_SIZE: usize = 4096;
        static mut REGIONS_MEM: [u8; REGIONS_SIZE] = [0; REGIONS_SIZE];
        let region_slice = unsafe {
            let ptr = transmute(REGIONS_MEM.as_mut_ptr());
            let sz = REGIONS_SIZE / size_of::<MemoryRegion>();
            slice::from_raw_parts_mut(ptr, sz)
        };

        spin::RwLock::new(FixedVec::new(region_slice))
    };
}

/// Initial Rust entry point.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) -> ! {
    unsafe {
        serial::init();
    }
    debug!("Serial Initialized");
    debug!("Multiboot Structure loaded at {:#X}", multiboot_addr);
    let mb = unsafe {
                 Multiboot::new(multiboot_addr.as_u64(), early_paddr_to_slice)
             }
             .expect("Could not access a Multiboot structure");

    discover_memory(&mb);

    loop {}
}

/// Discover available memory from the Multiboot structure
fn discover_memory(mb: &Multiboot) -> () {
    let mem_regions = mb.memory_regions()
                        .expect("Could not find Multiboot memory map");

    let mut vec = REGIONS.write();

    info!("Memory Map:");
    for region in mem_regions {
        let start = PAddr::from_u64(region.base_address());
        let end = PAddr::from_u64(region.base_address() + region.length());
        let mem_type = match region.memory_type() {
            MemoryType::RAM => "RAM",
            MemoryType::Unusable => "Unusable",
        };
        info!("{:#17X} - {:#17X}: {}", start, end, mem_type);
        if region.memory_type() == MemoryType::RAM {
            if let Err(e) = vec.push(MemoryRegion {
                start: start,
                end: end,
            }) {
                warn!("Could not store usable region {:#?}: {:?}", region, e);
            }
        }
    }

    for region in vec.iter() {
        debug!("{:?}", region);
    }
}
<|endoftext|>


<commit_before>/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module

use super::idt::{IDTR, IDT};

#[naked]
#[no_mangle]
pub unsafe extern fn kmain() {
    asm!("xchg bx, bx" : : : : "intel", "volatile");

    for entry in IDT.iter_mut() {
        entry.attribute = 1 << 7 | 0xE;
        entry.selector = 8;
        entry.set_offset(&blank as *const _ as usize);
        entry.zero = 0;
        entry.zero2 = 0;
    }
    IDTR.set_slice(&IDT);
    asm!("lidt [rax]" : : "{rax}"(&IDTR as *const _ as usize) : : "intel", "volatile");

    asm!("xchg bx, bx" : : : : "intel", "volatile");

    asm!("int 0xFF" : : : : "intel", "volatile");

    loop{
        asm!("hlt" : : : : "intel", "volatile");
    }
}

#[naked]
pub unsafe extern fn blank() {
    asm!("xchg bx, bx" : : : : "intel", "volatile");
    asm!("iretq" : : : : "intel", "volatile");
}
<commit_msg>Interrupt handling!<commit_after>/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module

use super::idt::{IDTR, IDT};

#[naked]
#[no_mangle]
pub unsafe extern "C" fn kmain() {
    asm!("xchg bx, bx" : : : : "intel", "volatile");

    for entry in IDT.iter_mut() {
        entry.attribute = 1 << 7 | 0xE;
        entry.selector = 8;
        entry.set_offset(blank as usize);
        entry.zero = 0;
        entry.zero2 = 0;
    }
    IDTR.set_slice(&IDT);
    asm!("lidt [rax]" : : "{rax}"(&IDTR as *const _ as usize) : : "intel", "volatile");

    asm!("xchg bx, bx" : : : : "intel", "volatile");

    asm!("int 0xFF" : : : : "intel", "volatile");

    loop{
        asm!("hlt" : : : : "intel", "volatile");
    }
}

#[naked]
pub unsafe extern "C" fn blank() {
    asm!("xchg bx, bx" : : : : "intel", "volatile");
    asm!("iretq" : : : : "intel", "volatile");
}
<|endoftext|>


<commit_before>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::fs::File;
use std::path::Path;

use super::common::*;

static FFI_MOD: &'static str = "ffi";

fn make_enum(f: &mut File, enum_name: &str, variants: &[&str], ffi_mod: &str) {
    make_simple_enum(f, enum_name, variants);
    make_simple_into(f, enum_name, variants, ffi_mod);
}

pub fn generate() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path =  Path::new(&out_dir).join("demux-enums.rs");
    let mut f = File::create(&dest_path).unwrap();

    make_enum(&mut f, "Input", &[
        "DMX_IN_FRONTEND",
        "DMX_IN_DVR"
    ], FFI_MOD);

    make_enum(&mut f, "Output", &[
        "DMX_OUT_DECODER",
        "DMX_OUT_TAP",
        "DMX_OUT_TS_TAP",
        "DMX_OUT_TSDEMUX_TAP"
    ], FFI_MOD);

    make_enum(&mut f, "PesType", &[
        "DMX_PES_AUDIO0",
        "DMX_PES_VIDEO0",
        "DMX_PES_TELETEXT0",
        "DMX_PES_SUBTITLE0",
        "DMX_PES_PCR0",
        "DMX_PES_AUDIO1",
        "DMX_PES_VIDEO1",
        "DMX_PES_TELETEXT1",
        "DMX_PES_SUBTITLE1",
        "DMX_PES_PCR1",
        "DMX_PES_AUDIO2",
        "DMX_PES_VIDEO2",
        "DMX_PES_TELETEXT2",
        "DMX_PES_SUBTITLE2",
        "DMX_PES_PCR2",
        "DMX_PES_AUDIO3",
        "DMX_PES_VIDEO3",
        "DMX_PES_TELETEXT3",
        "DMX_PES_SUBTITLE3",
        "DMX_PES_PCR3",
        "DMX_PES_OTHER"
    ], FFI_MOD);
}
<commit_msg>Add DemuxSource enum (dmx_source_t) to codegen.<commit_after>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::fs::File;
use std::path::Path;

use super::common::*;

static FFI_MOD: &'static str = "ffi";

fn make_enum(f: &mut File, enum_name: &str, variants: &[&str], ffi_mod: &str) {
    make_simple_enum(f, enum_name, variants);
    make_simple_into(f, enum_name, variants, ffi_mod);
}

pub fn generate() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path =  Path::new(&out_dir).join("demux-enums.rs");
    let mut f = File::create(&dest_path).unwrap();

    make_enum(&mut f, "Input", &[
        "DMX_IN_FRONTEND",
        "DMX_IN_DVR"
    ], FFI_MOD);

    make_enum(&mut f, "Output", &[
        "DMX_OUT_DECODER",
        "DMX_OUT_TAP",
        "DMX_OUT_TS_TAP",
        "DMX_OUT_TSDEMUX_TAP"
    ], FFI_MOD);

    make_enum(&mut f, "DemuxSource", &[
        "DMX_SOURCE_FRONT0",
        "DMX_SOURCE_FRONT1",
        "DMX_SOURCE_FRONT2",
        "DMX_SOURCE_FRONT3",
        "DMX_SOURCE_DVR0",
        "DMX_SOURCE_DVR1",
        "DMX_SOURCE_DVR2",
        "DMX_SOURCE_DVR3"
    ], FFI_MOD);

    make_enum(&mut f, "PesType", &[
        "DMX_PES_AUDIO0",
        "DMX_PES_VIDEO0",
        "DMX_PES_TELETEXT0",
        "DMX_PES_SUBTITLE0",
        "DMX_PES_PCR0",
        "DMX_PES_AUDIO1",
        "DMX_PES_VIDEO1",
        "DMX_PES_TELETEXT1",
        "DMX_PES_SUBTITLE1",
        "DMX_PES_PCR1",
        "DMX_PES_AUDIO2",
        "DMX_PES_VIDEO2",
        "DMX_PES_TELETEXT2",
        "DMX_PES_SUBTITLE2",
        "DMX_PES_PCR2",
        "DMX_PES_AUDIO3",
        "DMX_PES_VIDEO3",
        "DMX_PES_TELETEXT3",
        "DMX_PES_SUBTITLE3",
        "DMX_PES_PCR3",
        "DMX_PES_OTHER"
    ], FFI_MOD);
}
<|endoftext|>


<commit_before>use std;
use std::iter::Peekable;

use ::opcodes::{AddressingMode, OpCode};
use assembler::token::{LexerToken, ParserToken};

#[derive(Debug, PartialEq)]
pub struct ParserError {
    pub message: String,
}

impl ParserError {
    fn expected_instruction(line: u32) -> ParserError {
        ParserError::from(format!("Instruction expected. Line {}", line))
    }

    fn invalid_opcode_addressing_mode_combination(line: u32) -> ParserError {
        ParserError::from(format!("Invalid addressing mode for opcode. Line {}", line))
    }

    fn unexpected_eol(line: u32) -> ParserError {
        ParserError::from(format!("Unexpected end of line. Line {}", line))
    }

    fn expected_eol(line: u32) -> ParserError {
        ParserError::from(format!("Expected end of line. Line {}", line))
    }

    fn cannot_parse_address(line: u32) -> ParserError {
        ParserError::from(format!("Unable to parse address. Line {}", line))
    }

    fn unexpected_token(line: u32) -> ParserError {
        ParserError::from(format!("Unexpected token. Line {}", line))
    }
}

impl From<String> for ParserError {
    fn from(error: String) -> ParserError {
        ParserError { message: error }
    }
}

impl<'a> From<&'a str> for ParserError {
    fn from(error: &str) -> ParserError {
        ParserError { message: error.into() }
    }
}

pub struct Parser {
    line: u32,
}

/// Parser processes a list of 6502 Assembly tokens
impl Parser {
    pub fn new() -> Parser {
        Parser { line: 0 }
    }

    pub fn parse(&mut self, tokens: Vec<Vec<LexerToken>>) -> Result<Vec<ParserToken>, ParserError> {
        let mut result = Vec::new();

        for line in &tokens {
            self.line += 1;

            let mut peeker = line.iter().peekable();

            // Skip blank lines
            if let None = peeker.peek() {
                continue;
            }

            let next = *peeker.peek().unwrap();

            if let &LexerToken::Ident(ref ident) = next {
                // Check if this is an opcode
                if Self::is_opcode(ident.clone()) {
                    // Yep its an opcode, lets figure out its addressing mode
                    let mut opcode = self.consume_opcode(&mut peeker, ident.clone())?;
                    result.append(&mut opcode);
                } else {
                    // Skip the ident and we'll check what is next
                    let original_ident = peeker.next().unwrap();
                    // if there is nothing else - lets mark this as a Label and move on
                    if let None = peeker.peek() {
                        result.push(ParserToken::Label(ident.clone()));
                        continue;
                    }

                    // A colon after the ident also indicates a label
                    let next = *peeker.peek().unwrap();
                    if let &LexerToken::Colon = next {
                        result.push(ParserToken::Label(ident.clone()));
                        continue;
                    }

                    // Is the next one a label as well? Thats an error:
                    if let &LexerToken::Ident(ref ident) = next {
                        // Lets add the original as a label
                        if let &LexerToken::Ident(ref original_ident) = original_ident {
                            result.push(ParserToken::Label(original_ident.clone()));
                        }

                        if !Self::is_opcode(ident.clone()) {
                            return Err(ParserError::expected_instruction(self.line));
                        } else {
                            // Oh it is an opcode after the label - consume it
                            let mut opcode = self.consume_opcode(&mut peeker, ident.clone())?;
                            result.append(&mut opcode);
                        }
                    }
                }
            }
        }

        Ok(result)
    }

    fn is_opcode<S>(mnemonic: S) -> bool
        where S: Into<String>
    {
        if let Some(opcode) = OpCode::from_mnemonic(mnemonic) {
            true
        } else {
            false
        }
    }

    fn consume_opcode<'a, I, S>(&mut self,
                                mut peeker: &mut Peekable<I>,
                                ident: S)
                                -> Result<Vec<ParserToken>, ParserError>
        where I: Iterator<Item = &'a LexerToken>,
              S: Into<String> + std::fmt::Display
    {
        // Jump over the opcode
        peeker.next();

        // If there is nothing else after this opcode.. lets check if there is
        // a matching opcode with an implied addressing mode
        if let None = peeker.peek() {
            if let Some(opcode) =
                   OpCode::from_mnemonic_and_addressing_mode(ident, AddressingMode::Implied) {
                return Ok(vec![ParserToken::OpCode(opcode)]);
            } else {
                return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
            }
        } else {
            // Check the next token, is it an address?
            let next = *peeker.peek().unwrap();
            if let &LexerToken::Address(ref address) = next {
                // Its an address. What sort of address?
                if address.len() == 2 || address.len() == 4 {
                    // Its zero-page or absolute.. lets try and convert it to a raw byte
                    let (bytes, addressing_mode) = if address.len() == 2 {
                        // Its a 1 byte address
                        if let Ok(raw_byte) = u8::from_str_radix(&address[..], 16) {
                            (vec![raw_byte], AddressingMode::ZeroPage)
                        } else {
                            return Err(ParserError::cannot_parse_address(self.line));
                        }
                    } else {
                        // Its a 2 byte address
                        if let Ok(low_byte) = u8::from_str_radix(&address[2..], 16) {
                            if let Ok(high_byte) = u8::from_str_radix(&address[0..2], 16) {
                                (vec![low_byte, high_byte], AddressingMode::Absolute)
                            } else {
                                return Err(ParserError::cannot_parse_address(self.line));
                            }
                        } else {
                            return Err(ParserError::cannot_parse_address(self.line));
                        }
                    };
                    // consume the address and peek what is next:
                    peeker.next();
                    if let None = peeker.peek() {
                        // Nothing else.. find an opcode with this ident and addressing mode
                        if let Some(opcode) =
                               OpCode::from_mnemonic_and_addressing_mode(ident, addressing_mode) {
                            // We found one..
                            let mut final_vec = vec![ParserToken::OpCode(opcode)];
                            // Push the address bytes into the result
                            for b in bytes {
                                final_vec.push(ParserToken::RawByte(b));
                            }
                            return Ok(final_vec);
                        } else {
                            return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
                        }
                    }

                    // There is something after this address - if its
                    // a comma, then we're peachy. If its something else.. Thats
                    // an error.
                    let next = *peeker.peek().unwrap();
                    if let &LexerToken::Comma = next {
                        // Yes, its a comma. Consume it and check what is next
                        peeker.next();
                        // If theres nothing after the comma thats an error
                        if let None = peeker.peek() {
                            return Err(ParserError::unexpected_eol(self.line));
                        }

                        let next = *peeker.peek().unwrap();
                        if let &LexerToken::Ident(ref register) = next {
                            let register = register.to_uppercase();
                            if register != "X" && register != "Y" {
                                return Err(ParserError::unexpected_token(self.line));
                            }
                            let addressing_mode = if register == "X" {
                                if addressing_mode == AddressingMode::ZeroPage {
                                    AddressingMode::ZeroPageX
                                } else {
                                    AddressingMode::AbsoluteX
                                }
                            } else {
                                if addressing_mode == AddressingMode::ZeroPage {
                                    AddressingMode::ZeroPageY
                                } else {
                                    AddressingMode::AbsoluteY
                                }
                            };
                            if let Some(opcode) =
                                   OpCode::from_mnemonic_and_addressing_mode(ident, addressing_mode) {
                                // We found one..
                                let mut final_vec = vec![ParserToken::OpCode(opcode)];
                                // Push the address bytes into the result
                                for b in bytes {
                                    final_vec.push(ParserToken::RawByte(b));
                                }
                                return Ok(final_vec);
                            } else {
                                return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
                            }
                        } else {
                            return Err(ParserError::unexpected_token(self.line));
                        }
                    } else {
                        return Err(ParserError::unexpected_token(self.line));
                    }
                    let next = *peeker.peek().unwrap();

                } else {
                    return Err(ParserError::cannot_parse_address(self.line));
                }
            }
            Ok(vec![ParserToken::Label("BLAH".into())])
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ::assembler::token::{ImmediateBase, LexerToken, ParserToken};
    use ::opcodes::{AddressingMode, OpCode};

    #[test]
    fn can_parse_labels_via_lonely_label() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into())],
                          vec![LexerToken::Ident("START".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()), ParserToken::Label("START".into())],
                   &result[..]);
    }

    #[test]
    fn can_parse_labels_via_colon_terminator() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into())], vec![LexerToken::Colon]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into())], &result[..]);
    }

    #[test]
    fn can_parse_opcodes_after_labels_on_one_line() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("LDA".into()),
                               LexerToken::Address("4400".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()),
                     ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("LDA", AddressingMode::Absolute).unwrap()),
                     ParserToken::RawByte(0),
                     ParserToken::RawByte(68)],
                   &result[..]);
    }

    #[test]
    fn can_detect_double_labels_on_one_line() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("START".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens);

        assert_eq!(Err(ParserError::expected_instruction(1)), result);
    }

    #[test]
    fn can_detect_opcode_with_implied_addressing_mode() {
        let tokens = vec![vec![LexerToken::Ident("CLC".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("CLC", AddressingMode::Implied).unwrap())], &result[..]);
    }

    #[test]
    fn can_detect_opcode_with_correct_absolute_x_addressing_mode() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("LDA".into()),
                               LexerToken::Address("4400".into()),
                               LexerToken::Comma,
                               LexerToken::Ident("X".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()),
                     ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("LDA", AddressingMode::AbsoluteX).unwrap()),
                     ParserToken::RawByte(0),
                     ParserToken::RawByte(68)],
                   &result[..]);
    }

    #[test]
    fn errors_on_incorrect_zero_page_y_usage() {
        let tokens = vec![vec![LexerToken::Ident("LDA".into()),
                               LexerToken::Address("44".into()),
                               LexerToken::Comma,
                               LexerToken::Ident("Y".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens);

        assert_eq!(Err(ParserError::invalid_opcode_addressing_mode_combination(1)),
                   result);
    }
}<commit_msg>Add test for correct use of ZeroPageY<commit_after>use std;
use std::iter::Peekable;

use ::opcodes::{AddressingMode, OpCode};
use assembler::token::{LexerToken, ParserToken};

#[derive(Debug, PartialEq)]
pub struct ParserError {
    pub message: String,
}

impl ParserError {
    fn expected_instruction(line: u32) -> ParserError {
        ParserError::from(format!("Instruction expected. Line {}", line))
    }

    fn invalid_opcode_addressing_mode_combination(line: u32) -> ParserError {
        ParserError::from(format!("Invalid addressing mode for opcode. Line {}", line))
    }

    fn unexpected_eol(line: u32) -> ParserError {
        ParserError::from(format!("Unexpected end of line. Line {}", line))
    }

    fn expected_eol(line: u32) -> ParserError {
        ParserError::from(format!("Expected end of line. Line {}", line))
    }

    fn cannot_parse_address(line: u32) -> ParserError {
        ParserError::from(format!("Unable to parse address. Line {}", line))
    }

    fn unexpected_token(line: u32) -> ParserError {
        ParserError::from(format!("Unexpected token. Line {}", line))
    }
}

impl From<String> for ParserError {
    fn from(error: String) -> ParserError {
        ParserError { message: error }
    }
}

impl<'a> From<&'a str> for ParserError {
    fn from(error: &str) -> ParserError {
        ParserError { message: error.into() }
    }
}

pub struct Parser {
    line: u32,
}

/// Parser processes a list of 6502 Assembly tokens
impl Parser {
    pub fn new() -> Parser {
        Parser { line: 0 }
    }

    pub fn parse(&mut self, tokens: Vec<Vec<LexerToken>>) -> Result<Vec<ParserToken>, ParserError> {
        let mut result = Vec::new();

        for line in &tokens {
            self.line += 1;

            let mut peeker = line.iter().peekable();

            // Skip blank lines
            if let None = peeker.peek() {
                continue;
            }

            let next = *peeker.peek().unwrap();

            if let &LexerToken::Ident(ref ident) = next {
                // Check if this is an opcode
                if Self::is_opcode(ident.clone()) {
                    // Yep its an opcode, lets figure out its addressing mode
                    let mut opcode = self.consume_opcode(&mut peeker, ident.clone())?;
                    result.append(&mut opcode);
                } else {
                    // Skip the ident and we'll check what is next
                    let original_ident = peeker.next().unwrap();
                    // if there is nothing else - lets mark this as a Label and move on
                    if let None = peeker.peek() {
                        result.push(ParserToken::Label(ident.clone()));
                        continue;
                    }

                    // A colon after the ident also indicates a label
                    let next = *peeker.peek().unwrap();
                    if let &LexerToken::Colon = next {
                        result.push(ParserToken::Label(ident.clone()));
                        continue;
                    }

                    // Is the next one a label as well? Thats an error:
                    if let &LexerToken::Ident(ref ident) = next {
                        // Lets add the original as a label
                        if let &LexerToken::Ident(ref original_ident) = original_ident {
                            result.push(ParserToken::Label(original_ident.clone()));
                        }

                        if !Self::is_opcode(ident.clone()) {
                            return Err(ParserError::expected_instruction(self.line));
                        } else {
                            // Oh it is an opcode after the label - consume it
                            let mut opcode = self.consume_opcode(&mut peeker, ident.clone())?;
                            result.append(&mut opcode);
                        }
                    }
                }
            }
        }

        Ok(result)
    }

    fn is_opcode<S>(mnemonic: S) -> bool
        where S: Into<String>
    {
        if let Some(opcode) = OpCode::from_mnemonic(mnemonic) {
            true
        } else {
            false
        }
    }

    fn consume_opcode<'a, I, S>(&mut self,
                                mut peeker: &mut Peekable<I>,
                                ident: S)
                                -> Result<Vec<ParserToken>, ParserError>
        where I: Iterator<Item = &'a LexerToken>,
              S: Into<String> + std::fmt::Display
    {
        // Jump over the opcode
        peeker.next();

        // If there is nothing else after this opcode.. lets check if there is
        // a matching opcode with an implied addressing mode
        if let None = peeker.peek() {
            if let Some(opcode) =
                   OpCode::from_mnemonic_and_addressing_mode(ident, AddressingMode::Implied) {
                return Ok(vec![ParserToken::OpCode(opcode)]);
            } else {
                return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
            }
        } else {
            // Check the next token, is it an address?
            let next = *peeker.peek().unwrap();
            if let &LexerToken::Address(ref address) = next {
                // Its an address. What sort of address?
                if address.len() == 2 || address.len() == 4 {
                    // Its zero-page or absolute.. lets try and convert it to a raw byte
                    let (bytes, addressing_mode) = if address.len() == 2 {
                        // Its a 1 byte address
                        if let Ok(raw_byte) = u8::from_str_radix(&address[..], 16) {
                            (vec![raw_byte], AddressingMode::ZeroPage)
                        } else {
                            return Err(ParserError::cannot_parse_address(self.line));
                        }
                    } else {
                        // Its a 2 byte address
                        if let Ok(low_byte) = u8::from_str_radix(&address[2..], 16) {
                            if let Ok(high_byte) = u8::from_str_radix(&address[0..2], 16) {
                                (vec![low_byte, high_byte], AddressingMode::Absolute)
                            } else {
                                return Err(ParserError::cannot_parse_address(self.line));
                            }
                        } else {
                            return Err(ParserError::cannot_parse_address(self.line));
                        }
                    };
                    // consume the address and peek what is next:
                    peeker.next();
                    if let None = peeker.peek() {
                        // Nothing else.. find an opcode with this ident and addressing mode
                        if let Some(opcode) =
                               OpCode::from_mnemonic_and_addressing_mode(ident, addressing_mode) {
                            // We found one..
                            let mut final_vec = vec![ParserToken::OpCode(opcode)];
                            // Push the address bytes into the result
                            for b in bytes {
                                final_vec.push(ParserToken::RawByte(b));
                            }
                            return Ok(final_vec);
                        } else {
                            return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
                        }
                    }

                    // There is something after this address - if its
                    // a comma, then we're peachy. If its something else.. Thats
                    // an error.
                    let next = *peeker.peek().unwrap();
                    if let &LexerToken::Comma = next {
                        // Yes, its a comma. Consume it and check what is next
                        peeker.next();
                        // If theres nothing after the comma thats an error
                        if let None = peeker.peek() {
                            return Err(ParserError::unexpected_eol(self.line));
                        }

                        let next = *peeker.peek().unwrap();
                        if let &LexerToken::Ident(ref register) = next {
                            let register = register.to_uppercase();
                            if register != "X" && register != "Y" {
                                return Err(ParserError::unexpected_token(self.line));
                            }
                            let addressing_mode = if register == "X" {
                                if addressing_mode == AddressingMode::ZeroPage {
                                    AddressingMode::ZeroPageX
                                } else {
                                    AddressingMode::AbsoluteX
                                }
                            } else {
                                if addressing_mode == AddressingMode::ZeroPage {
                                    AddressingMode::ZeroPageY
                                } else {
                                    AddressingMode::AbsoluteY
                                }
                            };
                            if let Some(opcode) =
                                   OpCode::from_mnemonic_and_addressing_mode(ident, addressing_mode) {
                                // We found one..
                                let mut final_vec = vec![ParserToken::OpCode(opcode)];
                                // Push the address bytes into the result
                                for b in bytes {
                                    final_vec.push(ParserToken::RawByte(b));
                                }
                                return Ok(final_vec);
                            } else {
                                return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
                            }
                        } else {
                            return Err(ParserError::unexpected_token(self.line));
                        }
                    } else {
                        return Err(ParserError::unexpected_token(self.line));
                    }
                    let next = *peeker.peek().unwrap();

                } else {
                    return Err(ParserError::cannot_parse_address(self.line));
                }
            }
            Ok(vec![ParserToken::Label("BLAH".into())])
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ::assembler::token::{ImmediateBase, LexerToken, ParserToken};
    use ::opcodes::{AddressingMode, OpCode};

    #[test]
    fn can_parse_labels_via_lonely_label() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into())],
                          vec![LexerToken::Ident("START".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()), ParserToken::Label("START".into())],
                   &result[..]);
    }

    #[test]
    fn can_parse_labels_via_colon_terminator() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into())], vec![LexerToken::Colon]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into())], &result[..]);
    }

    #[test]
    fn can_parse_opcodes_after_labels_on_one_line() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("LDA".into()),
                               LexerToken::Address("4400".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()),
                     ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("LDA", AddressingMode::Absolute).unwrap()),
                     ParserToken::RawByte(0),
                     ParserToken::RawByte(68)],
                   &result[..]);
    }

    #[test]
    fn can_detect_double_labels_on_one_line() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("START".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens);

        assert_eq!(Err(ParserError::expected_instruction(1)), result);
    }

    #[test]
    fn can_detect_opcode_with_implied_addressing_mode() {
        let tokens = vec![vec![LexerToken::Ident("CLC".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("CLC", AddressingMode::Implied).unwrap())], &result[..]);
    }

    #[test]
    fn can_detect_opcode_with_correct_absolute_x_addressing_mode() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("LDA".into()),
                               LexerToken::Address("4400".into()),
                               LexerToken::Comma,
                               LexerToken::Ident("X".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()),
                     ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("LDA", AddressingMode::AbsoluteX).unwrap()),
                     ParserToken::RawByte(0),
                     ParserToken::RawByte(68)],
                   &result[..]);
    }

    #[test]
    fn errors_on_incorrect_zero_page_y_usage() {
        let tokens = vec![vec![LexerToken::Ident("LDA".into()),
                               LexerToken::Address("44".into()),
                               LexerToken::Comma,
                               LexerToken::Ident("Y".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens);

        assert_eq!(Err(ParserError::invalid_opcode_addressing_mode_combination(1)),
                   result);
    }

    #[test]
    fn can_handle_correct_zero_page_y_usage() {
        let tokens = vec![vec![LexerToken::Ident("LDX".into()),
                               LexerToken::Address("44".into()),
                               LexerToken::Comma,
                               LexerToken::Ident("Y".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[
                     ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("LDX", AddressingMode::ZeroPageY).unwrap()),
                     ParserToken::RawByte(68)],
                   &result[..]);
    }
}<|endoftext|>


<commit_before>//! TODO Fill in

use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rustwlc::Geometry;
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value, LightUserData};
use super::object::{Object, Objectable};
use super::class::{self, Class};
use super::property::Property;

#[derive(Clone, Debug)]
pub struct DrawableState {
    pub surface: Option<ImageSurface>,
    geo: Geometry,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool,
}

pub struct Drawable<'lua>(Table<'lua>);

impl_objectable!(Drawable, DrawableState);

impl Default for DrawableState {
    fn default() -> Self {
        DrawableState {
            surface: None,
            geo: Geometry::zero(),
            refreshed: true
        }
    }
}

impl <'lua> Drawable<'lua> {
    pub fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table();
        table.set("geometry", lua.create_function(geometry))?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Geometry> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref surface) => {
                let stash = surface.to_glib_none();
                let ptr = stash.0 as _;
                // So that it lives _forever_ heheheh.
                ::std::mem::forget(stash);
                Value::LightUserData(LightUserData(ptr))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, geometry: Geometry) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let mut drawable = self.state()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.surface = None;
            let size = geometry.size;
            if size.w > 0 && size.h > 0 {
                drawable.surface = Some(ImageSurface::create(Format::ARgb32,
                                                        size.w as i32,
                                                        size.h as i32)
                    .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?);
                // TODO emity property::surface
            }
        }
        self.set_state(drawable)
    }
}

impl Display for DrawableState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Drawable: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Drawable<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for DrawableState {}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    Class::builder(lua, Some(Rc::new(Drawable::new)), None, None)?
        .method("geometry".into(), lua.create_function(geometry))?
        .property(Property::new("surface".into(),
                                None,
                                Some(lua.create_function(get_surface)),
                                None))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: &'lua Lua, table: Table<'lua>) -> rlua::Result<Value<'lua>> {
    let drawable = Drawable::cast(table.clone().into())?;
    drawable.get_surface()
}

fn geometry<'lua>(lua: &'lua Lua, table: Table<'lua>) -> rlua::Result<Table<'lua>> {
    use rustwlc::{Point, Size};
    let drawable = Drawable::cast(table.into())?;
    let geometry = drawable.get_geometry()?;
    let Point { x, y } = geometry.origin;
    let Size { w, h } = geometry.size;
    let table = lua.create_table();
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", w)?;
    table.set("height", h)?;
    Ok(table)
}
<commit_msg>Improve drawable "refreshed" handling<commit_after>//! TODO Fill in

use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rustwlc::Geometry;
use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value, LightUserData};
use super::object::{Object, Objectable};
use super::class::{self, Class};
use super::property::Property;

#[derive(Clone, Debug)]
pub struct DrawableState {
    pub surface: Option<ImageSurface>,
    geo: Geometry,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool,
}

pub struct Drawable<'lua>(Table<'lua>);

impl_objectable!(Drawable, DrawableState);

impl Default for DrawableState {
    fn default() -> Self {
        DrawableState {
            surface: None,
            geo: Geometry::zero(),
            refreshed: false
        }
    }
}

impl <'lua> Drawable<'lua> {
    pub fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table();
        table.set("geometry", lua.create_function(geometry))?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Geometry> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref surface) => {
                let stash = surface.to_glib_none();
                let ptr = stash.0 as _;
                // So that it lives _forever_ heheheh.
                ::std::mem::forget(stash);
                Value::LightUserData(LightUserData(ptr))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, geometry: Geometry) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let mut drawable = self.state()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.surface = None;
            drawable.refreshed = false;
            let size = geometry.size;
            if size.w > 0 && size.h > 0 {
                drawable.surface = Some(ImageSurface::create(Format::ARgb32,
                                                        size.w as i32,
                                                        size.h as i32)
                    .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?);
                // TODO emity property::surface
            }
        }
        self.set_state(drawable)
    }
}

impl Display for DrawableState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Drawable: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Drawable<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for DrawableState {}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    Class::builder(lua, Some(Rc::new(Drawable::new)), None, None)?
        .method("geometry".into(), lua.create_function(geometry))?
        .property(Property::new("surface".into(),
                                None,
                                Some(lua.create_function(get_surface)),
                                None))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: &'lua Lua, table: Table<'lua>) -> rlua::Result<Value<'lua>> {
    let drawable = Drawable::cast(table.clone().into())?;
    drawable.get_surface()
}

fn geometry<'lua>(lua: &'lua Lua, table: Table<'lua>) -> rlua::Result<Table<'lua>> {
    use rustwlc::{Point, Size};
    let drawable = Drawable::cast(table.into())?;
    let geometry = drawable.get_geometry()?;
    let Point { x, y } = geometry.origin;
    let Size { w, h } = geometry.size;
    let table = lua.create_table();
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", w)?;
    table.set("height", h)?;
    Ok(table)
}
<|endoftext|>