<commit_before>//! Useful traits for manipulating sequences of data stored in `GenericArray`s

use super::*;
use core::ops::{Add, Sub};
use core::{mem, ptr};
use typenum::operator_aliases::*;

/// Defines some sequence with an associated length and iteration capabilities.
///
/// This is useful for passing N-length generic arrays as generics.
pub unsafe trait GenericSequence<T>: Sized + IntoIterator {
    /// `GenericArray` associated length
    type Length: ArrayLength<T>;

    /// Concrete sequence type used in conjuction with reference implementations of `GenericSequence`
    type Sequence: GenericSequence<T, Length = Self::Length> + FromIterator<T>;

    /// Initializes a new sequence instance using the given function.
    ///
    /// If the generator function panics while initializing the sequence,
    /// any already initialized elements will be dropped.
    fn generate<F>(f: F) -> Self::Sequence
    where
        F: FnMut(usize) -> T;

    #[doc(hidden)]
    fn inverted_zip<B, U, F>(
        self,
        lhs: GenericArray<B, Self::Length>,
        mut f: F,
    ) -> MappedSequence<GenericArray<B, Self::Length>, B, U>
    where
        GenericArray<B, Self::Length>: GenericSequence<B, Length = Self::Length>
            + MappedGenericSequence<B, U>,
        Self: MappedGenericSequence<T, U>,
        Self::Length: ArrayLength<B> + ArrayLength<U>,
        F: FnMut(B, Self::Item) -> U,
    {
        unsafe {
            let mut left = ArrayConsumer::new(lhs);

            let (left_array_iter, left_position) = left.iter_position();

            FromIterator::from_iter(left_array_iter.zip(self.into_iter()).map(
                |(l, right_value)| {
                        let left_value = ptr::read(l);

                        *left_position += 1;

                        f(left_value, right_value)
                },
            ))
        }
    }

    #[doc(hidden)]
    fn inverted_zip2<B, Lhs, U, F>(self, lhs: Lhs, mut f: F) -> MappedSequence<Lhs, B, U>
    where
        Lhs: GenericSequence<B, Length = Self::Length> + MappedGenericSequence<B, U>,
        Self: MappedGenericSequence<T, U>,
        Self::Length: ArrayLength<B> + ArrayLength<U>,
        F: FnMut(Lhs::Item, Self::Item) -> U,
    {
        FromIterator::from_iter(lhs.into_iter().zip(self.into_iter()).map(|(l, r)| f(l, r)))
    }
}

/// Accessor for `GenericSequence` item type, which is really `IntoIterator::Item`
///
/// For deeply nested generic mapped sequence types, like shown in `tests/generics.rs`,
/// this can be useful for keeping things organized.
pub type SequenceItem<T> = <T as IntoIterator>::Item;

unsafe impl<'a, T: 'a, S: GenericSequence<T>> GenericSequence<T> for &'a S
where
    &'a S: IntoIterator,
{
    type Length = S::Length;
    type Sequence = S::Sequence;

    #[inline]
    fn generate<F>(f: F) -> Self::Sequence
    where
        F: FnMut(usize) -> T,
    {
        S::generate(f)
    }
}

unsafe impl<'a, T: 'a, S: GenericSequence<T>> GenericSequence<T> for &'a mut S
where
    &'a mut S: IntoIterator,
{
    type Length = S::Length;
    type Sequence = S::Sequence;

    #[inline]
    fn generate<F>(f: F) -> Self::Sequence
    where
        F: FnMut(usize) -> T,
    {
        S::generate(f)
    }
}

/// Defines any `GenericSequence` which can be lengthened or extended by appending
/// or prepending an element to it.
///
/// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back`
pub unsafe trait Lengthen<T>: Sized + GenericSequence<T> {
    /// `GenericSequence` that has one more element than `Self`
    type Longer: Shorten<T, Shorter = Self>;

    /// Returns a new array with the given element appended to the end of it.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3];
    ///
    /// let b = a.append(4);
    ///
    /// assert_eq!(b, arr![i32; 1, 2, 3, 4]);
    /// ```
    fn append(self, last: T) -> Self::Longer;

    /// Returns a new array with the given element prepended to the front of it.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3];
    ///
    /// let b = a.prepend(4);
    ///
    /// assert_eq!(b, arr![i32; 4, 1, 2, 3]);
    /// ```
    fn prepend(self, first: T) -> Self::Longer;
}

/// Defines a `GenericSequence` which can be shortened by removing the first or last element from it.
///
/// Additionally, any shortened sequence can be lengthened by
/// appending or prepending an element to it.
pub unsafe trait Shorten<T>: Sized + GenericSequence<T> {
    /// `GenericSequence` that has one less element than `Self`
    type Shorter: Lengthen<T, Longer = Self>;

    /// Returns a new array without the last element, and the last element.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3, 4];
    ///
    /// let (init, last) = a.pop_back();
    ///
    /// assert_eq!(init, arr![i32; 1, 2, 3]);
    /// assert_eq!(last, 4);
    /// ```
    fn pop_back(self) -> (Self::Shorter, T);

    /// Returns a new array without the first element, and the first element.
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3, 4];
    ///
    /// let (head, tail) = a.pop_front();
    ///
    /// assert_eq!(head, 1);
    /// assert_eq!(tail, arr![i32; 2, 3, 4]);
    /// ```
    fn pop_front(self) -> (T, Self::Shorter);
}

unsafe impl<T, N: ArrayLength<T>> Lengthen<T> for GenericArray<T, N>
where
    N: Add<B1>,
    Add1<N>: ArrayLength<T>,
    Add1<N>: Sub<B1, Output = N>,
    Sub1<Add1<N>>: ArrayLength<T>,
{
    type Longer = GenericArray<T, Add1<N>>;

    fn append(self, last: T) -> Self::Longer {
        let mut longer: Self::Longer = unsafe { mem::uninitialized() };

        unsafe {
            ptr::write(longer.as_mut_ptr() as *mut _, self);
            ptr::write(&mut longer[N::to_usize()], last);
        }

        longer
    }

    fn prepend(self, first: T) -> Self::Longer {
        let mut longer: Self::Longer = unsafe { mem::uninitialized() };

        let longer_ptr = longer.as_mut_ptr();

        unsafe {
            ptr::write(longer_ptr as *mut _, first);
            ptr::write(longer_ptr.offset(1) as *mut _, self);
        }

        longer
    }
}

unsafe impl<T, N: ArrayLength<T>> Shorten<T> for GenericArray<T, N>
where
    N: Sub<B1>,
    Sub1<N>: ArrayLength<T>,
    Sub1<N>: Add<B1, Output = N>,
    Add1<Sub1<N>>: ArrayLength<T>,
{
    type Shorter = GenericArray<T, Sub1<N>>;

    fn pop_back(self) -> (Self::Shorter, T) {
        let init_ptr = self.as_ptr();
        let last_ptr = unsafe { init_ptr.offset(Sub1::<N>::to_usize() as isize) };

        let init = unsafe { ptr::read(init_ptr as _) };
        let last = unsafe { ptr::read(last_ptr as _) };

        mem::forget(self);

        (init, last)
    }

    fn pop_front(self) -> (T, Self::Shorter) {
        let head_ptr = self.as_ptr();
        let tail_ptr = unsafe { head_ptr.offset(1) };

        let head = unsafe { ptr::read(head_ptr as _) };
        let tail = unsafe { ptr::read(tail_ptr as _) };

        mem::forget(self);

        (head, tail)
    }
}

/// Defines a `GenericSequence` that can be split into two parts at a given pivot index.
pub unsafe trait Split<T, K>: GenericSequence<T>
where
    K: ArrayLength<T>,
{
    /// First part of the resulting split array
    type First: GenericSequence<T>;
    /// Second part of the resulting split array
    type Second: GenericSequence<T>;

    /// Splits an array at the given index, returning the separate parts of the array.
    fn split(self) -> (Self::First, Self::Second);
}

