<commit_before>use parking_lot::Mutex;
use std::cmp::{max, min};
use std::sync::Arc;

use driver::cmd::Args;
use gc::swiper::large::LargeSpace;
use gc::swiper::old::OldGen;
use gc::swiper::young::YoungGen;
use gc::swiper::CollectionKind;
use gc::{align_gen, formatted_size, GEN_SIZE, M};
use mem;
use os::signal::Trap;
use stdlib;
use timer;

const MAX_YOUNG_SIZE: usize = 20 * M;

const INIT_HEAP_SIZE_RATIO: usize = 2;
const INIT_YOUNG_RATIO: usize = 4;
const INIT_SEMI_RATIO: usize = 3;

pub fn init(config: &mut HeapConfig, args: &Args) {
    assert!(config.min_heap_size <= config.max_heap_size);

    let young_size = if let Some(young_ratio) = args.young_ratio() {
        assert!(young_ratio >= 1);
        align_gen(config.max_heap_size / young_ratio)
    } else if let Some(young_size) = args.young_size() {
        min(align_gen(young_size), config.max_heap_size - GEN_SIZE)
    } else if args.young_appel() {
        let max_heap_size = (config.max_heap_size as f64 * 0.9) as usize;
        align_gen(max_heap_size / 2)
    } else {
        let young_size = align_gen(config.max_heap_size / INIT_YOUNG_RATIO);
        min(MAX_YOUNG_SIZE, young_size)
    };

    let young_size = max(young_size, GEN_SIZE);
    let (eden_size, semi_size) = calculate_young_size(args, young_size, 0);

    config.eden_size = eden_size;
    config.semi_size = semi_size;

    let max_old_limit = config.max_heap_size - young_size;
    let min_old_limit = if config.min_heap_size > young_size {
        config.min_heap_size - young_size
    } else {
        0
    };

    let old_limit = align_gen(config.max_heap_size / INIT_HEAP_SIZE_RATIO);
    let old_limit = min(old_limit, max_old_limit);
    let old_limit = max(old_limit, min_old_limit);

    config.old_size = 0;
    config.old_limit = old_limit;
}

fn calculate_young_size(args: &Args, young_size: usize, min_semi_size: usize) -> (usize, usize) {
    let semi_ratio = args.flag_gc_semi_ratio.unwrap_or(INIT_SEMI_RATIO);
    let semi_size = if semi_ratio == 0 {
        0
    } else {
        align_gen(young_size / semi_ratio)
    };

    let semi_size = max(semi_size, min_semi_size);
    let semi_size = max(semi_size, GEN_SIZE);
    let eden_size = young_size - semi_size;

    (eden_size, semi_size)
}

pub fn choose_collection_kind(
    config: &SharedHeapConfig,
    args: &Args,
    young: &YoungGen,
) -> CollectionKind {
    let (eden_size, semi_size) = young.committed_size();
    let young_size = eden_size + semi_size;

    let rest = {
        let config = config.lock();
        config.old_limit - config.old_size
    };

    if args.young_ratio().is_some() {
        // With a large young generation with e.g. 1/2 or 1/3 of the
        // maximum heap size, we would do full collections most of the time.
        // Therefore always perform a minor collection. If objects cannot be promoted,
        // a full collection is performed automatically.
        return CollectionKind::Minor;
    }

    if rest < young_size {
        CollectionKind::Full
    } else {
        CollectionKind::Minor
    }
}

pub fn start(config: &SharedHeapConfig, young: &YoungGen, old: &OldGen, large: &LargeSpace) {
    let mut config = config.lock();

    config.gc_start = timer::timestamp();
    config.start_object_size = object_size(young, old, large);
    config.start_memory_size = memory_size(young, old, large);
}

pub fn stop(
    config: &SharedHeapConfig,
    kind: CollectionKind,
    young: &YoungGen,
    old: &OldGen,
    large: &LargeSpace,
    args: &Args,
) {
    let mut config = config.lock();

    let gc_end = timer::timestamp();
    config.gc_duration = timer::in_ms(gc_end - config.gc_start);

    config.end_object_size = object_size(young, old, large);
    config.end_memory_size = memory_size(young, old, large);

    assert!(young.eden_active().empty());
    let (eden_size, semi_size) = young.committed_size();
    let mut young_size = eden_size + semi_size;

    let old_size = old.committed_size() + large.committed_size();
    config.old_size = old_size;

    if args.young_appel() {
        config.old_limit = align_gen((config.old_size as f64 * 1.1) as usize);
        let max_young_size = config.max_heap_size - config.old_limit;
        let target_young_size = align_gen(max_young_size / 2);

        assert_eq!(young.eden_active().size(), 0);
        assert_eq!(young.to_active().size(), 0);
        let from_size = young.from_active().size();
        let min_semi_size = align_gen(mem::page_align(from_size) * 2);

        let (eden_size, semi_size) = calculate_young_size(args, target_young_size, min_semi_size);
        young_size = eden_size + semi_size;

        young.set_committed_size(eden_size, semi_size);
    } else {
        let old_limit = config.max_heap_size - young_size;
        let old_limit = max(old_limit, old_size);
        config.old_limit = old_limit;
    }

    if young_size + config.old_limit > config.max_heap_size {
        stdlib::trap(Trap::OOM.int());
    }

    assert!(young_size + config.old_limit <= config.max_heap_size);

    match kind {
        CollectionKind::Minor => {
            config.total_minor_collections += 1;
            config.total_minor_pause += config.gc_duration;
        }

        CollectionKind::Full => {
            config.total_full_collections += 1;
            config.total_full_pause += config.gc_duration;
        }
    }

    if args.flag_gc_verbose {
        print(&*config, kind);
    }
}

fn print(config: &HeapConfig, kind: CollectionKind) {
    match kind {
        CollectionKind::Minor => {
            println!(
                "GC: {} {}/{} -> {}/{}; {:.2} ms; {} promoted; {} copied",
                kind,
                formatted_size(config.start_object_size),
                formatted_size(config.start_memory_size),
                formatted_size(config.end_object_size),
                formatted_size(config.end_memory_size),
                config.gc_duration,
                formatted_size(config.minor_promoted),
                formatted_size(config.minor_copied),
            );
        }

        CollectionKind::Full => {
            println!(
                "GC: {} {}/{} -> {}/{}; {:.2} ms",
                kind,
                formatted_size(config.start_object_size),
                formatted_size(config.start_memory_size),
                formatted_size(config.end_object_size),
                formatted_size(config.end_memory_size),
                config.gc_duration,
            );
        }
    }
}

fn object_size(young: &YoungGen, old: &OldGen, large: &LargeSpace) -> usize {
    young.active_size() + old.active_size() + large.committed_size()
}

fn memory_size(young: &YoungGen, old: &OldGen, large: &LargeSpace) -> usize {
    let (eden_size, semi_size) = young.committed_size();
    let young_size = eden_size + semi_size;

    young_size + old.committed_size() + large.committed_size()
}

pub struct HeapConfig {
    min_heap_size: usize,
    max_heap_size: usize,