unsafe impl<T, N, K> Split<T, K> for GenericArray<T, N>
where
    N: ArrayLength<T>,
    K: ArrayLength<T>,
    N: Sub<K>,
    Diff<N, K>: ArrayLength<T>,
{
    type First = GenericArray<T, K>;
    type Second = GenericArray<T, Diff<N, K>>;

    fn split(self) -> (Self::First, Self::Second) {
        let head_ptr = self.as_ptr();
        let tail_ptr = unsafe { head_ptr.offset(K::to_usize() as isize) };

        let head = unsafe { ptr::read(head_ptr as _) };
        let tail = unsafe { ptr::read(tail_ptr as _) };

        mem::forget(self);

        (head, tail)
    }
}

/// Defines `GenericSequence`s which can be joined together, forming a larger array.
pub unsafe trait Concat<T, M>: GenericSequence<T>
where
    M: ArrayLength<T>,
{
    /// Sequence to be concatenated with `self`
    type Rest: GenericSequence<T, Length = M>;

    /// Resulting sequence formed by the concatenation.
    type Output: GenericSequence<T>;

    /// Concatenate, or join, two sequences.
    fn concat(self, rest: Self::Rest) -> Self::Output;
}

unsafe impl<T, N, M> Concat<T, M> for GenericArray<T, N>
where
    N: ArrayLength<T> + Add<M>,
    M: ArrayLength<T>,
    Sum<N, M>: ArrayLength<T>,
{
    type Rest = GenericArray<T, M>;
    type Output = GenericArray<T, Sum<N, M>>;

    fn concat(self, rest: Self::Rest) -> Self::Output {
        let mut output: Self::Output = unsafe { mem::uninitialized() };

        let output_ptr = output.as_mut_ptr();

        unsafe {
            ptr::write(output_ptr as *mut _, self);
            ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest);
        }

        output
    }
}
<commit_msg>Use pointer::add rather than offset<commit_after>//! Useful traits for manipulating sequences of data stored in `GenericArray`s

use super::*;
use core::ops::{Add, Sub};
use core::{mem, ptr};
use typenum::operator_aliases::*;

/// Defines some sequence with an associated length and iteration capabilities.
///
/// This is useful for passing N-length generic arrays as generics.
pub unsafe trait GenericSequence<T>: Sized + IntoIterator {
    /// `GenericArray` associated length
    type Length: ArrayLength<T>;

    /// Concrete sequence type used in conjuction with reference implementations of `GenericSequence`
    type Sequence: GenericSequence<T, Length = Self::Length> + FromIterator<T>;

    /// Initializes a new sequence instance using the given function.
    ///
    /// If the generator function panics while initializing the sequence,
    /// any already initialized elements will be dropped.
    fn generate<F>(f: F) -> Self::Sequence
    where
        F: FnMut(usize) -> T;

    #[doc(hidden)]
    fn inverted_zip<B, U, F>(
        self,
        lhs: GenericArray<B, Self::Length>,
        mut f: F,
    ) -> MappedSequence<GenericArray<B, Self::Length>, B, U>
    where
        GenericArray<B, Self::Length>: GenericSequence<B, Length = Self::Length>
            + MappedGenericSequence<B, U>,
        Self: MappedGenericSequence<T, U>,
        Self::Length: ArrayLength<B> + ArrayLength<U>,
        F: FnMut(B, Self::Item) -> U,
    {
        unsafe {
            let mut left = ArrayConsumer::new(lhs);

            let (left_array_iter, left_position) = left.iter_position();

            FromIterator::from_iter(left_array_iter.zip(self.into_iter()).map(
                |(l, right_value)| {
                        let left_value = ptr::read(l);

                        *left_position += 1;

                        f(left_value, right_value)
                },
            ))
        }
    }

    #[doc(hidden)]
    fn inverted_zip2<B, Lhs, U, F>(self, lhs: Lhs, mut f: F) -> MappedSequence<Lhs, B, U>
    where
        Lhs: GenericSequence<B, Length = Self::Length> + MappedGenericSequence<B, U>,
        Self: MappedGenericSequence<T, U>,
        Self::Length: ArrayLength<B> + ArrayLength<U>,
        F: FnMut(Lhs::Item, Self::Item) -> U,
    {
        FromIterator::from_iter(lhs.into_iter().zip(self.into_iter()).map(|(l, r)| f(l, r)))
    }
}

/// Accessor for `GenericSequence` item type, which is really `IntoIterator::Item`
///
/// For deeply nested generic mapped sequence types, like shown in `tests/generics.rs`,
/// this can be useful for keeping things organized.
pub type SequenceItem<T> = <T as IntoIterator>::Item;

unsafe impl<'a, T: 'a, S: GenericSequence<T>> GenericSequence<T> for &'a S
where
    &'a S: IntoIterator,
{
    type Length = S::Length;
    type Sequence = S::Sequence;

    #[inline]
    fn generate<F>(f: F) -> Self::Sequence
    where
        F: FnMut(usize) -> T,
    {
        S::generate(f)
    }
}

unsafe impl<'a, T: 'a, S: GenericSequence<T>> GenericSequence<T> for &'a mut S
where
    &'a mut S: IntoIterator,
{
    type Length = S::Length;
    type Sequence = S::Sequence;

    #[inline]
    fn generate<F>(f: F) -> Self::Sequence
    where
        F: FnMut(usize) -> T,
    {
        S::generate(f)
    }
}

/// Defines any `GenericSequence` which can be lengthened or extended by appending
/// or prepending an element to it.
///
/// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back`
pub unsafe trait Lengthen<T>: Sized + GenericSequence<T> {
    /// `GenericSequence` that has one more element than `Self`
    type Longer: Shorten<T, Shorter = Self>;

    /// Returns a new array with the given element appended to the end of it.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3];
    ///
    /// let b = a.append(4);
    ///
    /// assert_eq!(b, arr![i32; 1, 2, 3, 4]);
    /// ```
    fn append(self, last: T) -> Self::Longer;

    /// Returns a new array with the given element prepended to the front of it.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3];
    ///
    /// let b = a.prepend(4);
    ///
    /// assert_eq!(b, arr![i32; 4, 1, 2, 3]);
    /// ```
    fn prepend(self, first: T) -> Self::Longer;
}

/// Defines a `GenericSequence` which can be shortened by removing the first or last element from it.
///
/// Additionally, any shortened sequence can be lengthened by
/// appending or prepending an element to it.
pub unsafe trait Shorten<T>: Sized + GenericSequence<T> {
    /// `GenericSequence` that has one less element than `Self`
    type Shorter: Lengthen<T, Longer = Self>;

    /// Returns a new array without the last element, and the last element.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3, 4];
    ///
    /// let (init, last) = a.pop_back();
    ///
    /// assert_eq!(init, arr![i32; 1, 2, 3]);
    /// assert_eq!(last, 4);
    /// ```
    fn pop_back(self) -> (Self::Shorter, T);

    /// Returns a new array without the first element, and the first element.
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3, 4];
    ///
    /// let (head, tail) = a.pop_front();
    ///
    /// assert_eq!(head, 1);
    /// assert_eq!(tail, arr![i32; 2, 3, 4]);
    /// ```
    fn pop_front(self) -> (T, Self::Shorter);
}