    pub eden_size: usize,
    pub semi_size: usize,
    pub old_size: usize,
    pub old_limit: usize,

    gc_start: u64,
    gc_duration: f32,

    start_object_size: usize,
    start_memory_size: usize,
    end_object_size: usize,
    end_memory_size: usize,

    pub minor_promoted: usize,
    pub minor_copied: usize,

    pub total_minor_collections: usize,
    pub total_minor_pause: f32,
    pub total_full_collections: usize,
    pub total_full_pause: f32,
}

impl HeapConfig {
    pub fn new(min_heap_size: usize, max_heap_size: usize) -> HeapConfig {
        assert!(min_heap_size <= max_heap_size);

        HeapConfig {
            min_heap_size: min_heap_size,
            max_heap_size: max_heap_size,

            eden_size: 0,
            semi_size: 0,
            old_size: 0,
            old_limit: 0,

            gc_start: 0,
            gc_duration: 0f32,

            start_object_size: 0,
            start_memory_size: 0,
            end_object_size: 0,
            end_memory_size: 0,

            minor_promoted: 0,
            minor_copied: 0,

            total_minor_collections: 0,
            total_minor_pause: 0f32,
            total_full_collections: 0,
            total_full_pause: 0f32,
        }
    }

    pub fn grow_old(&mut self, size: usize) -> bool {
        if self.old_size + size <= self.old_limit {
            self.old_size += size;
            true
        } else {
            false
        }
    }
}

pub type SharedHeapConfig = Arc<Mutex<HeapConfig>>;
<commit_msg>swiper: force full collection with appel<commit_after>use parking_lot::Mutex;
use std::cmp::{max, min};
use std::sync::Arc;

use driver::cmd::Args;
use gc::swiper::large::LargeSpace;
use gc::swiper::old::OldGen;
use gc::swiper::young::YoungGen;
use gc::swiper::CollectionKind;
use gc::{align_gen, formatted_size, GEN_SIZE, M};
use mem;
use os::signal::Trap;
use stdlib;
use timer;

const MAX_YOUNG_SIZE: usize = 20 * M;

const INIT_HEAP_SIZE_RATIO: usize = 2;
const INIT_YOUNG_RATIO: usize = 4;
const INIT_SEMI_RATIO: usize = 3;

pub fn init(config: &mut HeapConfig, args: &Args) {
    assert!(config.min_heap_size <= config.max_heap_size);

    let young_size = if let Some(young_ratio) = args.young_ratio() {
        assert!(young_ratio >= 1);
        align_gen(config.max_heap_size / young_ratio)
    } else if let Some(young_size) = args.young_size() {
        min(align_gen(young_size), config.max_heap_size - GEN_SIZE)
    } else if args.young_appel() {
        let max_heap_size = (config.max_heap_size as f64 * 0.9) as usize;
        align_gen(max_heap_size / 2)
    } else {
        let young_size = align_gen(config.max_heap_size / INIT_YOUNG_RATIO);
        min(MAX_YOUNG_SIZE, young_size)
    };

    let young_size = max(young_size, GEN_SIZE);
    let (eden_size, semi_size) = calculate_young_size(args, young_size, 0);

    config.eden_size = eden_size;
    config.semi_size = semi_size;

    let max_old_limit = config.max_heap_size - young_size;
    let min_old_limit = if config.min_heap_size > young_size {
        config.min_heap_size - young_size
    } else {
        0
    };

    let old_limit = align_gen(config.max_heap_size / INIT_HEAP_SIZE_RATIO);
    let old_limit = min(old_limit, max_old_limit);
    let old_limit = max(old_limit, min_old_limit);

    config.old_size = 0;
    config.old_limit = old_limit;
}

fn calculate_young_size(args: &Args, young_size: usize, min_semi_size: usize) -> (usize, usize) {
    let semi_ratio = args.flag_gc_semi_ratio.unwrap_or(INIT_SEMI_RATIO);
    let semi_size = if semi_ratio == 0 {
        0
    } else {
        align_gen(young_size / semi_ratio)
    };

    let semi_size = max(semi_size, min_semi_size);
    let semi_size = max(semi_size, GEN_SIZE);
    let eden_size = young_size - semi_size;

    (eden_size, semi_size)
}

pub fn choose_collection_kind(
    config: &SharedHeapConfig,
    args: &Args,
    young: &YoungGen,
) -> CollectionKind {
    let (eden_size, semi_size) = young.committed_size();
    let young_size = eden_size + semi_size;

    let rest = {
        let config = config.lock();
        config.old_limit - config.old_size
    };

    if args.young_ratio().is_some() {
        // With a large young generation with e.g. 1/2 or 1/3 of the
        // maximum heap size, we would do full collections most of the time.
        // Therefore always perform a minor collection. If objects cannot be promoted,
        // a full collection is performed automatically.
        return CollectionKind::Minor;
    }

    if args.young_appel() {
        return if rest < M {
            CollectionKind::Full
        } else {
            CollectionKind::Minor
        };
    }

    if rest < young_size {
        CollectionKind::Full
    } else {
        CollectionKind::Minor
    }
}

pub fn start(config: &SharedHeapConfig, young: &YoungGen, old: &OldGen, large: &LargeSpace) {
    let mut config = config.lock();

    config.gc_start = timer::timestamp();
    config.start_object_size = object_size(young, old, large);
    config.start_memory_size = memory_size(young, old, large);
}

pub fn stop(
    config: &SharedHeapConfig,
    kind: CollectionKind,
    young: &YoungGen,
    old: &OldGen,
    large: &LargeSpace,
    args: &Args,
) {
    let mut config = config.lock();

    let gc_end = timer::timestamp();
    config.gc_duration = timer::in_ms(gc_end - config.gc_start);

    config.end_object_size = object_size(young, old, large);
    config.end_memory_size = memory_size(young, old, large);

    assert!(young.eden_active().empty());
    let (eden_size, semi_size) = young.committed_size();
    let mut young_size = eden_size + semi_size;

    let old_size = old.committed_size() + large.committed_size();
    config.old_size = old_size;

    if args.young_appel() {
        config.old_limit = align_gen((config.old_size as f64 * 1.1) as usize);
        let max_young_size = config.max_heap_size - config.old_limit;
        let target_young_size = align_gen(max_young_size / 2);

        assert_eq!(young.eden_active().size(), 0);
        assert_eq!(young.to_active().size(), 0);
        let from_size = young.from_active().size();
        let min_semi_size = align_gen(mem::page_align(from_size) * 2);

        let (eden_size, semi_size) = calculate_young_size(args, target_young_size, min_semi_size);
        young_size = eden_size + semi_size;

        young.set_committed_size(eden_size, semi_size);
    } else {
        let old_limit = config.max_heap_size - young_size;
        let old_limit = max(old_limit, old_size);
        config.old_limit = old_limit;
    }

    if young_size + config.old_limit > config.max_heap_size {
        stdlib::trap(Trap::OOM.int());
    }

    assert!(young_size + config.old_limit <= config.max_heap_size);

    match kind {
        CollectionKind::Minor => {
            config.total_minor_collections += 1;
            config.total_minor_pause += config.gc_duration;
        }

        CollectionKind::Full => {
            config.total_full_collections += 1;
            config.total_full_pause += config.gc_duration;
        }
    }

    if args.flag_gc_verbose {
        print(&*config, kind);
    }
}

fn print(config: &HeapConfig, kind: CollectionKind) {
    match kind {
        CollectionKind::Minor => {
            println!(
                "GC: {} {}/{} -> {}/{}; {:.2} ms; {} promoted; {} copied",
                kind,
                formatted_size(config.start_object_size),
                formatted_size(config.start_memory_size),
                formatted_size(config.end_object_size),
                formatted_size(config.end_memory_size),
                config.gc_duration,
                formatted_size(config.minor_promoted),
                formatted_size(config.minor_copied),
            );
        }

        CollectionKind::Full => {
            println!(
                "GC: {} {}/{} -> {}/{}; {:.2} ms",
                kind,
                formatted_size(config.start_object_size),
                formatted_size(config.start_memory_size),
                formatted_size(config.end_object_size),
                formatted_size(config.end_memory_size),
                config.gc_duration,
            );
        }
    }
}

fn object_size(young: &YoungGen, old: &OldGen, large: &LargeSpace) -> usize {
    young.active_size() + old.active_size() + large.committed_size()
}

fn memory_size(young: &YoungGen, old: &OldGen, large: &LargeSpace) -> usize {
    let (eden_size, semi_size) = young.committed_size();
    let young_size = eden_size + semi_size;

    young_size + old.committed_size() + large.committed_size()
}

pub struct HeapConfig {
    min_heap_size: usize,
    max_heap_size: usize,

    pub eden_size: usize,
    pub semi_size: usize,
    pub old_size: usize,
    pub old_limit: usize,

    gc_start: u64,
    gc_duration: f32,

    start_object_size: usize,
    start_memory_size: usize,
    end_object_size: usize,
    end_memory_size: usize,

    pub minor_promoted: usize,
    pub minor_copied: usize,

    pub total_minor_collections: usize,
    pub total_minor_pause: f32,
    pub total_full_collections: usize,
    pub total_full_pause: f32,
}

impl HeapConfig {
    pub fn new(min_heap_size: usize, max_heap_size: usize) -> HeapConfig {
        assert!(min_heap_size <= max_heap_size);

        HeapConfig {
            min_heap_size: min_heap_size,
            max_heap_size: max_heap_size,

            eden_size: 0,
            semi_size: 0,
            old_size: 0,
            old_limit: 0,

            gc_start: 0,
            gc_duration: 0f32,

            start_object_size: 0,
            start_memory_size: 0,
            end_object_size: 0,
            end_memory_size: 0,

            minor_promoted: 0,
            minor_copied: 0,

            total_minor_collections: 0,
            total_minor_pause: 0f32,
            total_full_collections: 0,
            total_full_pause: 0f32,
        }
    }

    pub fn grow_old(&mut self, size: usize) -> bool {
        if self.old_size + size <= self.old_limit {
            self.old_size += size;
            true
        } else {
            false
        }
    }
}

pub type SharedHeapConfig = Arc<Mutex<HeapConfig>>;
<|endoftext|>


<commit_before>use header::{Header, Raw, Host};
use std::borrow::Cow;
use std::fmt;
use std::str::FromStr;
use header::parsing::from_one_raw_str;

/// The `Origin` header.
///
/// The `Origin` header is a version of the `Referer` header that is used for all HTTP fetches and `POST`s whose CORS flag is set.
/// This header is often used to inform recipients of the security context of where the request was initiated.
///
///
/// Following the spec, https://fetch.spec.whatwg.org/#origin-header, the value of this header is composed of
/// a String (scheme), header::Host (host/port)
///
/// # Examples
/// ```
/// use hyper::header::{Headers, Origin};
///
/// let mut headers = Headers::new();
/// headers.set(
///     Origin::new("http", "hyper.rs", None)
/// );
/// ```
/// ```
/// use hyper::header::{Headers, Origin};
///
/// let mut headers = Headers::new();
/// headers.set(
///     Origin::new("https", "wikipedia.org", Some(443))
/// );
/// ```

#[derive(PartialEq, Clone, Debug)]
pub struct Origin(OriginOrNull);

#[derive(PartialEq, Clone, Debug)]
enum OriginOrNull {
    Origin {
        /// The scheme, such as http or https
        scheme: Cow<'static,str>,
        /// The host, such as Host{hostname: "hyper.rs".to_owned(), port: None}
        host: Host,
    },
    Null,
}

impl Origin {
    /// Creates a new `Origin` header.
    pub fn new<S: Into<Cow<'static,str>>, H: Into<Cow<'static,str>>>(scheme: S, hostname: H, port: Option<u16>) -> Origin{
        Origin(OriginOrNull::Origin {
            scheme: scheme.into(),
            host: Host::new(hostname, port),
        })
    }

    /// Creates a `Null` `Origin` header.
    pub fn null() -> Origin {
        Origin(OriginOrNull::Null)
    }

    /// Checks if `Origin` is `Null`.
    pub fn is_null(&self) -> bool {
        match self {
            &Origin(OriginOrNull::Null) => true,
            _ => false,
        }
    }

    /// The scheme, such as http or https
    /// ```
    /// use hyper::header::Origin;
    /// let origin = Origin::new("https", "foo.com", Some(443));
    /// assert_eq!(origin.scheme(), Some("https"));
    /// ```
    pub fn scheme(&self) -> Option<&str> {
        match self {
            &Origin(OriginOrNull::Origin { ref scheme, .. }) => Some(&scheme),
            _ => None,
        }
    }

    /// The host, such as Host{hostname: "hyper.rs".to_owned(), port: None}
    /// ```
    /// use hyper::header::{Origin,Host};
    /// let origin = Origin::new("https", "foo.com", Some(443));
    /// assert_eq!(origin.host(), Some(&Host::new("foo.com", Some(443))));
    /// ```
    pub fn host(&self) -> Option<&Host> {
        match self {
            &Origin(OriginOrNull::Origin { ref host, .. }) => Some(&host),
            _ => None,
        }
    }
}

impl Header for Origin {
    fn header_name() -> &'static str {
        static NAME: &'static str = "Origin";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<Origin> {
        from_one_raw_str(raw)
    }

    fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
        f.fmt_line(self)
    }
}

static HTTP : &'static str = "http";
static HTTPS : &'static str = "https";

impl FromStr for Origin {
    type Err = ::Error;

    fn from_str(s: &str) -> ::Result<Origin> {
        let idx = match s.find("://") {
            Some(idx) => idx,
            None => return Err(::Error::Header)
        };
        // idx + 3 because that's how long "://" is
        let (scheme, etc) = (&s[..idx], &s[idx + 3..]);
        let host = try!(Host::from_str(etc));
        let scheme = match scheme {
            "http"  => Cow::Borrowed(HTTP),
            "https" => Cow::Borrowed(HTTPS),
            s       => Cow::Owned(s.to_owned())
        };

        Ok(Origin(OriginOrNull::Origin {
            scheme: scheme,
            host: host
        }))
    }
}