unsafe impl<T, N: ArrayLength<T>> Lengthen<T> for GenericArray<T, N>
where
    N: Add<B1>,
    Add1<N>: ArrayLength<T>,
    Add1<N>: Sub<B1, Output = N>,
    Sub1<Add1<N>>: ArrayLength<T>,
{
    type Longer = GenericArray<T, Add1<N>>;

    fn append(self, last: T) -> Self::Longer {
        let mut longer: Self::Longer = unsafe { mem::uninitialized() };

        unsafe {
            ptr::write(longer.as_mut_ptr() as *mut _, self);
            ptr::write(&mut longer[N::to_usize()], last);
        }

        longer
    }

    fn prepend(self, first: T) -> Self::Longer {
        let mut longer: Self::Longer = unsafe { mem::uninitialized() };

        let longer_ptr = longer.as_mut_ptr();

        unsafe {
            ptr::write(longer_ptr as *mut _, first);
            ptr::write(longer_ptr.offset(1) as *mut _, self);
        }

        longer
    }
}

unsafe impl<T, N: ArrayLength<T>> Shorten<T> for GenericArray<T, N>
where
    N: Sub<B1>,
    Sub1<N>: ArrayLength<T>,
    Sub1<N>: Add<B1, Output = N>,
    Add1<Sub1<N>>: ArrayLength<T>,
{
    type Shorter = GenericArray<T, Sub1<N>>;

    fn pop_back(self) -> (Self::Shorter, T) {
        let init_ptr = self.as_ptr();
        let last_ptr = unsafe { init_ptr.add(Sub1::<N>::to_usize()) };

        let init = unsafe { ptr::read(init_ptr as _) };
        let last = unsafe { ptr::read(last_ptr as _) };

        mem::forget(self);

        (init, last)
    }

    fn pop_front(self) -> (T, Self::Shorter) {
        let head_ptr = self.as_ptr();
        let tail_ptr = unsafe { head_ptr.offset(1) };

        let head = unsafe { ptr::read(head_ptr as _) };
        let tail = unsafe { ptr::read(tail_ptr as _) };

        mem::forget(self);

        (head, tail)
    }
}

/// Defines a `GenericSequence` that can be split into two parts at a given pivot index.
pub unsafe trait Split<T, K>: GenericSequence<T>
where
    K: ArrayLength<T>,
{
    /// First part of the resulting split array
    type First: GenericSequence<T>;
    /// Second part of the resulting split array
    type Second: GenericSequence<T>;

    /// Splits an array at the given index, returning the separate parts of the array.
    fn split(self) -> (Self::First, Self::Second);
}

unsafe impl<T, N, K> Split<T, K> for GenericArray<T, N>
where
    N: ArrayLength<T>,
    K: ArrayLength<T>,
    N: Sub<K>,
    Diff<N, K>: ArrayLength<T>,
{
    type First = GenericArray<T, K>;
    type Second = GenericArray<T, Diff<N, K>>;

    fn split(self) -> (Self::First, Self::Second) {
        let head_ptr = self.as_ptr();
        let tail_ptr = unsafe { head_ptr.add(K::to_usize()) };

        let head = unsafe { ptr::read(head_ptr as _) };
        let tail = unsafe { ptr::read(tail_ptr as _) };

        mem::forget(self);

        (head, tail)
    }
}

/// Defines `GenericSequence`s which can be joined together, forming a larger array.
pub unsafe trait Concat<T, M>: GenericSequence<T>
where
    M: ArrayLength<T>,
{
    /// Sequence to be concatenated with `self`
    type Rest: GenericSequence<T, Length = M>;

    /// Resulting sequence formed by the concatenation.
    type Output: GenericSequence<T>;

    /// Concatenate, or join, two sequences.
    fn concat(self, rest: Self::Rest) -> Self::Output;
}

unsafe impl<T, N, M> Concat<T, M> for GenericArray<T, N>
where
    N: ArrayLength<T> + Add<M>,
    M: ArrayLength<T>,
    Sum<N, M>: ArrayLength<T>,
{
    type Rest = GenericArray<T, M>;
    type Output = GenericArray<T, Sum<N, M>>;

    fn concat(self, rest: Self::Rest) -> Self::Output {
        let mut output: Self::Output = unsafe { mem::uninitialized() };

        let output_ptr = output.as_mut_ptr();

        unsafe {
            ptr::write(output_ptr as *mut _, self);
            ptr::write(output_ptr.add(N::to_usize()) as *mut _, rest);
        }

        output
    }
}
<|endoftext|>


<commit_before>#[test]
fn test_readme_deps() {
    version_sync::assert_markdown_deps_updated!("README.md");
}

#[test]
fn test_readme_changelog() {
    version_sync::assert_contains_regex!(
        "README.md",
        r"^### Version {version} — .* \d\d?.., 20\d\d$"
    );
}

#[test]
fn test_html_root_url() {
    version_sync::assert_html_root_url_updated!("src/lib.rs");
}
<commit_msg>tests: fix changelog test<commit_after>#[test]
fn test_readme_deps() {
    version_sync::assert_markdown_deps_updated!("README.md");
}

#[test]
fn test_changelog() {
    version_sync::assert_contains_regex!(
        "CHANGELOG.md",
        r"^## Version {version} — .* \d\d?.., 20\d\d$"
    );
}

#[test]
fn test_html_root_url() {
    version_sync::assert_html_root_url_updated!("src/lib.rs");
}
<|endoftext|>


<commit_before>use std::collections::hashmap::HashMap;
use std::io::Writer;
use time;
use common::{ LogEntry };

pub struct LogWriter<'a> {
    writer: &'a mut Writer+'a,
    options: LogWriterOptions<'a>
}

pub struct LogWriterOptions<'a> {
    pub repository_link: String,
    pub version: String,
    pub subtitle: String
}

impl<'a> LogWriter<'a> {

    fn get_commit_link (repository: &String, hash: &String) -> String {
        let short_hash = hash.as_slice().slice_chars(0,8);
        if repository.len() > 0 {
            format!("[{}]({}/commit/{})", short_hash, repository, hash)
        }
        else {
            format!("({})", short_hash)
        }
    }

    fn get_issue_link (repository: &String, issue: &String) -> String {
        if repository.len() > 0 {
            format!("[#{}]({}/issues/{})", issue, repository, issue)
        }
        else {
            format!("(#{})", issue)
        }
    }

    pub fn write_header (&mut self) {

        let subtitle = match self.options.subtitle.len() {
            0 => self.options.subtitle.clone(),
            _ => format!(" {}", self.options.subtitle)
        };

        let version_text = format!("## {}{}", self.options.version, subtitle);

        let date = time::now_utc().strftime("%Y-%m-%d");

        if self.options.repository_link.len() > 0 {
            write!(self.writer, "{} ({})\n\n", version_text, date);
        } else {
            write!(self.writer, "<a name=\"{}\"\n{} ({})\n\n",
                                self.options.version,
                                version_text,
                                date);
        }
    }

    pub fn write_section (&mut self, title: &str, section: &HashMap<String, Vec<LogEntry>>) {
        if section.len() == 0 { return; }

        let repo_link = &self.options.repository_link;
        // FIXME: Refactor these to non-static methods
        let issue_link = |s| -> String {
            LogWriter::get_issue_link(repo_link, s)
        };
        let commit_link = |s| -> String {
            LogWriter::get_commit_link(repo_link, s)
        };

        self.writer.write_line(format!("\n#### {}\n\n", title).as_slice());

        for (component, entries) in section.iter() {
            let nested = entries.len() > 1;

            //TODO: implement the empty component stuff
            let prefix = if nested {
                write!(self.writer, "* **{}**\n", component);
                "  *".to_string()
            } else {
                format!("* **{}**", component)
            };

            for entry in entries.iter() {
                write!(self.writer, "{} {} ({}",
                                    prefix,
                                    entry.subject,
                                    commit_link(&entry.hash));

                if entry.closes.len() > 0 {
                    let closes_string = entry.closes.iter()
                                                    .map(|s| issue_link(s))
                                                    // FIXME: Connect should be
                                                    // used on the Iterator
                                                    .collect::<Vec<String>>()
                                                    .connect(", ");

                    write!(self.writer, ", closes {}", closes_string);
                }

                write!(self.writer, ")\n");
            };
        };
    }