impl fmt::Display for Origin {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Origin(OriginOrNull::Origin { ref scheme, ref host }) => write!(f, "{}://{}", scheme, host),
            /// Serialized as "null" per ASCII serialization of an origin
            /// https://html.spec.whatwg.org/multipage/browsers.html#ascii-serialisation-of-an-origin
            _ => write!(f, "null")
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Origin;
    use header::Header;
    use std::borrow::Cow;

    macro_rules! assert_borrowed{
        ($expr : expr) => {
            match $expr {
                Cow::Owned(ref v) => panic!("assertion failed: `{}` owns {:?}", stringify!($expr), v),
                _ => {}
            }
        }
    }

    #[test]
    fn test_origin() {
        let origin : Origin = Header::parse_header(&vec![b"http://foo.com".to_vec()].into()).unwrap();
        assert_eq!(&origin, &Origin::new("http", "foo.com", None));
        assert_borrowed!(origin.scheme().unwrap().into());

        let origin : Origin = Header::parse_header(&vec![b"https://foo.com:443".to_vec()].into()).unwrap();
        assert_eq!(&origin, &Origin::new("https", "foo.com", Some(443)));
        assert_borrowed!(origin.scheme().unwrap().into());
    }
}

bench_header!(bench, Origin, { vec![b"https://foo.com".to_vec()] });
<commit_msg>chore(header): fix unused doc comment warning in Origin<commit_after>use header::{Header, Raw, Host};
use std::borrow::Cow;
use std::fmt;
use std::str::FromStr;
use header::parsing::from_one_raw_str;

/// The `Origin` header.
///
/// The `Origin` header is a version of the `Referer` header that is used for all HTTP fetches and `POST`s whose CORS flag is set.
/// This header is often used to inform recipients of the security context of where the request was initiated.
///
///
/// Following the spec, https://fetch.spec.whatwg.org/#origin-header, the value of this header is composed of
/// a String (scheme), header::Host (host/port)
///
/// # Examples
/// ```
/// use hyper::header::{Headers, Origin};
///
/// let mut headers = Headers::new();
/// headers.set(
///     Origin::new("http", "hyper.rs", None)
/// );
/// ```
/// ```
/// use hyper::header::{Headers, Origin};
///
/// let mut headers = Headers::new();
/// headers.set(
///     Origin::new("https", "wikipedia.org", Some(443))
/// );
/// ```

#[derive(PartialEq, Clone, Debug)]
pub struct Origin(OriginOrNull);

#[derive(PartialEq, Clone, Debug)]
enum OriginOrNull {
    Origin {
        /// The scheme, such as http or https
        scheme: Cow<'static,str>,
        /// The host, such as Host{hostname: "hyper.rs".to_owned(), port: None}
        host: Host,
    },
    Null,
}

impl Origin {
    /// Creates a new `Origin` header.
    pub fn new<S: Into<Cow<'static,str>>, H: Into<Cow<'static,str>>>(scheme: S, hostname: H, port: Option<u16>) -> Origin{
        Origin(OriginOrNull::Origin {
            scheme: scheme.into(),
            host: Host::new(hostname, port),
        })
    }

    /// Creates a `Null` `Origin` header.
    pub fn null() -> Origin {
        Origin(OriginOrNull::Null)
    }

    /// Checks if `Origin` is `Null`.
    pub fn is_null(&self) -> bool {
        match self {
            &Origin(OriginOrNull::Null) => true,
            _ => false,
        }
    }

    /// The scheme, such as http or https
    /// ```
    /// use hyper::header::Origin;
    /// let origin = Origin::new("https", "foo.com", Some(443));
    /// assert_eq!(origin.scheme(), Some("https"));
    /// ```
    pub fn scheme(&self) -> Option<&str> {
        match self {
            &Origin(OriginOrNull::Origin { ref scheme, .. }) => Some(&scheme),
            _ => None,
        }
    }

    /// The host, such as Host{hostname: "hyper.rs".to_owned(), port: None}
    /// ```
    /// use hyper::header::{Origin,Host};
    /// let origin = Origin::new("https", "foo.com", Some(443));
    /// assert_eq!(origin.host(), Some(&Host::new("foo.com", Some(443))));
    /// ```
    pub fn host(&self) -> Option<&Host> {
        match self {
            &Origin(OriginOrNull::Origin { ref host, .. }) => Some(&host),
            _ => None,
        }
    }
}

impl Header for Origin {
    fn header_name() -> &'static str {
        static NAME: &'static str = "Origin";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<Origin> {
        from_one_raw_str(raw)
    }

    fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
        f.fmt_line(self)
    }
}

static HTTP : &'static str = "http";
static HTTPS : &'static str = "https";

impl FromStr for Origin {
    type Err = ::Error;

    fn from_str(s: &str) -> ::Result<Origin> {
        let idx = match s.find("://") {
            Some(idx) => idx,
            None => return Err(::Error::Header)
        };
        // idx + 3 because that's how long "://" is
        let (scheme, etc) = (&s[..idx], &s[idx + 3..]);
        let host = try!(Host::from_str(etc));
        let scheme = match scheme {
            "http"  => Cow::Borrowed(HTTP),
            "https" => Cow::Borrowed(HTTPS),
            s       => Cow::Owned(s.to_owned())
        };

        Ok(Origin(OriginOrNull::Origin {
            scheme: scheme,
            host: host
        }))
    }
}

impl fmt::Display for Origin {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            OriginOrNull::Origin { ref scheme, ref host } => write!(f, "{}://{}", scheme, host),
            // Serialized as "null" per ASCII serialization of an origin
            // https://html.spec.whatwg.org/multipage/browsers.html#ascii-serialisation-of-an-origin
            OriginOrNull::Null => f.write_str("null")
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Origin;
    use header::Header;
    use std::borrow::Cow;

    macro_rules! assert_borrowed{
        ($expr : expr) => {
            match $expr {
                Cow::Owned(ref v) => panic!("assertion failed: `{}` owns {:?}", stringify!($expr), v),
                _ => {}
            }
        }
    }

    #[test]
    fn test_origin() {
        let origin : Origin = Header::parse_header(&vec![b"http://foo.com".to_vec()].into()).unwrap();
        assert_eq!(&origin, &Origin::new("http", "foo.com", None));
        assert_borrowed!(origin.scheme().unwrap().into());

        let origin : Origin = Header::parse_header(&vec![b"https://foo.com:443".to_vec()].into()).unwrap();
        assert_eq!(&origin, &Origin::new("https", "foo.com", Some(443)));
        assert_borrowed!(origin.scheme().unwrap().into());
    }
}

bench_header!(bench, Origin, { vec![b"https://foo.com".to_vec()] });
<|endoftext|>


<commit_before><commit_msg>fixup! factor::numeric::Montgomery: Fix overflow bug<commit_after><|endoftext|>


<commit_before>use arraymap::ArrayMap;
use itertools::Itertools;
use mli::*;
use mli_ndarray::Ndeep;
use ndarray::{Array, Array1, Array2, OwnedRepr};

type D1 = ndarray::Ix1;

fn corners(coordinate: [f32; 2]) -> [[isize; 2]; 4] {
    let c00 = coordinate.map(|f| f.floor() as isize);
    let c11 = coordinate.map(|f| f.ceil() as isize);
    let c01 = [c00[0], c11[1]];
    let c10 = [c11[0], c00[1]];
    [c00, c01, c10, c11]
}

/// Looks up a position gradient from a location in the features using bilinear interpolation and zero-padding.
fn bilinear_position_gradient(f: [f32; 4], rc: [f32; 2]) -> [f32; 2] {
    // Perform the y interpolation to get the x values.
    let fx = [
        (1.0 - rc[0]) * f[0] + rc[0] * f[2],
        (1.0 - rc[0]) * f[1] + rc[0] * f[3],
    ];

    // Perform the x interpolation to get the y values.
    let fy = [
        (1.0 - rc[1]) * f[0] + rc[1] * f[1],
        (1.0 - rc[1]) * f[2] + rc[1] * f[3],
    ];

    // The gradient is the difference between the interpolation values in each dimension.
    [fy[1] - fy[0], fx[1] - fx[0]]
}

pub struct DefConvData<'a> {
    pub features: &'a Array2<f32>,
    pub offsets: &'a Array2<f32>,
}

impl<'a> DefConvData<'a> {
    fn validate_corners(&self, coordinate: [f32; 2]) -> ([Option<[usize; 2]>; 4], [f32; 2]) {
        // Get the integer versions of four corners.
        let coords = corners(coordinate);

        // Get the relative coordinate.
        let rc = [
            coordinate[0] - coords[0][0] as f32,
            coordinate[1] - coords[0][1] as f32,
        ];

        // Create a closure to detect out-of-bounds.
        let in_bounds = |[y, x]: [isize; 2]| {
            if y < 0
                || x < 0
                || y >= self.features.shape()[0] as isize
                || x >= self.features.shape()[1] as isize
            {
                None
            } else {
                Some([y, x].map(|&n| n as usize))
            }
        };

        // Create a closure to extract the feature with zero-padding.
        let extract = |c| in_bounds(c);

        (coords.map(|&c| extract(c)), rc)
    }

    /// Extracts the corner features and relative coordinate for a bilinear interpolation.
    fn extract_corners(&self, validated_corners: [Option<[usize; 2]>; 4]) -> [f32; 4] {
        validated_corners.map(|c| c.as_ref().map(|&c| self.features[c]).unwrap_or(0.0))
    }

    /// Looks up a location in the features using bilinear interpolation and zero-padding.
    fn bilinear(&self, coordinate: [f32; 2]) -> f32 {
        // Extract the corner features and the relative coordinate.
        let (validated_corners, rc) = self.validate_corners(coordinate);
        let f = self.extract_corners(validated_corners);

        // Perform the y interpolation.
        let fx = [
            (1.0 - rc[0]) * f[0] + rc[0] * f[2],
            (1.0 - rc[0]) * f[1] + rc[0] * f[3],
        ];

        // Perform the x interpolation.
        (1.0 - rc[1]) * fx[0] + rc[1] * fx[1]
    }
}

#[derive(Clone, Debug)]
pub struct DefConv2 {
    weights: Array1<f32>,
    output_shape: [usize; 2],
}

impl DefConv2 {
    pub fn new(weights: Array1<f32>, output_shape: [usize; 2]) -> Self {
        Self {
            weights,
            output_shape,
        }
    }
}

impl Forward for DefConv2 {
    type Input = (Array2<f32>, Array2<f32>);
    type Internal = ();
    type Output = Array2<f32>;

    fn forward(&self, (features, offsets): &Self::Input) -> ((), Self::Output) {
        let input = DefConvData { features, offsets };
        assert_eq!(self.weights.len(), input.offsets.shape()[0]);
        // Get shapes.
        let outshape = self.output_shape;
        let inshape = input.features.raw_dim();

        // Compute the coordinate multiplier.
        let multipliers = [
            inshape[0] as f32 / outshape[0] as f32,
            inshape[1] as f32 / outshape[1] as f32,
        ];

        // Compute bilinear interpolation for (y, x) pairs.
        (
            (),
            Array::from_shape_vec(
                outshape,
                (0..outshape[0])
                    .cartesian_product(0..outshape[1])
                    .map(|(y, x)| {
                        self.weights
                            .iter()
                            .zip(input.offsets.outer_iter())
                            .map(|(weight, offset)| {
                                input.bilinear([
                                    (y as f32 + 0.5 + offset[0]) * multipliers[0],
                                    (x as f32 + 0.5 + offset[1]) * multipliers[1],
                                ]) * weight
                            })
                            .sum()
                    })
                    .collect(),
            )
            .expect("mli-defconv: unexpected shape vec"),
        )
    }
}

impl Backward for DefConv2 {
    type OutputDelta = Array2<f32>;
    type InputDelta = (Array2<f32>, Array2<f32>);
    type TrainDelta = Ndeep<OwnedRepr<f32>, D1>;

    fn backward(
        &self,
        (features, offsets): &Self::Input,
        _: &Self::Internal,
        output_delta: &Self::OutputDelta,
    ) -> (Self::InputDelta, Self::TrainDelta) {
        let input = DefConvData { features, offsets };
        // Get shapes.
        let outshape = self.output_shape;
        let inshape = input.features.raw_dim();

        // Compute the coordinate multiplier.
        let multipliers = [
            inshape[0] as f32 / outshape[0] as f32,
            inshape[1] as f32 / outshape[1] as f32,
        ];

        // We cannot determine in advance what locations are affected
        let mut feature_deltas: Array2<f32> = Array2::zeros(inshape);
        let mut offset_deltas: Array2<f32> = Array2::zeros(input.offsets.raw_dim());
        let mut weight_deltas: Array1<f32> = Array1::zeros(self.weights.raw_dim());

        for (y, x) in (0..outshape[0]).cartesian_product(0..outshape[1]) {
            let output_delta = output_delta[[y, x]];
            for (ix, (weight, offset)) in self
                .weights
                .iter()
                .zip(input.offsets.outer_iter())
                .enumerate()
            {
                // Compute the original sample coordinate.
                let sample_coordinate = [
                    (y as f32 + 0.5 + offset[0]) * multipliers[0],
                    (x as f32 + 0.5 + offset[1]) * multipliers[1],
                ];

                // Find the corners if they are within the input.
                let (validated_corners, rc) = input.validate_corners(sample_coordinate);

                // Loop over all the corners and the amount each contributed.
                for (coord, coeff) in validated_corners.iter().zip(
                    [
                        (1.0 - rc[0]) * (1.0 - rc[1]),
                        (1.0 - rc[0]) * rc[1],
                        rc[0] * (1.0 - rc[1]),
                        rc[0] * rc[1],
                    ]
                    .iter(),
                ) {
                    // If the coordinate was in bounds of the input tensor.
                    if let Some(coord) = coord {
                        // Add the contribution.
                        feature_deltas[*coord] += coeff * weight * output_delta;
                    }
                }

                // Compute the position gradients.
                let f = input.extract_corners(validated_corners);
                let position_gradient = bilinear_position_gradient(f, rc);
                // Compute and add the offset gradients based on the position gradients and chain rule.
                // The multipliers affect the gradient of the position because they multiply the sampling locations.
                // The greater the weight the greater the effect on sampling location because the output is multiplied by the weight.
                offset_deltas[[ix, 0]] +=
                    multipliers[0] * position_gradient[0] * weight * output_delta;
                offset_deltas[[ix, 1]] +=
                    multipliers[1] * position_gradient[1] * weight * output_delta;

                // TODO: This is incredibly inefficient recomputing the entire bilinear interpolation. Use internals to store it.
                weight_deltas[ix] += input.bilinear(sample_coordinate) * output_delta;
            }
        }

        // Compute bilinear interpolation for (y, x) pairs.
        ((feature_deltas, offset_deltas), Ndeep(weight_deltas))
    }
}
<commit_msg>make a DefConv2 with internal trainable offsets<commit_after>use arraymap::ArrayMap;
use itertools::Itertools;
use mli::*;
use mli_ndarray::{Ndeep, Variable};
use ndarray::{Array, Array1, Array2, OwnedRepr};