    pub fn write (&mut self, content: &str) {
        write!(self.writer, "\n\n\n");
        write!(self.writer, "{}", content);
    }

    pub fn new<T:Writer + Send>(writer: &'a mut T, options: LogWriterOptions) -> LogWriter<'a> {
        LogWriter {
            writer: writer,
            options: options
        }
    }
}
<commit_msg>refactor(log_writer): change static methods to regular methods<commit_after>use std::collections::hashmap::HashMap;
use std::io::Writer;
use time;
use common::{ LogEntry };

pub struct LogWriter<'a> {
    writer: &'a mut Writer+'a,
    options: LogWriterOptions<'a>
}

pub struct LogWriterOptions<'a> {
    pub repository_link: String,
    pub version: String,
    pub subtitle: String
}

impl<'a> LogWriter<'a> {

    fn commit_link(&self, hash: &String) -> String {
        let short_hash = hash.as_slice().slice_chars(0,8);
        match self.options.repository_link.as_slice() {
            "" => format!("({})", short_hash),
            link => format!("[{}]({}/commit/{})", short_hash, link, hash)

        }
    }

    fn issue_link(&self, issue: &String) -> String {
        match self.options.repository_link.as_slice() {
            "" => format!("(#{})", issue),
            link => format!("[#{}]({}/issues/{})", issue, link, issue)
        }
    }

    pub fn write_header (&mut self) {

        let subtitle = match self.options.subtitle.len() {
            0 => self.options.subtitle.clone(),
            _ => format!(" {}", self.options.subtitle)
        };

        let version_text = format!("## {}{}", self.options.version, subtitle);

        let date = time::now_utc().strftime("%Y-%m-%d");

        if self.options.repository_link.len() > 0 {
            write!(self.writer, "{} ({})\n\n", version_text, date);
        } else {
            write!(self.writer, "<a name=\"{}\"\n{} ({})\n\n",
                                self.options.version,
                                version_text,
                                date);
        }
    }

    pub fn write_section (&mut self, title: &str, section: &HashMap<String, Vec<LogEntry>>) {
        if section.len() == 0 { return; }

        self.writer.write_line(format!("\n#### {}\n\n", title).as_slice());

        for (component, entries) in section.iter() {
            let nested = entries.len() > 1;

            //TODO: implement the empty component stuff
            let prefix = if nested {
                write!(self.writer, "* **{}**\n", component);
                "  *".to_string()
            } else {
                format!("* **{}**", component)
            };

            for entry in entries.iter() {
                write!(self.writer, "{} {} ({}",
                                    prefix,
                                    entry.subject,
                                    self.commit_link(&entry.hash));

                if entry.closes.len() > 0 {
                    let closes_string = entry.closes.iter()
                                                    .map(|s| self.issue_link(s))
                                                    // FIXME: Connect should be
                                                    // used on the Iterator
                                                    .collect::<Vec<String>>()
                                                    .connect(", ");

                    write!(self.writer, ", closes {}", closes_string);
                }

                write!(self.writer, ")\n");
            };
        };
    }

    pub fn write (&mut self, content: &str) {
        write!(self.writer, "\n\n\n");
        write!(self.writer, "{}", content);
    }