type D1 = ndarray::Ix1;
type D2 = ndarray::Ix2;

fn corners(coordinate: [f32; 2]) -> [[isize; 2]; 4] {
    let c00 = coordinate.map(|f| f.floor() as isize);
    let c11 = coordinate.map(|f| f.ceil() as isize);
    let c01 = [c00[0], c11[1]];
    let c10 = [c11[0], c00[1]];
    [c00, c01, c10, c11]
}

/// Looks up a position gradient from a location in the features using bilinear interpolation and zero-padding.
fn bilinear_position_gradient(f: [f32; 4], rc: [f32; 2]) -> [f32; 2] {
    // Perform the y interpolation to get the x values.
    let fx = [
        (1.0 - rc[0]) * f[0] + rc[0] * f[2],
        (1.0 - rc[0]) * f[1] + rc[0] * f[3],
    ];

    // Perform the x interpolation to get the y values.
    let fy = [
        (1.0 - rc[1]) * f[0] + rc[1] * f[1],
        (1.0 - rc[1]) * f[2] + rc[1] * f[3],
    ];

    // The gradient is the difference between the interpolation values in each dimension.
    [fy[1] - fy[0], fx[1] - fx[0]]
}

struct DefConvData<'a> {
    features: &'a Array2<f32>,
    offsets: &'a Array2<f32>,
}

impl<'a> DefConvData<'a> {
    fn validate_corners(&self, coordinate: [f32; 2]) -> ([Option<[usize; 2]>; 4], [f32; 2]) {
        // Get the integer versions of four corners.
        let coords = corners(coordinate);

        // Get the relative coordinate.
        let rc = [
            coordinate[0] - coords[0][0] as f32,
            coordinate[1] - coords[0][1] as f32,
        ];

        // Create a closure to detect out-of-bounds.
        let in_bounds = |[y, x]: [isize; 2]| {
            if y < 0
                || x < 0
                || y >= self.features.shape()[0] as isize
                || x >= self.features.shape()[1] as isize
            {
                None
            } else {
                Some([y, x].map(|&n| n as usize))
            }
        };

        // Create a closure to extract the feature with zero-padding.
        let extract = |c| in_bounds(c);

        (coords.map(|&c| extract(c)), rc)
    }

    /// Extracts the corner features and relative coordinate for a bilinear interpolation.
    fn extract_corners(&self, validated_corners: [Option<[usize; 2]>; 4]) -> [f32; 4] {
        validated_corners.map(|c| c.as_ref().map(|&c| self.features[c]).unwrap_or(0.0))
    }

    /// Looks up a location in the features using bilinear interpolation and zero-padding.
    fn bilinear(&self, coordinate: [f32; 2]) -> f32 {
        // Extract the corner features and the relative coordinate.
        let (validated_corners, rc) = self.validate_corners(coordinate);
        let f = self.extract_corners(validated_corners);

        // Perform the y interpolation.
        let fx = [
            (1.0 - rc[0]) * f[0] + rc[0] * f[2],
            (1.0 - rc[0]) * f[1] + rc[0] * f[3],
        ];

        // Perform the x interpolation.
        (1.0 - rc[1]) * fx[0] + rc[1] * fx[1]
    }
}

#[derive(Clone, Debug)]
pub struct DefConv2 {
    weights: Array1<f32>,
    output_shape: [usize; 2],
}

impl DefConv2 {
    pub fn new(weights: Array1<f32>, output_shape: [usize; 2]) -> Self {
        Self {
            weights,
            output_shape,
        }
    }
}

impl Forward for DefConv2 {
    type Input = (Array2<f32>, Array2<f32>);
    type Internal = ();
    type Output = Array2<f32>;

    fn forward(&self, (features, offsets): &Self::Input) -> ((), Self::Output) {
        let input = DefConvData { features, offsets };
        assert_eq!(self.weights.len(), input.offsets.shape()[0]);
        // Get shapes.
        let outshape = self.output_shape;
        let inshape = input.features.raw_dim();

        // Compute the coordinate multiplier.
        let multipliers = [
            inshape[0] as f32 / outshape[0] as f32,
            inshape[1] as f32 / outshape[1] as f32,
        ];

        // Compute bilinear interpolation for (y, x) pairs.
        (
            (),
            Array::from_shape_vec(
                outshape,
                (0..outshape[0])
                    .cartesian_product(0..outshape[1])
                    .map(|(y, x)| {
                        self.weights
                            .iter()
                            .zip(input.offsets.outer_iter())
                            .map(|(weight, offset)| {
                                input.bilinear([
                                    (y as f32 + 0.5 + offset[0]) * multipliers[0],
                                    (x as f32 + 0.5 + offset[1]) * multipliers[1],
                                ]) * weight
                            })
                            .sum()
                    })
                    .collect(),
            )
            .expect("mli-defconv: unexpected shape vec"),
        )
    }
}

impl Backward for DefConv2 {
    type OutputDelta = Array2<f32>;
    type InputDelta = (Array2<f32>, Array2<f32>);
    type TrainDelta = Ndeep<OwnedRepr<f32>, D1>;

    fn backward(
        &self,
        (features, offsets): &Self::Input,
        _: &Self::Internal,
        output_delta: &Self::OutputDelta,
    ) -> (Self::InputDelta, Self::TrainDelta) {
        let input = DefConvData { features, offsets };
        // Get shapes.
        let outshape = self.output_shape;
        let inshape = input.features.raw_dim();

        // Compute the coordinate multiplier.
        let multipliers = [
            inshape[0] as f32 / outshape[0] as f32,
            inshape[1] as f32 / outshape[1] as f32,
        ];

        // We cannot determine in advance what locations are affected
        let mut feature_deltas: Array2<f32> = Array2::zeros(inshape);
        let mut offset_deltas: Array2<f32> = Array2::zeros(input.offsets.raw_dim());
        let mut weight_deltas: Array1<f32> = Array1::zeros(self.weights.raw_dim());

        for (y, x) in (0..outshape[0]).cartesian_product(0..outshape[1]) {
            let output_delta = output_delta[[y, x]];
            for (ix, (weight, offset)) in self
                .weights
                .iter()
                .zip(input.offsets.outer_iter())
                .enumerate()
            {
                // Compute the original sample coordinate.
                let sample_coordinate = [
                    (y as f32 + 0.5 + offset[0]) * multipliers[0],
                    (x as f32 + 0.5 + offset[1]) * multipliers[1],
                ];

                // Find the corners if they are within the input.
                let (validated_corners, rc) = input.validate_corners(sample_coordinate);

                // Loop over all the corners and the amount each contributed.
                for (coord, coeff) in validated_corners.iter().zip(
                    [
                        (1.0 - rc[0]) * (1.0 - rc[1]),
                        (1.0 - rc[0]) * rc[1],
                        rc[0] * (1.0 - rc[1]),
                        rc[0] * rc[1],
                    ]
                    .iter(),
                ) {
                    // If the coordinate was in bounds of the input tensor.
                    if let Some(coord) = coord {
                        // Add the contribution.
                        feature_deltas[*coord] += coeff * weight * output_delta;
                    }
                }

                // Compute the position gradients.
                let f = input.extract_corners(validated_corners);
                let position_gradient = bilinear_position_gradient(f, rc);
                // Compute and add the offset gradients based on the position gradients and chain rule.
                // The multipliers affect the gradient of the position because they multiply the sampling locations.
                // The greater the weight the greater the effect on sampling location because the output is multiplied by the weight.
                offset_deltas[[ix, 0]] +=
                    multipliers[0] * position_gradient[0] * weight * output_delta;
                offset_deltas[[ix, 1]] +=
                    multipliers[1] * position_gradient[1] * weight * output_delta;

                // TODO: This is incredibly inefficient recomputing the entire bilinear interpolation. Use internals to store it.
                weight_deltas[ix] += input.bilinear(sample_coordinate) * output_delta;
            }
        }

        // Compute bilinear interpolation for (y, x) pairs.
        ((feature_deltas, offset_deltas), Ndeep(weight_deltas))
    }
}

pub struct DefConv2InternalOffsets {
    def_conv: DefConv2,
    offsets: Variable<f32, D2>,
}

impl DefConv2InternalOffsets {
    pub fn new(weights: Array1<f32>, offsets: Array2<f32>, output_shape: [usize; 2]) -> Self {
        Self {
            def_conv: DefConv2::new(weights, output_shape),
            offsets: Variable(offsets),
        }
    }
}

impl Forward for DefConv2InternalOffsets {
    type Input = Array2<f32>;
    type Internal = ();
    type Output = Array2<f32>;

    fn forward(&self, input: &Self::Input) -> ((), Self::Output) {
        self.def_conv
            .forward(&(input.clone(), self.offsets.0.clone()))
    }
}

impl Backward for DefConv2InternalOffsets {
    type OutputDelta = Array2<f32>;
    type InputDelta = Array2<f32>;
    type TrainDelta = ChainData<Ndeep<OwnedRepr<f32>, D1>, Ndeep<OwnedRepr<f32>, D2>>;

    fn backward(
        &self,
        input: &Self::Input,
        _: &Self::Internal,
        output_delta: &Self::OutputDelta,
    ) -> (Self::InputDelta, Self::TrainDelta) {
        let ((input_delta, offset_delta), weight_delta) =
            self.def_conv
                .backward(&(input.clone(), self.offsets.0.clone()), &(), output_delta);
        (input_delta, ChainData(weight_delta, Ndeep(offset_delta)))
    }
}
<|endoftext|>


<commit_before>use crate::controllers::frontend_prelude::*;

use crate::models::Team;
use crate::schema::teams;
use crate::views::EncodableTeam;

/// Handles the `GET /teams/:team_id` route.
pub fn show_team(req: &mut dyn RequestExt) -> EndpointResult {
    use self::teams::dsl::{login, teams};

    let name = &req.params()["team_id"];
    let conn = req.db_read_only()?;
    let team: Team = teams.filter(login.eq(name)).first(&*conn)?;

    #[derive(Serialize)]
    struct R {
        team: EncodableTeam,
    }
    Ok(req.json(&R { team: team.into() }))
}
<commit_msg>controllers::team: Use `json!` macro to simplify JSON serialization code<commit_after>use crate::controllers::frontend_prelude::*;

use crate::models::Team;
use crate::schema::teams;
use crate::views::EncodableTeam;

/// Handles the `GET /teams/:team_id` route.
pub fn show_team(req: &mut dyn RequestExt) -> EndpointResult {
    use self::teams::dsl::{login, teams};

    let name = &req.params()["team_id"];
    let conn = req.db_read_only()?;
    let team: Team = teams.filter(login.eq(name)).first(&*conn)?;

    Ok(req.json(&json!({ "team": EncodableTeam::from(team) })))
}
<|endoftext|>


<commit_before>use std::time::Duration;
use ggez::{Context, GameResult, graphics};
use ggez::event::{Mod, Keycode};
use event::{Assets, Transition, EventHandler, Button};
use states::menu_state::MenuState;
use util::DurationExt;

const FADE_TIME: f32 = 3.0;
const WAIT_TIME: f32 = 1.5;

pub struct IntroState {
    intro_text: graphics::Text,
    hit_any_key: bool,
    fader: f32,
    waiter: f32,
    fade_in: f32,
    fade_out: f32,
}

impl IntroState {
    /// A `GameEndState` takes values from `PlayState` to render certain values
    /// such as no. of lines cleared, highest level cleared, final score, etc.
    pub fn new(ctx: &mut Context, assets: &Assets) -> GameResult<Self> {
        let intro_text = graphics::Text::new(
            ctx,
            "a (bad) game (clone) by obsoke",
            assets.get_font("normal")?,
        )?;

        Ok(IntroState {
            intro_text: intro_text,
            hit_any_key: false,
            fader: 0.0,
            waiter: WAIT_TIME,
            fade_in: 0.0,
            fade_out: FADE_TIME,
        })
    }

    pub fn handle_input(&mut self) {
        self.hit_any_key = true;
    }
}

impl EventHandler for IntroState {
    fn update(
        &mut self,
        ctx: &mut Context,
        assets: &Assets,
        dt: Duration,
    ) -> GameResult<Transition> {

        if self.hit_any_key {
            return Ok(Transition::Swap(Box::new(MenuState::new(ctx, assets)?)));
        }

        if self.fade_in < FADE_TIME {
            self.fade_in += dt.as_subsec_millis() as f32;
            self.fader = self.fade_in;
        } else if self.waiter > 0.0 {
            self.waiter -= dt.as_subsec_millis() as f32;
        } else if self.fade_out > 0.0 {
            self.fade_out -= dt.as_subsec_millis() as f32;
            self.fader = self.fade_out;
        } else {
            return Ok(Transition::Swap(Box::new(MenuState::new(ctx, assets)?)));
        }

        Ok(Transition::None)
    }