    pub fn new<T:Writer + Send>(writer: &'a mut T, options: LogWriterOptions) -> LogWriter<'a> {
        LogWriter {
            writer: writer,
            options: options
        }
    }
}
<|endoftext|>


<commit_before>//! Code for the internal Lua thread which handles all Lua requests.

use std::collections::btree_map::BTreeMap;
use std::thread;
use std::fs::{File};
use std::path::Path;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

use convert::json::lua_to_json;

use rustc_serialize::json::Json;
use uuid::Uuid;
use hlua::{self, Lua, LuaError};
use hlua::any::AnyLuaValue;

use super::types::*;
use super::rust_interop;
use super::init_path;
use super::super::keys;

use registry::{self};

use ::layout::{lock_tree, ContainerType};

lazy_static! {
    /// Sends requests to the Lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the Lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);

    /// Requests to update the registry state from Lua
    static ref REGISTRY_QUEUE: RwLock<Vec<String>> = RwLock::new(vec![]);
}

pub const ERR_LOCK_RUNNING: &'static str = "Lua thread: unable to lock RUNNING";
pub const ERR_LOCK_SENDER: &'static str = "Lua thread: unable to lock SENDER";
pub const ERR_LOCK_QUEUE: &'static str =
    "Lua thread: unable to lock REGISTRY_QUEUE";

const INIT_LUA_FUNC: &'static str = "way_cooler.on_init()";
const LUA_TERMINATE_CODE: &'static str = "way_cooler.on_terminate()";
const LUA_RESTART_CODE: &'static str = "way_cooler.on_restart()";

/// Struct sent to the Lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

// Reexported in lua/mod.rs:11
/// Whether the Lua thread is currently available.
pub fn running() -> bool {
    *RUNNING.read().expect(ERR_LOCK_RUNNING)
}

// Reexported in lua/mod.rs:11
/// Errors which may arise from attempting
/// to sending a message to the Lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

/// Appends this combination of category and key to the registry queue.
pub fn update_registry_value(category: String) {
    let mut queue = REGISTRY_QUEUE.write().expect(ERR_LOCK_QUEUE);
    queue.push(category);
}

// Reexported in lua/mod.rs:11
/// Attemps to send a LuaQuery to the Lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().expect(ERR_LOCK_SENDER);
        match *maybe_sender {
            Some(ref real_sender) => {
                // Senders are designed to be cloneable
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    // Create a response channel
    let (response_tx, response_rx) = channel();
    let message = LuaMessage { reply: response_tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(response_rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the Lua thread.
pub fn init() {
    info!("Initializing lua...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = Lua::new();
    debug!("Loading Lua libraries...");
    lua.openlibs();
    debug!("Loading way-cooler libraries...");
    rust_interop::register_libraries(&mut lua);

    let (use_config, maybe_init_file) = init_path::get_config();
    if use_config {
        match maybe_init_file {
            Ok(init_file) => {
                let _: () = lua.execute_from_reader(init_file)
                    .map(|r| { debug!("Read init.lua successfully"); r })
                    .or_else(|err| {
                        error!("Lua error: {:?}", err);
                        warn!("Defaulting to pre-compiled init.lua");
                        lua.execute(init_path::DEFAULT_CONFIG)
                        })
                    .expect("Unable to load pre-compiled init file");
                debug!("Read init.lua successfully");
            }
            Err(_) => {
                warn!("Defaulting to pre-compiled init.lua");
                let _: () = lua.execute(init_path::DEFAULT_CONFIG)
                    .expect("Unable to load pre-compiled init file");
            }
        }
    }
    else {
        info!("Skipping config search");
    }

    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    debug!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || { main_loop(receiver, &mut lua) });
    // Immediately update all the values that the init file set
    send(LuaQuery::UpdateRegistryFromCache)
        .expect("Could not update registry from cache");
}

pub fn on_compositor_ready() {
    info!("Running lua on_init()");
    // Call the special init hook function that we read from the init file
    send(LuaQuery::Execute(INIT_LUA_FUNC.to_owned()))
        .err()
        .map(|error| { error!("Lua init callback returned an error: {:?}", error); error });

    // Re-tile the layout tree, to make any changes appear immediantly.
    if let Ok(mut tree) = lock_tree() {
        tree.layout_active_of(ContainerType::Root)
            .unwrap_or_else(|_| {
                warn!("Lua thread could not re-tile the layout tree");
            });
        // Yeah this is silly, it's so the active border can be updated properly.
        if let Some(active_id) = tree.active_id() {
            tree.focus(active_id)
                .expect("Could not focus on the focused id");
        }
    }
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                if !handle_message(message, lua) {
                    return
                }
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut Lua) -> bool {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            if let Err(error) = lua.execute::<()>(LUA_TERMINATE_CODE) {
                error!("Lua termination callback returned an error: {:?}", error);
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            info!("Lua thread terminating!");
            return false
        },
        LuaQuery::Restart => {
            trace!("Received restart signal!");
            if let Err(error) = lua.execute::<()>(LUA_RESTART_CODE) {
                error!("Lua restart callback returned an error: {:?}", error);
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            // The only real way to restart
            let _new_handle = thread::Builder::new()
                .name("Lua re-init".to_string())
                .spawn(move || {
                    init();
                    keys::init();
                });

            info!("Lua thread restarting");
            return false
        },
        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },
        LuaQuery::ExecFile(name) => {
            info!("Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("Error executing {}!", name);
                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let Ok
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());
                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },
        LuaQuery::ExecRust(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(Some(result)));
        },
        LuaQuery::HandleKey(press) => {
            trace!("Lua: handling keypress {}", &press);
            let press_ix = press.get_lua_index_string();
            // Access the index
            let code = format!("__key_map['{}']()", press_ix);
            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error handling {}: {:?}", &press, error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Handled keypress okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        }
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
        LuaQuery::UpdateRegistryFromCache => {
            let lock = registry::clients_read();
            // Lua has access to everything
            let client = lock.client(Uuid::nil()).unwrap();
            let mut handle = registry::WriteHandle::new(&client);

            let mut queue = REGISTRY_QUEUE.write().expect(ERR_LOCK_QUEUE);
            for category in queue.drain(0..) {
                let mut registry_cache = lua.get::<hlua::LuaTable<_>, _>("__registry_cache")
                    .expect("__registry_cache wasn't defined");
                if let Some(mut category_table) = registry_cache.get::<hlua::LuaTable<_>, _>(category.clone()) {
                    let cat_table = match handle.write(category.clone()) {
                        Ok(cat) => cat,
                        Err(err) => {
                            warn!("Could not lock {}: {:?}", category, err);
                            break;
                        }
                    };
                    update_values(&mut category_table, cat_table);
                }
                drop(registry_cache)
            }
            lua.execute::<()>("__registry_cache = {}")
                .expect("Could not clear __registry_cache");
        },
    }
    return true
}

fn update_values<L>(mut table: &mut hlua::LuaTable<L>,
                    category: &mut registry::Category)
    where L: hlua::AsMutLua {
    let mut keys = Vec::new();
    for entry in table.iter::<String, AnyLuaValue>() {
        if let Some((key, value)) = entry {
            match value {
                AnyLuaValue::LuaOther => {
                    keys.push(key.clone());
                    category.insert(key, Json::Object(BTreeMap::new()));
                },
                value => {
                    match lua_to_json(value) {
                        Ok(val) => {
                            trace!("Updating {}:{} = {:#?}", category.name(), key, &val);
                            category.insert(key, val);
                        },
                        Err(value) => {
                            warn!("Could not translate {:?} to JSON", value);
                        }
                    }
                }
            }
        }
    }
    for key in keys {
        let inner_mapping = category.get_mut(&key)
            .expect("Could not get the value we just made")
            .as_object_mut()
            .expect("The inner value was not an object!");
        if let Some(mut inner_table) = table.get::<hlua::LuaTable<_>, _>(key) {
            for entry in inner_table.iter::<String, AnyLuaValue>() {
                if let Some((key, value)) = entry {
                    match value {
                        AnyLuaValue::LuaOther => {
                            warn!("Dropping inner table {:?}", key);
                        },
                        value => {
                            if let Ok(val) = lua_to_json(value) {
                                inner_mapping.insert(key, val);
                            }
                        }
                    }
                }
            }
        }
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}
<commit_msg>move layout re-tile to lua::init()<commit_after>//! Code for the internal Lua thread which handles all Lua requests.

use std::collections::btree_map::BTreeMap;
use std::thread;
use std::fs::{File};
use std::path::Path;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

use convert::json::lua_to_json;

use rustc_serialize::json::Json;
use uuid::Uuid;
use hlua::{self, Lua, LuaError};
use hlua::any::AnyLuaValue;

use super::types::*;
use super::rust_interop;
use super::init_path;
use super::super::keys;

use registry::{self};

use ::layout::{lock_tree, ContainerType};

lazy_static! {
    /// Sends requests to the Lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the Lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);

    /// Requests to update the registry state from Lua
    static ref REGISTRY_QUEUE: RwLock<Vec<String>> = RwLock::new(vec![]);
}

pub const ERR_LOCK_RUNNING: &'static str = "Lua thread: unable to lock RUNNING";
pub const ERR_LOCK_SENDER: &'static str = "Lua thread: unable to lock SENDER";
pub const ERR_LOCK_QUEUE: &'static str =
    "Lua thread: unable to lock REGISTRY_QUEUE";

const INIT_LUA_FUNC: &'static str = "way_cooler.on_init()";
const LUA_TERMINATE_CODE: &'static str = "way_cooler.on_terminate()";
const LUA_RESTART_CODE: &'static str = "way_cooler.on_restart()";

/// Struct sent to the Lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

// Reexported in lua/mod.rs:11
/// Whether the Lua thread is currently available.
pub fn running() -> bool {
    *RUNNING.read().expect(ERR_LOCK_RUNNING)
}

// Reexported in lua/mod.rs:11
/// Errors which may arise from attempting
/// to sending a message to the Lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

/// Appends this combination of category and key to the registry queue.
pub fn update_registry_value(category: String) {
    let mut queue = REGISTRY_QUEUE.write().expect(ERR_LOCK_QUEUE);
    queue.push(category);
}

// Reexported in lua/mod.rs:11
/// Attemps to send a LuaQuery to the Lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().expect(ERR_LOCK_SENDER);
        match *maybe_sender {
            Some(ref real_sender) => {
                // Senders are designed to be cloneable
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    // Create a response channel
    let (response_tx, response_rx) = channel();
    let message = LuaMessage { reply: response_tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(response_rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the Lua thread.
pub fn init() {
    info!("Initializing lua...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = Lua::new();
    debug!("Loading Lua libraries...");
    lua.openlibs();
    debug!("Loading way-cooler libraries...");
    rust_interop::register_libraries(&mut lua);

    let (use_config, maybe_init_file) = init_path::get_config();
    if use_config {
        match maybe_init_file {
            Ok(init_file) => {
                let _: () = lua.execute_from_reader(init_file)
                    .map(|r| { debug!("Read init.lua successfully"); r })
                    .or_else(|err| {
                        error!("Lua error: {:?}", err);
                        warn!("Defaulting to pre-compiled init.lua");
                        lua.execute(init_path::DEFAULT_CONFIG)
                        })
                    .expect("Unable to load pre-compiled init file");
                debug!("Read init.lua successfully");
            }
            Err(_) => {
                warn!("Defaulting to pre-compiled init.lua");
                let _: () = lua.execute(init_path::DEFAULT_CONFIG)
                    .expect("Unable to load pre-compiled init file");
            }
        }
    }
    else {
        info!("Skipping config search");
    }

    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    debug!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || { main_loop(receiver, &mut lua) });
    // Immediately update all the values that the init file set
    send(LuaQuery::UpdateRegistryFromCache)
        .expect("Could not update registry from cache");

    // Re-tile the layout tree, to make any changes appear immediantly.
    if let Ok(mut tree) = lock_tree() {
        tree.layout_active_of(ContainerType::Root)
            .unwrap_or_else(|_| {
                warn!("Lua thread could not re-tile the layout tree");
            });
        // Yeah this is silly, it's so the active border can be updated properly.
        if let Some(active_id) = tree.active_id() {
            tree.focus(active_id)
                .expect("Could not focus on the focused id");
        }
    }
}

pub fn on_compositor_ready() {
    info!("Running lua on_init()");
    // Call the special init hook function that we read from the init file
    send(LuaQuery::Execute(INIT_LUA_FUNC.to_owned()))
        .err()
        .map(|error| { error!("Lua init callback returned an error: {:?}", error); error });
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                if !handle_message(message, lua) {
                    return
                }
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut Lua) -> bool {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            if let Err(error) = lua.execute::<()>(LUA_TERMINATE_CODE) {
                error!("Lua termination callback returned an error: {:?}", error);
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            info!("Lua thread terminating!");
            return false
        },
        LuaQuery::Restart => {
            trace!("Received restart signal!");
            if let Err(error) = lua.execute::<()>(LUA_RESTART_CODE) {
                error!("Lua restart callback returned an error: {:?}", error);
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            // The only real way to restart
            let _new_handle = thread::Builder::new()
                .name("Lua re-init".to_string())
                .spawn(move || {
                    init();
                    keys::init();
                });

            info!("Lua thread restarting");
            return false
        },
        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },
        LuaQuery::ExecFile(name) => {
            info!("Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("Error executing {}!", name);
                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let Ok
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());
                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },
        LuaQuery::ExecRust(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(Some(result)));
        },
        LuaQuery::HandleKey(press) => {
            trace!("Lua: handling keypress {}", &press);
            let press_ix = press.get_lua_index_string();
            // Access the index
            let code = format!("__key_map['{}']()", press_ix);
            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error handling {}: {:?}", &press, error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Handled keypress okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        }
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
        LuaQuery::UpdateRegistryFromCache => {
            let lock = registry::clients_read();
            // Lua has access to everything
            let client = lock.client(Uuid::nil()).unwrap();
            let mut handle = registry::WriteHandle::new(&client);

            let mut queue = REGISTRY_QUEUE.write().expect(ERR_LOCK_QUEUE);
            for category in queue.drain(0..) {
                let mut registry_cache = lua.get::<hlua::LuaTable<_>, _>("__registry_cache")
                    .expect("__registry_cache wasn't defined");
                if let Some(mut category_table) = registry_cache.get::<hlua::LuaTable<_>, _>(category.clone()) {
                    let cat_table = match handle.write(category.clone()) {
                        Ok(cat) => cat,
                        Err(err) => {
                            warn!("Could not lock {}: {:?}", category, err);
                            break;
                        }
                    };
                    update_values(&mut category_table, cat_table);
                }
                drop(registry_cache)
            }
            lua.execute::<()>("__registry_cache = {}")
                .expect("Could not clear __registry_cache");
        },
    }
    return true
}

fn update_values<L>(mut table: &mut hlua::LuaTable<L>,
                    category: &mut registry::Category)
    where L: hlua::AsMutLua {
    let mut keys = Vec::new();
    for entry in table.iter::<String, AnyLuaValue>() {
        if let Some((key, value)) = entry {
            match value {
                AnyLuaValue::LuaOther => {
                    keys.push(key.clone());
                    category.insert(key, Json::Object(BTreeMap::new()));
                },
                value => {
                    match lua_to_json(value) {
                        Ok(val) => {
                            trace!("Updating {}:{} = {:#?}", category.name(), key, &val);
                            category.insert(key, val);
                        },
                        Err(value) => {
                            warn!("Could not translate {:?} to JSON", value);
                        }
                    }
                }
            }
        }
    }
    for key in keys {
        let inner_mapping = category.get_mut(&key)
            .expect("Could not get the value we just made")
            .as_object_mut()
            .expect("The inner value was not an object!");
        if let Some(mut inner_table) = table.get::<hlua::LuaTable<_>, _>(key) {
            for entry in inner_table.iter::<String, AnyLuaValue>() {
                if let Some((key, value)) = entry {
                    match value {
                        AnyLuaValue::LuaOther => {
                            warn!("Dropping inner table {:?}", key);
                        },
                        value => {
                            if let Ok(val) = lua_to_json(value) {
                                inner_mapping.insert(key, val);
                            }
                        }
                    }
                }
            }
        }
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use super::condition_register::ConditionRegister;
use super::exception::Exception;
use super::instruction::Instruction;
use super::mmu;
use super::machine_status::MachineStatus;
use super::time_base_register::TimeBaseRegister;
use super::super::interconnect::Interconnect;

const NUM_GPR: usize = 32;
const NUM_SPR: usize = 1023;
const NUM_SR : usize = 16;

const XER : usize = 1;
const HID0: usize = 1008;

pub struct Cpu {
    pub interconnect: Interconnect,
    pub mmu: mmu::Mmu,
    cia: u32,
    nia: u32,
    ctr: u32,
    gpr: [u32; NUM_GPR],
    spr: [u32; NUM_SPR], // ToDo phase out
    pub msr: MachineStatus,
    sr: [u32; NUM_SR],
    cr: ConditionRegister,
    lr: u32,
    tb: TimeBaseRegister
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        let mut cpu = Cpu {
            interconnect: interconnect,
            mmu: mmu::Mmu::new(),
            cia: 0,
            nia: 0,
            ctr: 0,
            gpr: [0; NUM_GPR],
            spr: [0; NUM_SPR],
            msr: MachineStatus::default(),
            sr: [0; NUM_SR],
            cr: ConditionRegister::default(),
            lr: 0,
            tb: TimeBaseRegister::default()
        };

        cpu.exception(Exception::SystemReset); // power on reset
        cpu
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction();

        println!("{:#x} {}", self.cia, instr.opcode());

        self.nia = self.cia + 4;

        match instr.opcode() {
            10 => self.cmpli(instr),
            14 => self.addi(instr),
            15 => self.addis(instr),
            16 => self.bcx(instr),
            18 => self.bx(instr),
            19 => {
                match instr.subopcode() {
                    16 => self.bclrx(instr),
                    150 => self.isync(instr),
                    _ => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }
            },
            21 => self.rlwinm(instr),
            24 => { // ori - OR immediate
                self.gpr[instr.a()] = self.gpr[instr.s()] | instr.uimm();
            },
            31 => {

                match instr.subopcode() {
                     28 => self.andx(instr),
                     32 => self.cmpl(instr),
                     40 => self.subfx(instr),
                     83 => self.mfmsr(instr),
                    146 => self.mtmsr(instr),
                    210 => self.mtsr(instr),
                    339 => self.mfspr(instr),
                    371 => self.mftb(instr),
                    467 => self.mtspr(instr),
                    _   => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }

            },
            32 => self.lwz(instr),
            36 => self.stw(instr),
            44 => self.sth(instr),
            _  => panic!("Unrecognized instruction {:#x} {:#b}", instr.0, instr.opcode())
        }

        self.cia = self.nia;

        // tick timer
        self.tb.advance();
    }

    fn read_instruction(&mut self) -> Instruction {
        let addr = self.mmu.translate_address(mmu::BatType::Instruction, &self.msr, self.cia);

        Instruction(self.interconnect.read_word(addr))
    }

    // FixMe: handle exceptions properly
    pub fn exception(&mut self, e: Exception) {
        let nia = match e {
            Exception::SystemReset => 0x00100
        };

        if self.msr.exception_prefix {
            self.cia = nia ^ 0xFFF00000
        } else {
            self.cia = nia
        }

        println!("{:#x} exception occurred, nia {:#x}", nia, self.cia);
    }

    // complare logic immediate
    fn cmpli(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = instr.uimm();

        let mut c:u8 = if a < b {
            0b1000
        } else if a > b {
            0b0100
        } else {
            0b0010
        };

        c |= self.spr[XER] as u8 & 0b1;

        self.cr.set_field(instr.crfd(), c);
    }

    // add immediate
    fn addi(&mut self, instr: Instruction) {
        let a = instr.a();
        if a == 0 {
            self.gpr[instr.d()] = instr.uimm();
        } else {
            self.gpr[instr.d()] = self.gpr[a] + instr.uimm();
        }
    }

    // add immediate shifted
    fn addis(&mut self, instr: Instruction) {
        if instr.a() == 0 { // lis
            self.gpr[instr.d()] = instr.uimm() << 16;
        } else { // subis
            self.gpr[instr.d()] = self.gpr[instr.a()] + (instr.uimm() << 16);
        }
    }

    // branch conditional
    fn bcx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr = self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr.get_bit(instr.bi())))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            if instr.aa() == 1 {
                self.nia = sign_ext_16(instr.bd() << 2) as u32;
            } else {
                self.nia = self.cia.wrapping_add(sign_ext_16(instr.bd() << 2) as u32);
            }

            if instr.lk() == 1 {
                self.lr = self.cia + 4;
            }
        }
    }

    // branch
    fn bx(&mut self, instr: Instruction) {
        if instr.aa() == 1 {
            self.nia = sign_ext_26(instr.li() << 2) as u32;
        } else {
            self.nia = self.cia.wrapping_add(sign_ext_26(instr.li() << 2) as u32);
        }

        if instr.lk() == 1 {
            self.lr = self.cia + 4;
        }
    }

    // branch conditional to link register
    fn bclrx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr = self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr.get_bit(instr.bi())))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            self.nia = self.lr & 0b00;

            if instr.lk() == 1 {
                self.lr = self.cia + 4;
            }
        }
    }

    #[allow(unused_variables)]
    // isync - instruction synchronize
    fn isync(&mut self, instr: Instruction) {
        // don't do anything
    }

    // rotate word immediate then AND with mask
    fn rlwinm(&mut self, instr: Instruction) {
        let r = self.gpr[instr.s()] << instr.sh();
        let m = mask(instr.mb(), instr.me());

        self.gpr[instr.a()] = r & m;
    }

    fn andx(&mut self, instr: Instruction) {
        self.gpr[instr.a()] = self.gpr[instr.d()] & self.gpr[instr.b()];

        if instr.rc() {
            self.cr.set_field(0, self.gpr[instr.a()] as u8);
        }
    }

    // ToDo: if L = 1, instruction form is invalid
    fn cmpl(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = self.gpr[instr.b()];

        let mut c:u8 = if a < b {
            0b1000
        } else if a > b {
            0b0100
        } else {
            0b0010
        };

        c |= self.spr[XER] as u8 & 0b1;

        self.cr.set_field(instr.crfd(), c);
    }

    // subtract from
    fn subfx(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.gpr[instr.a()].wrapping_sub(self.gpr[instr.b()]);

        if instr.rc() {
            self.cr.set_field(0, self.gpr[instr.d()] as u8);
        }

        // TODO: update XER if OE = 1
    }

    // move from machine state register
    fn mfmsr(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.msr.as_u32();

        // TODO: check privelege level
    }

    // move to machine state register
    fn mtmsr(&mut self, instr: Instruction) {
        self.msr = self.gpr[instr.s()].into();

        // TODO: check privelege level
    }

    // move to segment register
    fn mtsr(&mut self, instr: Instruction) {
        self.sr[instr.sr()] = self.gpr[instr.s()];

        // TODO: check privelege level -> supervisor level instruction
    }

    // move from special purpose register
    fn mfspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.gpr[instr.s()] = self.lr,
            9 => self.gpr[instr.s()] = self.ctr,
            _ => {
                println!("FIXME: spr {} not implemented", n);
                self.gpr[instr.s()] = self.spr[n];
            }
        }