    fn draw(&mut self, ctx: &mut Context, _: &Assets) -> GameResult<()> {
        let coords = graphics::get_screen_coordinates(ctx);

        let intro_text_dest = graphics::Point::new(coords.w / 2.0, 300.0);

        println!(
            "fader: {}, normalized fader: {}",
            self.fader,
            self.fader / FADE_TIME
        );

        graphics::set_color(
            ctx,
            graphics::Color::new(1.0, 1.0, 1.0, self.fader / FADE_TIME),
        )?;

        graphics::draw(ctx, &self.intro_text, intro_text_dest, 0.0)?;

        Ok(())
    }

    fn key_down_event(&mut self, keycode: Keycode, _keymod: Mod, repeat: bool, _assets: &Assets) {
        if repeat {
            return;
        }

        match keycode {
            _ => self.handle_input(),
        }
    }

    fn controller_button_down_event(&mut self, btn: Button, _instance_id: i32, _assets: &Assets) {
        match btn {
            _ => self.handle_input(),
        }
    }
}
<commit_msg>remove println (synchronous)<commit_after>use std::time::Duration;
use ggez::{Context, GameResult, graphics};
use ggez::event::{Mod, Keycode};
use event::{Assets, Transition, EventHandler, Button};
use states::menu_state::MenuState;
use util::DurationExt;

const FADE_TIME: f32 = 3.0;
const WAIT_TIME: f32 = 1.5;

pub struct IntroState {
    intro_text: graphics::Text,
    hit_any_key: bool,
    fader: f32,
    waiter: f32,
    fade_in: f32,
    fade_out: f32,
}

impl IntroState {
    /// A `GameEndState` takes values from `PlayState` to render certain values
    /// such as no. of lines cleared, highest level cleared, final score, etc.
    pub fn new(ctx: &mut Context, assets: &Assets) -> GameResult<Self> {
        let intro_text = graphics::Text::new(
            ctx,
            "a (bad) game (clone) by obsoke",
            assets.get_font("normal")?,
        )?;

        Ok(IntroState {
            intro_text: intro_text,
            hit_any_key: false,
            fader: 0.0,
            waiter: WAIT_TIME,
            fade_in: 0.0,
            fade_out: FADE_TIME,
        })
    }

    pub fn handle_input(&mut self) {
        self.hit_any_key = true;
    }
}

impl EventHandler for IntroState {
    fn update(
        &mut self,
        ctx: &mut Context,
        assets: &Assets,
        dt: Duration,
    ) -> GameResult<Transition> {

        if self.hit_any_key {
            return Ok(Transition::Swap(Box::new(MenuState::new(ctx, assets)?)));
        }

        if self.fade_in < FADE_TIME {
            self.fade_in += dt.as_subsec_millis() as f32;
            self.fader = self.fade_in;
        } else if self.waiter > 0.0 {
            self.waiter -= dt.as_subsec_millis() as f32;
        } else if self.fade_out > 0.0 {
            self.fade_out -= dt.as_subsec_millis() as f32;
            self.fader = self.fade_out;
        } else {
            return Ok(Transition::Swap(Box::new(MenuState::new(ctx, assets)?)));
        }

        Ok(Transition::None)
    }

    fn draw(&mut self, ctx: &mut Context, _: &Assets) -> GameResult<()> {
        let coords = graphics::get_screen_coordinates(ctx);

        let intro_text_dest = graphics::Point::new(coords.w / 2.0, 300.0);

        graphics::set_color(
            ctx,
            graphics::Color::new(1.0, 1.0, 1.0, self.fader / FADE_TIME),
        )?;

        graphics::draw(ctx, &self.intro_text, intro_text_dest, 0.0)?;

        Ok(())
    }

    fn key_down_event(&mut self, keycode: Keycode, _keymod: Mod, repeat: bool, _assets: &Assets) {
        if repeat {
            return;
        }

        match keycode {
            _ => self.handle_input(),
        }
    }

    fn controller_button_down_event(&mut self, btn: Button, _instance_id: i32, _assets: &Assets) {
        match btn {
            _ => self.handle_input(),
        }
    }
}
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => (set_z!($cpu_state,$val);set_s!($cpu_state,$val););
}
macro_rules! set_z {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;);
}
macro_rules! set_s {
    ($cpu_state:expr,$val:expr) => ($cpu_state.S = $val >= 0x80;);
}
macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 | $cpu_state.sp,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=1;
            $mem.read8(0x0100 | $cpu_state.sp;)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BCC => {
                if !cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BCS => {
                if cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BEQ => {
                if cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BIT => {
                cpu_state.V = (cpu_state.decode_register.value_final.unwrap() >> 6) & 1 > 0;
                set_z!(cpu_state,cpu_state.decode_register.value_final.unwrap() & cpu_state.a);
                set_s!(cpu_state,cpu_state.decode_register.value_final.unwrap());

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BNE => {
                if !cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc-1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::STA => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.a));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.x));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<commit_msg>implemented BVS opcode<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => (set_z!($cpu_state,$val);set_s!($cpu_state,$val););
}
macro_rules! set_z {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;);
}
macro_rules! set_s {
    ($cpu_state:expr,$val:expr) => ($cpu_state.S = $val >= 0x80;);
}
macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 | $cpu_state.sp,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=1;
            $mem.read8(0x0100 | $cpu_state.sp;)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.pc+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BCC => {
                if !cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BCS => {
                if cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BEQ => {
                if cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BIT => {
                cpu_state.V = (cpu_state.decode_register.value_final.unwrap() >> 6) & 1 > 0;
                set_z!(cpu_state,cpu_state.decode_register.value_final.unwrap() & cpu_state.a);
                set_s!(cpu_state,cpu_state.decode_register.value_final.unwrap());

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BNE => {
                if !cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BVS => {
                if cpu_state.V { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc-1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::STA => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.a));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.x));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<|endoftext|>


<commit_before>// ignore-windows: Concurrency on Windows is not supported yet.

// Check that we terminate the program when the main thread terminates.

//~^^^^ ERROR: unsupported operation: the main thread terminated without waiting for other threads

#![feature(rustc_private)]

extern crate libc;

use std::{mem, ptr};

extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
    ptr::null_mut()
}

fn main() {
    unsafe {
        let mut native: libc::pthread_t = mem::zeroed();
        let attr: libc::pthread_attr_t = mem::zeroed();
        // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented.
        assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0);
    }
}
<commit_msg>Fix the test annotation.<commit_after>// ignore-windows: Concurrency on Windows is not supported yet.
// error-pattern: unsupported operation: the main thread terminated without waiting for other threads

// Check that we terminate the program when the main thread terminates.

#![feature(rustc_private)]

extern crate libc;

use std::{mem, ptr};

extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
    ptr::null_mut()
}

fn main() {
    unsafe {
        let mut native: libc::pthread_t = mem::zeroed();
        let attr: libc::pthread_attr_t = mem::zeroed();
        // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented.
        assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0);
    }
}
<|endoftext|>