        // TODO: check privelege level
    }

    // move from time base
    fn mftb(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        match n {
            268 => self.gpr[instr.d()] = self.tb.l(),
            269 => self.gpr[instr.d()] = self.tb.u(),
            _ => panic!("Unrecognized TBR {}", n) // FixMe: invoke error handler
        }
    }

    // move special purpose register
    fn mtspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.lr = self.gpr[instr.s()],
            9 => self.ctr = self.gpr[instr.s()],
            528 ... 543 => { // if IBAT or DBAT, write to MMU register
                self.mmu.write_bat_reg(n, self.gpr[instr.s()]);
                //panic!("FixMe: write to BAT registers");
            },
            _ => {
                println!("FIXME: mtspr {} not implemented", n);
                self.spr[n] = self.gpr[instr.s()];
            }
        }

        // TODO: check privelege level
    }

    // load word and zero
    fn lwz(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.gpr[instr.d()] = self.interconnect.read_word(addr);
    }

    // store word
    fn stw(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.interconnect.write_word(addr, self.gpr[instr.s()]);
    }

    // store half word
    fn sth(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.interconnect.write_halfword(addr, self.gpr[instr.s()] as u16);
    }
}

//((1 << (x - y +1)) - 1) << y
// FixMe: not sure if this is correct
// actually I think this might be backwards
fn mask(x: u8, y: u8) -> u32 {
    let mut mask:u32 = 0xFFFFFFFF >> y;

    if x >= 31 {
        mask ^= 0;
    } else {
        mask ^= 0xFFFFFFFF >> (x + 1);
    }

    if y > x {
        !mask
    } else {
        mask
    }
}

// Note: A cast from a signed value widens with signed-extension
//       A cast from an unsigned value widens with zero-extension
fn sign_ext_16(x: u16) -> i32 {
    (x as i16) as i32
}

fn sign_ext_26(x: u32) -> i32 {
    if x & 0x2000000 != 0 {
        (x | 0xFC000000) as i32
    } else {
        x as i32
    }
}

fn bon(bo: u8, n: u8) -> u8 {
    (bo >> (4-n)) & 1
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MSR: {:?} gpr: {:?}, sr: {:?}, cr:{:?}, HID0: {}", self.msr, self.gpr, self.sr, self.cr, self.spr[HID0])
    }
}
<commit_msg>fix bug in bclrx<commit_after>use std::fmt;

use super::condition_register::ConditionRegister;
use super::exception::Exception;
use super::instruction::Instruction;
use super::mmu;
use super::machine_status::MachineStatus;
use super::time_base_register::TimeBaseRegister;
use super::super::interconnect::Interconnect;

const NUM_GPR: usize = 32;
const NUM_SPR: usize = 1023;
const NUM_SR : usize = 16;

const XER : usize = 1;
const HID0: usize = 1008;

pub struct Cpu {
    pub interconnect: Interconnect,
    pub mmu: mmu::Mmu,
    cia: u32,
    nia: u32,
    ctr: u32,
    gpr: [u32; NUM_GPR],
    spr: [u32; NUM_SPR], // ToDo phase out
    pub msr: MachineStatus,
    sr: [u32; NUM_SR],
    cr: ConditionRegister,
    lr: u32,
    tb: TimeBaseRegister
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        let mut cpu = Cpu {
            interconnect: interconnect,
            mmu: mmu::Mmu::new(),
            cia: 0,
            nia: 0,
            ctr: 0,
            gpr: [0; NUM_GPR],
            spr: [0; NUM_SPR],
            msr: MachineStatus::default(),
            sr: [0; NUM_SR],
            cr: ConditionRegister::default(),
            lr: 0,
            tb: TimeBaseRegister::default()
        };

        cpu.exception(Exception::SystemReset); // power on reset
        cpu
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction();

        println!("{:#x} {}", self.cia, instr.opcode());

        self.nia = self.cia + 4;

        match instr.opcode() {
            10 => self.cmpli(instr),
            14 => self.addi(instr),
            15 => self.addis(instr),
            16 => self.bcx(instr),
            18 => self.bx(instr),
            19 => {
                match instr.subopcode() {
                    16 => self.bclrx(instr),
                    150 => self.isync(instr),
                    _ => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }
            },
            21 => self.rlwinm(instr),
            24 => { // ori - OR immediate
                self.gpr[instr.a()] = self.gpr[instr.s()] | instr.uimm();
            },
            31 => {

                match instr.subopcode() {
                     28 => self.andx(instr),
                     32 => self.cmpl(instr),
                     40 => self.subfx(instr),
                     83 => self.mfmsr(instr),
                    146 => self.mtmsr(instr),
                    210 => self.mtsr(instr),
                    339 => self.mfspr(instr),
                    371 => self.mftb(instr),
                    467 => self.mtspr(instr),
                    _   => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }

            },
            32 => self.lwz(instr),
            36 => self.stw(instr),
            44 => self.sth(instr),
            _  => panic!("Unrecognized instruction {:#x} {:#b}", instr.0, instr.opcode())
        }

        self.cia = self.nia;

        // tick timer
        self.tb.advance();
    }

    fn read_instruction(&mut self) -> Instruction {
        let addr = self.mmu.translate_address(mmu::BatType::Instruction, &self.msr, self.cia);

        Instruction(self.interconnect.read_word(addr))
    }

    // FixMe: handle exceptions properly
    pub fn exception(&mut self, e: Exception) {
        let nia = match e {
            Exception::SystemReset => 0x00100
        };

        if self.msr.exception_prefix {
            self.cia = nia ^ 0xFFF00000
        } else {
            self.cia = nia
        }

        println!("{:#x} exception occurred, nia {:#x}", nia, self.cia);
    }

    // complare logic immediate
    fn cmpli(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = instr.uimm();

        let mut c:u8 = if a < b {
            0b1000
        } else if a > b {
            0b0100
        } else {
            0b0010
        };

        c |= self.spr[XER] as u8 & 0b1;

        self.cr.set_field(instr.crfd(), c);
    }

    // add immediate
    fn addi(&mut self, instr: Instruction) {
        let a = instr.a();
        if a == 0 {
            self.gpr[instr.d()] = instr.uimm();
        } else {
            self.gpr[instr.d()] = self.gpr[a] + instr.uimm();
        }
    }

    // add immediate shifted
    fn addis(&mut self, instr: Instruction) {
        if instr.a() == 0 { // lis
            self.gpr[instr.d()] = instr.uimm() << 16;
        } else { // subis
            self.gpr[instr.d()] = self.gpr[instr.a()] + (instr.uimm() << 16);
        }
    }

    // branch conditional
    fn bcx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr = self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr.get_bit(instr.bi())))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            if instr.aa() == 1 {
                self.nia = sign_ext_16(instr.bd() << 2) as u32;
            } else {
                self.nia = self.cia.wrapping_add(sign_ext_16(instr.bd() << 2) as u32);
            }

            if instr.lk() == 1 {
                self.lr = self.cia + 4;
            }
        }
    }

    // branch
    fn bx(&mut self, instr: Instruction) {
        if instr.aa() == 1 {
            self.nia = sign_ext_26(instr.li() << 2) as u32;
        } else {
            self.nia = self.cia.wrapping_add(sign_ext_26(instr.li() << 2) as u32);
        }

        if instr.lk() == 1 {
            self.lr = self.cia + 4;
        }
    }

    // branch conditional to link register
    fn bclrx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr = self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr.get_bit(instr.bi())))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            self.nia = self.lr & 0xFFFFFFFC;

            if instr.lk() == 1 {
                self.lr = self.cia + 4;
            }
        }
    }

    #[allow(unused_variables)]
    // isync - instruction synchronize
    fn isync(&mut self, instr: Instruction) {
        // don't do anything
    }

    // rotate word immediate then AND with mask
    fn rlwinm(&mut self, instr: Instruction) {
        let r = self.gpr[instr.s()] << instr.sh();
        let m = mask(instr.mb(), instr.me());

        self.gpr[instr.a()] = r & m;
    }

    fn andx(&mut self, instr: Instruction) {
        self.gpr[instr.a()] = self.gpr[instr.d()] & self.gpr[instr.b()];

        if instr.rc() {
            self.cr.set_field(0, self.gpr[instr.a()] as u8);
        }
    }

    // ToDo: if L = 1, instruction form is invalid
    fn cmpl(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = self.gpr[instr.b()];

        let mut c:u8 = if a < b {
            0b1000
        } else if a > b {
            0b0100
        } else {
            0b0010
        };

        c |= self.spr[XER] as u8 & 0b1;

        self.cr.set_field(instr.crfd(), c);
    }

    // subtract from
    fn subfx(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.gpr[instr.a()].wrapping_sub(self.gpr[instr.b()]);

        if instr.rc() {
            self.cr.set_field(0, self.gpr[instr.d()] as u8);
        }

        // TODO: update XER if OE = 1
    }

    // move from machine state register
    fn mfmsr(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.msr.as_u32();

        // TODO: check privelege level
    }

    // move to machine state register
    fn mtmsr(&mut self, instr: Instruction) {
        self.msr = self.gpr[instr.s()].into();

        // TODO: check privelege level
    }

    // move to segment register
    fn mtsr(&mut self, instr: Instruction) {
        self.sr[instr.sr()] = self.gpr[instr.s()];

        // TODO: check privelege level -> supervisor level instruction
    }

    // move from special purpose register
    fn mfspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.gpr[instr.s()] = self.lr,
            9 => self.gpr[instr.s()] = self.ctr,
            _ => {
                println!("FIXME: spr {} not implemented", n);
                self.gpr[instr.s()] = self.spr[n];
            }
        }

        // TODO: check privelege level
    }

    // move from time base
    fn mftb(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        match n {
            268 => self.gpr[instr.d()] = self.tb.l(),
            269 => self.gpr[instr.d()] = self.tb.u(),
            _ => panic!("Unrecognized TBR {}", n) // FixMe: invoke error handler
        }
    }

    // move special purpose register
    fn mtspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.lr = self.gpr[instr.s()],
            9 => self.ctr = self.gpr[instr.s()],
            528 ... 543 => { // if IBAT or DBAT, write to MMU register
                self.mmu.write_bat_reg(n, self.gpr[instr.s()]);
                //panic!("FixMe: write to BAT registers");
            },
            _ => {
                println!("FIXME: mtspr {} not implemented", n);
                self.spr[n] = self.gpr[instr.s()];
            }
        }

        // TODO: check privelege level
    }

    // load word and zero
    fn lwz(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.gpr[instr.d()] = self.interconnect.read_word(addr);
    }

    // store word
    fn stw(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.interconnect.write_word(addr, self.gpr[instr.s()]);
    }

    // store half word
    fn sth(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.translate_address(mmu::BatType::Data, &self.msr, ea);

        self.interconnect.write_halfword(addr, self.gpr[instr.s()] as u16);
    }
}

//((1 << (x - y +1)) - 1) << y
// FixMe: not sure if this is correct
// actually I think this might be backwards
fn mask(x: u8, y: u8) -> u32 {
    let mut mask:u32 = 0xFFFFFFFF >> y;

    if x >= 31 {
        mask ^= 0;
    } else {
        mask ^= 0xFFFFFFFF >> (x + 1);
    }

    if y > x {
        !mask
    } else {
        mask
    }
}

// Note: A cast from a signed value widens with signed-extension
//       A cast from an unsigned value widens with zero-extension
fn sign_ext_16(x: u16) -> i32 {
    (x as i16) as i32
}

fn sign_ext_26(x: u32) -> i32 {
    if x & 0x2000000 != 0 {
        (x | 0xFC000000) as i32
    } else {
        x as i32
    }
}

fn bon(bo: u8, n: u8) -> u8 {
    (bo >> (4-n)) & 1
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MSR: {:?} gpr: {:?}, sr: {:?}, cr:{:?}, HID0: {}", self.msr, self.gpr, self.sr, self.cr, self.spr[HID0])
    }
}
<|endoftext|>