<commit_before>use super::super::entities::*;
use super::geo::*;

const BBOX_LAT_DEG_EXT: f64 = 0.02;
const BBOX_LNG_DEG_EXT: f64 = 0.04;

pub fn extend_bbox(bbox: &MapBbox) -> MapBbox {
    let south_west_lat_deg = LatCoord::min()
        .to_deg()
        .max(bbox.south_west().lat().to_deg() - BBOX_LAT_DEG_EXT);
    let north_east_lat_deg = LatCoord::max()
        .to_deg()
        .min(bbox.north_east().lat().to_deg() + BBOX_LAT_DEG_EXT);
    let mut south_west_lng_deg = bbox.south_west().lng().to_deg() - BBOX_LNG_DEG_EXT;
    if south_west_lng_deg < LngCoord::min().to_deg() {
        // wrap around
        south_west_lng_deg += LngCoord::max().to_deg() - LngCoord::min().to_deg();
    }
    let mut north_east_lng_deg = bbox.north_east().lng().to_deg() + BBOX_LNG_DEG_EXT;
    if north_east_lng_deg > LngCoord::max().to_deg() {
        // wrap around
        north_east_lng_deg -= LngCoord::max().to_deg() - LngCoord::min().to_deg();
    }
    if bbox.south_west().lng() <= bbox.north_east().lng() {
        if south_west_lng_deg > north_east_lng_deg {
            // overflow after wrap around (boundaries switched) -> maximize
            south_west_lng_deg = LngCoord::min().to_deg();
            north_east_lng_deg = LngCoord::max().to_deg();
        }
    } else {
        if south_west_lng_deg < north_east_lng_deg {
            // overflow after wrap around (boundaries switched) -> maximize
            south_west_lng_deg = LngCoord::min().to_deg();
            north_east_lng_deg = LngCoord::max().to_deg();
        }
    }
    let extended_bbox = MapBbox::new(
        MapPoint::from_lat_lng_deg(south_west_lat_deg, south_west_lng_deg),
        MapPoint::from_lat_lng_deg(north_east_lat_deg, north_east_lng_deg),
    );
    debug_assert!(extended_bbox.is_valid());
    extended_bbox
}

pub trait InBBox {
    fn in_bbox(&self, bbox: &MapBbox) -> bool;
}

impl InBBox for Entry {
    fn in_bbox(&self, bbox: &MapBbox) -> bool {
        bbox.contains_point(&MapPoint::from_lat_lng_deg(
            self.location.lat,
            self.location.lng,
        ))
    }
}

impl InBBox for Event {
    fn in_bbox(&self, bbox: &MapBbox) -> bool {
        if let Some(ref location) = self.location {
            bbox.contains_point(&MapPoint::from_lat_lng_deg(location.lat, location.lng))
        } else {
            false
        }
    }
}

pub fn entries_by_category_ids<'a>(ids: &'a [String]) -> impl Fn(&Entry) -> bool + 'a {
    move |e| ids.iter().any(|c| e.categories.iter().any(|x| x == c))
}

pub fn entries_by_tags_or_search_text<'a>(
    text: &'a str,
    tags: &'a [String],
) -> Box<Fn(&Entry) -> bool + 'a> {
    if !tags.is_empty() {
        Box::new(entries_by_tags_and_search_text(text, tags))
    } else {
        Box::new(entries_by_search_text(text))
    }
}

fn entries_by_search_text<'a>(text: &'a str) -> impl Fn(&Entry) -> bool + 'a {
    let words = to_words(text);
    move |entry| {
        ((!text.is_empty()
            && words.iter().any(|word| {
                entry.title.to_lowercase().contains(word)
                    || entry.description.to_lowercase().contains(word)
                    || entry.tags.iter().any(|tag| tag == word)
            }))
            || text.is_empty())
    }
}

fn entries_by_tags_and_search_text<'a>(
    text: &'a str,
    tags: &'a [String],
) -> impl Fn(&Entry) -> bool + 'a {
    let words = to_words(text);
    move |entry| {
        tags.iter()
            .map(|t| t.to_lowercase())
            .all(|tag| entry.tags.iter().any(|t| *t == tag))
            || ((!text.is_empty()
                && words.iter().any(|word| {
                    entry.title.to_lowercase().contains(word)
                        || entry.description.to_lowercase().contains(word)
                        || entry.tags.iter().any(|tag| tag == word)
                }))
                || (text.is_empty() && tags[0] == ""))
    }
}

fn to_words(txt: &str) -> Vec<String> {
    txt.to_lowercase()
        .split(',')
        .map(|x| x.to_string())
        .collect()
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn is_in_bounding_box() {
        let bb = MapBbox::new(
            MapPoint::from_lat_lng_deg(-10.0, -10.0),
            MapPoint::from_lat_lng_deg(10.0, 10.0),
        );
        let e = Entry::build()
            .title("foo")
            .description("bar")
            .lat(5.0)
            .lng(5.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), true);
        let e = Entry::build()
            .title("foo")
            .description("bar")
            .lat(10.1)
            .lng(10.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), false);
    }

    #[test]
    fn filter_by_bounding_box() {
        let bb = MapBbox::new(
            MapPoint::from_lat_lng_deg(-10.0, -10.0),
            MapPoint::from_lat_lng_deg(10.0, 10.0),
        );
        let entries = vec![
            Entry::build().lat(5.0).lng(5.0).finish(),
            Entry::build().lat(-5.0).lng(5.0).finish(),
            Entry::build().lat(10.0).lng(10.1).finish(),
        ];
        assert_eq!(
            entries
                .iter()
                .filter(|&x| x.in_bbox(&bb))
                .collect::<Vec<&Entry>>()
                .len(),
            2
        );
    }

    #[test]
    fn filter_by_category() {
        let entries = vec![
            Entry::build().categories(vec!["a"]).finish(),
            Entry::build().categories(vec!["c"]).finish(),
            Entry::build().categories(vec!["b", "a"]).finish(),
        ];
        let ab = vec!["a".into(), "b".into()];
        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(entries_by_category_ids(&ab))
            .collect();
        assert_eq!(x.len(), 2);
        let b = vec!["b".into()];
        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(entries_by_category_ids(&b))
            .collect();
        assert_eq!(x.len(), 1);
        let c = vec!["c".into()];
        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(entries_by_category_ids(&c))
            .collect();
        assert_eq!(x.len(), 1);
    }

    #[test]
    fn filter_by_tags_or_text() {
        let entries = vec![
            Entry::build()
                .id("a")
                .title("aaa")
                .description("bli bla blubb")
                .finish(),
            Entry::build()
                .id("b")
                .title("bbb")
                .description("blabla")
                .tags(vec!["tag1"])
                .finish(),
            Entry::build()
                .id("c")
                .title("ccc")
                .description("bli")
                .tags(vec!["tag2"])
                .finish(),
            Entry::build()
                .id("d")
                .title("ddd")
                .description("blibla")
                .tags(vec!["tag1", "tag2"])
                .finish(),
            Entry::build()
                .id("e")
                .title("eee")
                .description("blubb")
                .description("tag1")
                .finish(),
        ];
        let entries_without_tags = vec![
            Entry::build().id("a").title("a").finish(),
            Entry::build()
                .id("b")
                .title("b")
                .description("blabla")
                .finish(),
            Entry::build().id("c").finish(),
            Entry::build().id("d").finish(),
            Entry::build().id("e").description("tag1").finish(),
        ];
        let tags1 = vec!["tag1".into()];
        let tags2 = vec!["tag1".into(), "tag2".into()];
        let tags3 = vec!["tag2".into()];
        let no_tags = vec![];
        let aaa = "aaa";
        let blabla = "blabla";
        let other = "other";
        let tag1 = "tag1";
        let no_string = "";

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&no_string, &no_tags))
            .collect();
        assert_eq!(x.len(), 5);

        let x: Vec<_> = entries_without_tags
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags1))
            .collect();
        assert_eq!(x.len(), 0);

        let x: Vec<_> = entries_without_tags
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags2))
            .collect();
        assert_eq!(x.len(), 0);

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags2))
            .collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags3))
            .collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "c");
        assert_eq!(x[1].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&no_string, &tags1))
            .collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&aaa, &no_tags))
            .collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id, "a");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&aaa, &tags2))
            .collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "a");
        assert_eq!(x[1].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&blabla, &tags3))
            .collect();
        assert_eq!(x.len(), 3);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "c");
        assert_eq!(x[2].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&tag1, &no_tags))
            .collect();
        assert_eq!(x.len(), 3);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "d");
        assert_eq!(x[2].id, "e");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags1))
            .collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "d");
    }

    #[test]
    fn extend_max_bbox() {
        let bbox = MapBbox::new(
            MapPoint::from_lat_lng_deg(-89.99, -179.97),
            MapPoint::from_lat_lng_deg(89.99, 179.97),
        );
        let ext_bbox = extend_bbox(&bbox);
        assert!(ext_bbox.is_valid());
        assert_eq!(ext_bbox.south_west().lat(), LatCoord::min());
        assert_eq!(ext_bbox.north_east().lat(), LatCoord::max());
        assert_eq!(ext_bbox.south_west().lng(), LngCoord::min());
        assert_eq!(ext_bbox.north_east().lng(), LngCoord::max());
    }
}
<commit_msg>Hide unused functions<commit_after>use super::super::entities::*;
use super::geo::*;

const BBOX_LAT_DEG_EXT: f64 = 0.02;
const BBOX_LNG_DEG_EXT: f64 = 0.04;

pub fn extend_bbox(bbox: &MapBbox) -> MapBbox {
    let south_west_lat_deg = LatCoord::min()
        .to_deg()
        .max(bbox.south_west().lat().to_deg() - BBOX_LAT_DEG_EXT);
    let north_east_lat_deg = LatCoord::max()
        .to_deg()
        .min(bbox.north_east().lat().to_deg() + BBOX_LAT_DEG_EXT);
    let mut south_west_lng_deg = bbox.south_west().lng().to_deg() - BBOX_LNG_DEG_EXT;
    if south_west_lng_deg < LngCoord::min().to_deg() {
        // wrap around
        south_west_lng_deg += LngCoord::max().to_deg() - LngCoord::min().to_deg();
    }
    let mut north_east_lng_deg = bbox.north_east().lng().to_deg() + BBOX_LNG_DEG_EXT;
    if north_east_lng_deg > LngCoord::max().to_deg() {
        // wrap around
        north_east_lng_deg -= LngCoord::max().to_deg() - LngCoord::min().to_deg();
    }
    if bbox.south_west().lng() <= bbox.north_east().lng() {
        if south_west_lng_deg > north_east_lng_deg {
            // overflow after wrap around (boundaries switched) -> maximize
            south_west_lng_deg = LngCoord::min().to_deg();
            north_east_lng_deg = LngCoord::max().to_deg();
        }
    } else {
        if south_west_lng_deg < north_east_lng_deg {
            // overflow after wrap around (boundaries switched) -> maximize
            south_west_lng_deg = LngCoord::min().to_deg();
            north_east_lng_deg = LngCoord::max().to_deg();
        }
    }
    let extended_bbox = MapBbox::new(
        MapPoint::from_lat_lng_deg(south_west_lat_deg, south_west_lng_deg),
        MapPoint::from_lat_lng_deg(north_east_lat_deg, north_east_lng_deg),
    );
    debug_assert!(extended_bbox.is_valid());
    extended_bbox
}

pub trait InBBox {
    fn in_bbox(&self, bbox: &MapBbox) -> bool;
}

impl InBBox for Entry {
    fn in_bbox(&self, bbox: &MapBbox) -> bool {
        bbox.contains_point(&MapPoint::from_lat_lng_deg(
            self.location.lat,
            self.location.lng,
        ))
    }
}

impl InBBox for Event {
    fn in_bbox(&self, bbox: &MapBbox) -> bool {
        if let Some(ref location) = self.location {
            bbox.contains_point(&MapPoint::from_lat_lng_deg(location.lat, location.lng))
        } else {
            false
        }
    }
}

#[cfg(feature = "test")]
pub fn entries_by_category_ids<'a>(ids: &'a [String]) -> impl Fn(&Entry) -> bool + 'a {
    move |e| ids.iter().any(|c| e.categories.iter().any(|x| x == c))
}

#[cfg(feature = "test")]
fn entries_by_tags_and_search_text<'a>(
    text: &'a str,
    tags: &'a [String],
) -> impl Fn(&Entry) -> bool + 'a {
    let words = to_words(text);
    move |entry| {
        tags.iter()
            .map(|t| t.to_lowercase())
            .all(|tag| entry.tags.iter().any(|t| *t == tag))
            || ((!text.is_empty()
                && words.iter().any(|word| {
                    entry.title.to_lowercase().contains(word)
                        || entry.description.to_lowercase().contains(word)
                        || entry.tags.iter().any(|tag| tag == word)
                }))
                || (text.is_empty() && tags[0] == ""))
    }
}

#[cfg(feature = "test")]
pub fn entries_by_tags_or_search_text<'a>(
    text: &'a str,
    tags: &'a [String],
) -> Box<Fn(&Entry) -> bool + 'a> {
    if !tags.is_empty() {
        Box::new(entries_by_tags_and_search_text(text, tags))
    } else {
        Box::new(entries_by_search_text(text))
    }
}

#[cfg(feature = "test")]
fn entries_by_search_text<'a>(text: &'a str) -> impl Fn(&Entry) -> bool + 'a {
    let words = to_words(text);
    move |entry| {
        ((!text.is_empty()
            && words.iter().any(|word| {
                entry.title.to_lowercase().contains(word)
                    || entry.description.to_lowercase().contains(word)
                    || entry.tags.iter().any(|tag| tag == word)
            }))
            || text.is_empty())
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    fn to_words(txt: &str) -> Vec<String> {
        txt.to_lowercase()
            .split(',')
            .map(|x| x.to_string())
            .collect()
    }

    #[test]
    fn is_in_bounding_box() {
        let bb = MapBbox::new(
            MapPoint::from_lat_lng_deg(-10.0, -10.0),
            MapPoint::from_lat_lng_deg(10.0, 10.0),
        );
        let e = Entry::build()
            .title("foo")
            .description("bar")
            .lat(5.0)
            .lng(5.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), true);
        let e = Entry::build()
            .title("foo")
            .description("bar")
            .lat(10.1)
            .lng(10.0)
            .finish();
        assert_eq!(e.in_bbox(&bb), false);
    }

    #[test]
    fn filter_by_bounding_box() {
        let bb = MapBbox::new(
            MapPoint::from_lat_lng_deg(-10.0, -10.0),
            MapPoint::from_lat_lng_deg(10.0, 10.0),
        );
        let entries = vec![
            Entry::build().lat(5.0).lng(5.0).finish(),
            Entry::build().lat(-5.0).lng(5.0).finish(),
            Entry::build().lat(10.0).lng(10.1).finish(),
        ];
        assert_eq!(
            entries
                .iter()
                .filter(|&x| x.in_bbox(&bb))
                .collect::<Vec<&Entry>>()
                .len(),
            2
        );
    }

    #[test]
    fn filter_by_category() {
        let entries = vec![
            Entry::build().categories(vec!["a"]).finish(),
            Entry::build().categories(vec!["c"]).finish(),
            Entry::build().categories(vec!["b", "a"]).finish(),
        ];
        let ab = vec!["a".into(), "b".into()];
        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(entries_by_category_ids(&ab))
            .collect();
        assert_eq!(x.len(), 2);
        let b = vec!["b".into()];
        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(entries_by_category_ids(&b))
            .collect();
        assert_eq!(x.len(), 1);
        let c = vec!["c".into()];
        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(entries_by_category_ids(&c))
            .collect();
        assert_eq!(x.len(), 1);
    }

    #[test]
    fn filter_by_tags_or_text() {
        let entries = vec![
            Entry::build()
                .id("a")
                .title("aaa")
                .description("bli bla blubb")
                .finish(),
            Entry::build()
                .id("b")
                .title("bbb")
                .description("blabla")
                .tags(vec!["tag1"])
                .finish(),
            Entry::build()
                .id("c")
                .title("ccc")
                .description("bli")
                .tags(vec!["tag2"])
                .finish(),
            Entry::build()
                .id("d")
                .title("ddd")
                .description("blibla")
                .tags(vec!["tag1", "tag2"])
                .finish(),
            Entry::build()
                .id("e")
                .title("eee")
                .description("blubb")
                .description("tag1")
                .finish(),
        ];
        let entries_without_tags = vec![
            Entry::build().id("a").title("a").finish(),
            Entry::build()
                .id("b")
                .title("b")
                .description("blabla")
                .finish(),
            Entry::build().id("c").finish(),
            Entry::build().id("d").finish(),
            Entry::build().id("e").description("tag1").finish(),
        ];
        let tags1 = vec!["tag1".into()];
        let tags2 = vec!["tag1".into(), "tag2".into()];
        let tags3 = vec!["tag2".into()];
        let no_tags = vec![];
        let aaa = "aaa";
        let blabla = "blabla";
        let other = "other";
        let tag1 = "tag1";
        let no_string = "";

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&no_string, &no_tags))
            .collect();
        assert_eq!(x.len(), 5);

        let x: Vec<_> = entries_without_tags
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags1))
            .collect();
        assert_eq!(x.len(), 0);

        let x: Vec<_> = entries_without_tags
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags2))
            .collect();
        assert_eq!(x.len(), 0);

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags2))
            .collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags3))
            .collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "c");
        assert_eq!(x[1].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&no_string, &tags1))
            .collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&aaa, &no_tags))
            .collect();
        assert_eq!(x.len(), 1);
        assert_eq!(x[0].id, "a");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&aaa, &tags2))
            .collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "a");
        assert_eq!(x[1].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&blabla, &tags3))
            .collect();
        assert_eq!(x.len(), 3);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "c");
        assert_eq!(x[2].id, "d");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&tag1, &no_tags))
            .collect();
        assert_eq!(x.len(), 3);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "d");
        assert_eq!(x[2].id, "e");

        let x: Vec<_> = entries
            .iter()
            .cloned()
            .filter(&*entries_by_tags_or_search_text(&other, &tags1))
            .collect();
        assert_eq!(x.len(), 2);
        assert_eq!(x[0].id, "b");
        assert_eq!(x[1].id, "d");
    }

    #[test]
    fn extend_max_bbox() {
        let bbox = MapBbox::new(
            MapPoint::from_lat_lng_deg(-89.99, -179.97),
            MapPoint::from_lat_lng_deg(89.99, 179.97),
        );
        let ext_bbox = extend_bbox(&bbox);
        assert!(ext_bbox.is_valid());
        assert_eq!(ext_bbox.south_west().lat(), LatCoord::min());
        assert_eq!(ext_bbox.north_east().lat(), LatCoord::max());
        assert_eq!(ext_bbox.south_west().lng(), LngCoord::min());
        assert_eq!(ext_bbox.north_east().lng(), LngCoord::max());
    }
}
<|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 as u16 | $cpu_state.sp as u16,$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.sp+=1;
            $mem.read8(0x0100 as u16 | $cpu_state.sp as u16)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.sp+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}
macro_rules! compare {
    ($cpu_state:expr,$a:expr,$b:expr) => {
        {
            set_zs!($cpu_state,$a - $b);
            $cpu_state.C = $a >= $b;
        }
    }
}

#[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::AND => {
				cpu_state.a = 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::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::BPL => {
                if !cpu_state.S { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BVC => {
                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::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::CMP => {
                compare!(cpu_state,cpu_state.a,cpu_state.decode_register.value_final.unwrap());

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::CLD => {
                cpu_state.D = 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 => {
            },
            // http://wiki.nesdev.com/w/index.php/Status_flags
    		OpcodeClass::PHP => {
                stack_push8!(cpu_state,mem,cpu_state.unpack_flags() | 0x30);
            },
    		OpcodeClass::PLA => {
                cpu_state.a = stack_pull8!(cpu_state,mem).unwrap();
                set_zs!(cpu_state,cpu_state.a);
            },
    		OpcodeClass::RTS => {
                cpu_state.pc = stack_pull16!(cpu_state,mem).unwrap() + 1;
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::SED => {
                cpu_state.D = true;
    		},
    		OpcodeClass::SEI => {
                cpu_state.I = 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 PHA 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 as u16 | $cpu_state.sp as u16,$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.sp+=1;
            $mem.read8(0x0100 as u16 | $cpu_state.sp as u16)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.sp+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}
macro_rules! compare {
    ($cpu_state:expr,$a:expr,$b:expr) => {
        {
            set_zs!($cpu_state,$a - $b);
            $cpu_state.C = $a >= $b;
        }
    }
}

#[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::AND => {
				cpu_state.a = 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::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::BPL => {
                if !cpu_state.S { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BVC => {
                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::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::CMP => {
                compare!(cpu_state,cpu_state.a,cpu_state.decode_register.value_final.unwrap());

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::CLD => {
                cpu_state.D = 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::PHA => {
                stack_push8!(cpu_state,mem,cpu_state.a);
            },
            // http://wiki.nesdev.com/w/index.php/Status_flags
    		OpcodeClass::PHP => {
                stack_push8!(cpu_state,mem,cpu_state.unpack_flags() | 0x30);
            },
    		OpcodeClass::PLA => {
                cpu_state.a = stack_pull8!(cpu_state,mem).unwrap();
                set_zs!(cpu_state,cpu_state.a);
            },
    		OpcodeClass::RTS => {
                cpu_state.pc = stack_pull16!(cpu_state,mem).unwrap() + 1;
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::SED => {
                cpu_state.D = true;
    		},
    		OpcodeClass::SEI => {
                cpu_state.I = 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>use std::io::BufRead;
use std::str::from_utf8;

use super::{read_marker, read_numeric_data};
use super::super::init::Marker;
use super::super::value::ValueRef;

// TODO: Display trait.
#[derive(Debug)]
pub struct Error;

pub fn read_value_ref<R>(rd: &mut R) -> Result<ValueRef, Error>
    where R: BufRead
{
    // Reading the marker involves either 1 byte read or nothing.
    let val = match read_marker(rd).unwrap() {
        Marker::Str8 => {
            let len = read_numeric_data::<R, u8>(rd).unwrap() as usize;
            let buf = rd.fill_buf().unwrap();
            let res = from_utf8(&buf[..len]).unwrap();
            ValueRef::String(res)
        }
        _ => unimplemented!(),
    };

    Ok(val)
}
<commit_msg>[ValueRef] Planning.<commit_after>use std::io::BufRead;
use std::str::from_utf8;

use super::{read_marker, read_numeric_data};
use super::super::init::Marker;
use super::super::value::ValueRef;

// TODO: Display trait.
#[derive(Debug)]
pub struct Error;

pub fn read_value_ref<R>(rd: &mut R) -> Result<ValueRef, Error>
    where R: BufRead
{
    let mut buf = rd.fill_buf().unwrap(); // TODO: May fail.

    // Reading the marker involves either 1 byte read or nothing. Consumes 1 byte from `buf`, not
    // from `rd`.
    let val = match read_marker(&mut buf).unwrap() { // TODO: May fail (IO).
        Marker::Str8 => {
            let len = read_numeric_data::<&[u8], u8>(&mut buf).unwrap(); // TODO: May fail (IO).
            let len = len as usize; // TODO: May panic.
            // TODO: Check buffer length.
            let res = from_utf8(&buf[..len]).unwrap(); // TODO: May fail (not UTF-8), return &[u8] otherwise.
            ValueRef::String(res)
        }
        _ => unimplemented!(),
    };

    Ok(val)
}
<|endoftext|>


<commit_before>use std::any::{ Any };

use super::{ Definition, ToDefinition, TypeDef };
use super::super::getter::{ GetterWrap, Getter };

struct ClonedDef<T> {
    value: T,
}

/// Creates `Definition` from cloneable value.
#[stable]
impl<T: 'static + Clone> ToDefinition for T {
    fn to_definition<'a>(self) -> Box<Definition + 'a> {
        // We wrap this one in a ClonedDef just to avoid conflicting
        // with definitions that need simple Cloned T for other pusposes,
        // like Rc.
        box ClonedDef { value : self }
    }
}

impl<T: 'static + Clone> Definition for ClonedDef<T> {
    fn get_type(&self) -> TypeDef {
        TypeDef::of::<T>()
    }

    fn get_arg_types(&self) -> Vec<TypeDef> {
        Vec::new()
    }

    fn get_getter(&self, _arg_getters: &[Box<Any>]) -> Box<Any> {
        box GetterWrap::new(
            box self.value.clone()
        ) as Box<Any>
    }
}

impl<T: 'static + Clone> Getter<T> for T {
    fn get(&self) -> T {
        self.clone()
    }
}
<commit_msg>Typo in comment.<commit_after>use std::any::{ Any };

use super::{ Definition, ToDefinition, TypeDef };
use super::super::getter::{ GetterWrap, Getter };

struct ClonedDef<T> {
    value: T,
}

/// Creates `Definition` from cloneable value.
#[stable]
impl<T: 'static + Clone> ToDefinition for T {
    fn to_definition<'a>(self) -> Box<Definition + 'a> {
        // We wrap this one in a ClonedDef just to avoid conflicting
        // with definitions that need simple Cloned T for other purposes,
        // like Rc.
        box ClonedDef { value : self }
    }
}

impl<T: 'static + Clone> Definition for ClonedDef<T> {
    fn get_type(&self) -> TypeDef {
        TypeDef::of::<T>()
    }

    fn get_arg_types(&self) -> Vec<TypeDef> {
        Vec::new()
    }

    fn get_getter(&self, _arg_getters: &[Box<Any>]) -> Box<Any> {
        box GetterWrap::new(
            box self.value.clone()
        ) as Box<Any>
    }
}

impl<T: 'static + Clone> Getter<T> for T {
    fn get(&self) -> T {
        self.clone()
    }
}
<|endoftext|>


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

//! # gl_generator
//!
//! `gl_generator` is an OpenGL bindings generator plugin. It defines a macro
//!  named `generate_gl_bindings!` which can be used to generate all constants
//!  and functions of a given OpenGL version.
//!
//! ## Example
//!
//! ~~~rust
//! #[phase(plugin)]
//! extern crate gl_generator;
//! extern crate libc;
//!
//! use std::mem;
//! use self::types::*;
//!
//! generate_gl_bindings! {
//!     api: gl,
//!     profile: core,
//!     version: 4.5,
//!     generator: global,
//!     extensions: [
//!         GL_EXT_texture_filter_anisotropic,
//!     ],
//! }
//! ~~~
//!
//! ## Arguments
//!
//! Each field can be specified at most once, or not at all. If the field is not
//! specified, then a default value will be used.
//!
//! - `api`: The API to generate. Can be either `"gl"`, `"gles1"`, `"gles2"`,
//!   `"wgl"`, `"glx"`, `"egl"`. Defaults to `"gl"`.
//! - `profile`: Can be either `"core"` or `"compatibility"`. Defaults to
//!   `"core"`. `"core"` will only include all functions supported by the
//!   requested version it self, while `"compatibility"` will include all the
//!   functions from previous versions as well.
//! - `version`: The requested API version. This is usually in the form
//!   `"major.minor"`. Defaults to `"1.0"`
//! - `generator`: The type of loader to generate. Can be either `"static"`,
//!   `"global"`, or `"struct"`. Defaults to `"static"`.
//! - `extensions`: Extra extensions to include in the bindings. These are
//!   specified as a list of strings. Defaults to `[]`.
//!
//! ## About EGL
//!
//! When you generate bindings for EGL, the following platform-specific types must be declared
//!  *at the same level where you call `generate_gl_bindings`*:
//!
//! - `khronos_utime_nanoseconds_t`
//! - `khronos_uint64_t`
//! - `khronos_ssize_t`
//! - `EGLNativeDisplayType`
//! - `EGLNativePixmapType`
//! - `EGLNativeWindowType`
//! - `EGLint`
//! - `NativeDisplayType`
//! - `NativePixmapType`
//! - `NativeWindowType`
//!

#![crate_name = "gl_generator"]
#![comment = "OpenGL function loader generator."]
#![license = "ASL2"]
#![crate_type = "dylib"]

#![feature(advanced_slice_patterns)]
#![feature(macro_rules)]
#![feature(phase)]
#![feature(plugin_registrar)]
#![feature(quote)]

#[phase(plugin, link)]
extern crate log;

#[phase(plugin)]
extern crate regex_macros;

extern crate khronos_api;
extern crate regex;
extern crate rustc;
extern crate syntax;

use generators::Generator;
use registry::{Registry, Filter, Ns};
use syntax::ast::{TokenTree, TtDelimited, TtToken};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacResult, MacItems};
use syntax::parse::token;

mod generators;

#[allow(dead_code)]
mod registry;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut ::rustc::plugin::Registry) {
    reg.register_macro("generate_gl_bindings", macro_handler);
}

/// A predicate that is useful for splitting a comma separated list of tokens
fn is_comma(tt: &TokenTree) -> bool {
    match *tt {
        TtToken(_, token::COMMA) => true,
        _ => false,
    }
}

/// Drops a trailing comma if it exists
fn drop_trailing_comma(tts: &[TokenTree]) -> &[TokenTree] {
    match tts {
        [tts.., TtToken(_, token::COMMA)] => tts,
        tts => tts,
    }
}

/// handler for generate_gl_bindings!
fn macro_handler(ecx: &mut ExtCtxt, span: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
    // Generator options
    let mut api = None::<(Ns, &'static [u8])>;
    let mut profile = None::<String>;
    let mut version = None::<String>;
    let mut generator = None::<Box<Generator>>;
    let mut extensions = None::<Vec<String>>;

    let tts = drop_trailing_comma(tts);

    // Iterate through the comma separated
    for tts in tts.split(is_comma) {
        let mut it = tts.iter();
        let field = match it.next() {
            Some(&TtToken(_, token::IDENT(ref field, _))) => field.as_str(),
            tt => {
                let span = tt.map(|tt| tt.get_span()).unwrap_or(span);
                ecx.span_err(span, "Expected a generator argument name, \
                                    either: `api`, `profile`, `version`, \
                                    `generator`, or `extensions`.");
                return DummyResult::any(span);
            },
        };
        match it.next() {
            Some(&TtToken(_, token::COLON)) => {},
            tt => {
                let span = tt.map(|tt| tt.get_span()).unwrap_or(span);
                ecx.span_err(span, "Expected `:`");
                return DummyResult::any(span);
            },
        }
        match (field, it.collect::<Vec<_>>().as_slice()) {
            ("api", tts) => {
                if api.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "An API was already specified.");
                    return DummyResult::any(span);
                }
                api = Some(match tts {
                    [&TtToken(_, token::LIT_STR(api))] if api.as_str() == "gl"
                        => (registry::Gl, khronos_api::GL_XML),
                    [&TtToken(_, token::LIT_STR(api))] if api.as_str() == "glx"
                        => (registry::Glx, khronos_api::GLX_XML),
                    [&TtToken(_, token::LIT_STR(api))] if api.as_str() == "wgl"
                        => (registry::Wgl, khronos_api::WGL_XML),
                    [&TtToken(_, token::LIT_STR(api))] if api.as_str() == "egl"
                        => (registry::Egl, khronos_api::EGL_XML),
                    [&TtToken(_, token::LIT_STR(api))] if api.as_str() == "gles1"
                        => (registry::Gles1, khronos_api::GL_XML),
                    [&TtToken(_, token::LIT_STR(api))] if api.as_str() == "gles2"
                        => (registry::Gles2, khronos_api::GL_XML),
                    [&TtToken(span, token::LIT_STR(api))] => {
                        ecx.span_err(span, format!("Unknown API \"{}\"", api.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid API format, expected \
                                            string.");
                        return DummyResult::any(span);
                    }
                })
            }
            ("profile", tts) => {
                if profile.is_some() {
                    ecx.span_err(tts[0].get_span(), "A profile was already specified.");
                    return DummyResult::any(span);
                }
                profile = Some(match tts {
                    [&TtToken(_, token::LIT_STR(profile))] if profile.as_str() == "core"
                        => "core".to_string(),
                    [&TtToken(_, token::LIT_STR(profile))] if profile.as_str() == "compatibility"
                        => "compatibility".to_string(),
                    [&TtToken(_, token::LIT_STR(profile))] => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, format!("Unknown profile \"{}\"",
                                                   profile.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid profile format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                })
            }
            ("version", tts) => {
                if version.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "A version was already specified.");
                    return DummyResult::any(span);
                }
                version = Some(match tts {
                    [&TtToken(_, token::LIT_STR(version))] => {
                        version.as_str().to_string()
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid version format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                });
            }
            ("generator", tts) => {
                if generator.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "A generator was already specified.");
                    return DummyResult::any(span);
                }
                generator = Some(match tts {
                    [&TtToken(_, token::LIT_STR(gen))] if gen.as_str() == "global"
                        => box generators::global_gen::GlobalGenerator as Box<Generator>,
                    [&TtToken(_, token::LIT_STR(gen))] if gen.as_str() == "struct"
                        => box generators::struct_gen::StructGenerator as Box<Generator>,
                    [&TtToken(_, token::LIT_STR(gen))] if gen.as_str() == "static"
                        => box generators::static_gen::StaticGenerator as Box<Generator>,
                    [&TtToken(span, token::LIT_STR(gen))] => {
                        ecx.span_err(span, format!("Unknown generator \"{}\"",
                                                   gen.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid generator format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                });
            }
            ("extensions", tts) => {
                if extensions.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "The list of extensions were already \
                                        specified.");
                    return DummyResult::any(span);
                }
                extensions = Some(match tts {
                    [&TtDelimited(span, ref delimited)] => {
                        let (ref begin, ref tts, ref close) = **delimited;
                        match (&begin.token, &close.token) {
                            (&token::LBRACKET, &token::RBRACKET) => {
                                // Drop the trailing comma if it exists
                                let tts = drop_trailing_comma(tts.as_slice());

                                // Collect the extensions, breaking early if a parse
                                // error occurs.
                                let mut failed = false;
                                let exts = tts.split(is_comma).scan((), |_, tts| {
                                    match tts {
                                        [TtToken(_, token::LIT_STR(ext))] => {
                                            Some(ext.as_str().to_string())
                                        },
                                        _ => {
                                            failed = true;
                                            None
                                        },
                                    }
                                }).collect();

                                // Cause an error if there is still some leftover
                                // tokens.
                                if failed {
                                    ecx.span_err(span, "Invalid extension format, \
                                                        expected string.");
                                    return DummyResult::any(span);
                                } else {
                                    exts
                                }
                            },
                            (_, _) => {
                                ecx.span_err(span, "Expected a comma separated \
                                                    list of extension strings \
                                                    delimited by square brackets: \
                                                    `[]`");
                                return DummyResult::any(span);
                            },
                        }
                    },
                    _ => {
                        ecx.span_err(span, "Expected a comma separated list of \
                                            extension strings.");
                        return DummyResult::any(span);
                    },
                });
            }
            (field, _) => {
                ecx.span_err(span, format!("Unknown field `{}`", field).as_slice());
                return DummyResult::any(span);
            }
        }
    }

    // Use default values if the parameters have not been set
    let (ns, source) = api.unwrap_or((registry::Gl, khronos_api::GL_XML));
    let extensions = extensions.unwrap_or(vec![]);
    let version = version.unwrap_or("1.0".to_string());
    let generator = generator.unwrap_or(box generators::static_gen::StaticGenerator);
    let profile = profile.unwrap_or("core".to_string());

    // Get generator field values, using default values if they have not been
    // specified
    let filter = Some(Filter {
        api: ns.to_string(),
        extensions: extensions,
        version: version,
        profile: profile,
    });

    // Generate the registry of all bindings
    let registry = {
        use std::io::BufReader;
        use std::task;

        let result = task::try(proc() {
            let reader = BufReader::new(source);
            Registry::from_xml(reader, ns, filter)
        });

        match result {
            Ok(reg) => reg,
            Err(err) => {
                use std::any::{Any, AnyRefExt};
                let err: &Any = &*err;

                match err {
                    err if err.is::<String>() => {
                        ecx.span_err(span, "error while parsing the registry");
                        ecx.span_err(span, err.downcast_ref::<String>().unwrap().as_slice());
                    },
                    err if err.is::<&'static str>() => {
                        ecx.span_err(span, "error while parsing the registry");
                        ecx.span_err(span, err.downcast_ref::<&'static str>().unwrap().as_slice());
                    },
                    _ => {
                        ecx.span_err(span, "unknown error while parsing the registry");
                    }
                }

                return DummyResult::any(span);
            }
        }
    };

    // generating the Rust bindings as a source code into "buffer"
    let items = generator.write(ecx, &registry, ns);

    MacItems::new(items.into_iter())
}
<commit_msg>Update for rustc<commit_after>// Copyright 2013-2014 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! # gl_generator
//!
//! `gl_generator` is an OpenGL bindings generator plugin. It defines a macro
//!  named `generate_gl_bindings!` which can be used to generate all constants
//!  and functions of a given OpenGL version.
//!
//! ## Example
//!
//! ~~~rust
//! #[phase(plugin)]
//! extern crate gl_generator;
//! extern crate libc;
//!
//! use std::mem;
//! use self::types::*;
//!
//! generate_gl_bindings! {
//!     api: gl,
//!     profile: core,
//!     version: 4.5,
//!     generator: global,
//!     extensions: [
//!         GL_EXT_texture_filter_anisotropic,
//!     ],
//! }
//! ~~~
//!
//! ## Arguments
//!
//! Each field can be specified at most once, or not at all. If the field is not
//! specified, then a default value will be used.
//!
//! - `api`: The API to generate. Can be either `"gl"`, `"gles1"`, `"gles2"`,
//!   `"wgl"`, `"glx"`, `"egl"`. Defaults to `"gl"`.
//! - `profile`: Can be either `"core"` or `"compatibility"`. Defaults to
//!   `"core"`. `"core"` will only include all functions supported by the
//!   requested version it self, while `"compatibility"` will include all the
//!   functions from previous versions as well.
//! - `version`: The requested API version. This is usually in the form
//!   `"major.minor"`. Defaults to `"1.0"`
//! - `generator`: The type of loader to generate. Can be either `"static"`,
//!   `"global"`, or `"struct"`. Defaults to `"static"`.
//! - `extensions`: Extra extensions to include in the bindings. These are
//!   specified as a list of strings. Defaults to `[]`.
//!
//! ## About EGL
//!
//! When you generate bindings for EGL, the following platform-specific types must be declared
//!  *at the same level where you call `generate_gl_bindings`*:
//!
//! - `khronos_utime_nanoseconds_t`
//! - `khronos_uint64_t`
//! - `khronos_ssize_t`
//! - `EGLNativeDisplayType`
//! - `EGLNativePixmapType`
//! - `EGLNativeWindowType`
//! - `EGLint`
//! - `NativeDisplayType`
//! - `NativePixmapType`
//! - `NativeWindowType`
//!

#![crate_name = "gl_generator"]
#![comment = "OpenGL function loader generator."]
#![license = "ASL2"]
#![crate_type = "dylib"]

#![feature(advanced_slice_patterns)]
#![feature(macro_rules)]
#![feature(phase)]
#![feature(plugin_registrar)]
#![feature(quote)]

#[phase(plugin, link)]
extern crate log;

#[phase(plugin)]
extern crate regex_macros;

extern crate khronos_api;
extern crate regex;
extern crate rustc;
extern crate syntax;

use generators::Generator;
use registry::{Registry, Filter, Ns};
use syntax::ast::{TokenTree, TtDelimited, TtToken};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacResult, MacItems};
use syntax::parse::token;

mod generators;

#[allow(dead_code)]
mod registry;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut ::rustc::plugin::Registry) {
    reg.register_macro("generate_gl_bindings", macro_handler);
}

/// A predicate that is useful for splitting a comma separated list of tokens
fn is_comma(tt: &TokenTree) -> bool {
    match *tt {
        TtToken(_, token::Comma) => true,
        _ => false,
    }
}

/// Drops a trailing comma if it exists
fn drop_trailing_comma(tts: &[TokenTree]) -> &[TokenTree] {
    match tts {
        [tts.., TtToken(_, token::Comma)] => tts,
        tts => tts,
    }
}

/// handler for generate_gl_bindings!
fn macro_handler(ecx: &mut ExtCtxt, span: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
    // Generator options
    let mut api = None::<(Ns, &'static [u8])>;
    let mut profile = None::<String>;
    let mut version = None::<String>;
    let mut generator = None::<Box<Generator>>;
    let mut extensions = None::<Vec<String>>;

    let tts = drop_trailing_comma(tts);

    // Iterate through the comma separated
    for tts in tts.split(is_comma) {
        let mut it = tts.iter();
        let field = match it.next() {
            Some(&TtToken(_, token::Ident(ref field, _))) => field.as_str(),
            tt => {
                let span = tt.map(|tt| tt.get_span()).unwrap_or(span);
                ecx.span_err(span, "Expected a generator argument name, \
                                    either: `api`, `profile`, `version`, \
                                    `generator`, or `extensions`.");
                return DummyResult::any(span);
            },
        };
        match it.next() {
            Some(&TtToken(_, token::Colon)) => {},
            tt => {
                let span = tt.map(|tt| tt.get_span()).unwrap_or(span);
                ecx.span_err(span, "Expected `:`");
                return DummyResult::any(span);
            },
        }
        match (field, it.collect::<Vec<_>>().as_slice()) {
            ("api", tts) => {
                if api.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "An API was already specified.");
                    return DummyResult::any(span);
                }
                api = Some(match tts {
                    [&TtToken(_, token::LitStr(api))] if api.as_str() == "gl"
                        => (registry::Gl, khronos_api::GL_XML),
                    [&TtToken(_, token::LitStr(api))] if api.as_str() == "glx"
                        => (registry::Glx, khronos_api::GLX_XML),
                    [&TtToken(_, token::LitStr(api))] if api.as_str() == "wgl"
                        => (registry::Wgl, khronos_api::WGL_XML),
                    [&TtToken(_, token::LitStr(api))] if api.as_str() == "egl"
                        => (registry::Egl, khronos_api::EGL_XML),
                    [&TtToken(_, token::LitStr(api))] if api.as_str() == "gles1"
                        => (registry::Gles1, khronos_api::GL_XML),
                    [&TtToken(_, token::LitStr(api))] if api.as_str() == "gles2"
                        => (registry::Gles2, khronos_api::GL_XML),
                    [&TtToken(span, token::LitStr(api))] => {
                        ecx.span_err(span, format!("Unknown API \"{}\"", api.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid API format, expected \
                                            string.");
                        return DummyResult::any(span);
                    }
                })
            }
            ("profile", tts) => {
                if profile.is_some() {
                    ecx.span_err(tts[0].get_span(), "A profile was already specified.");
                    return DummyResult::any(span);
                }
                profile = Some(match tts {
                    [&TtToken(_, token::LitStr(profile))] if profile.as_str() == "core"
                        => "core".to_string(),
                    [&TtToken(_, token::LitStr(profile))] if profile.as_str() == "compatibility"
                        => "compatibility".to_string(),
                    [&TtToken(_, token::LitStr(profile))] => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, format!("Unknown profile \"{}\"",
                                                   profile.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid profile format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                })
            }
            ("version", tts) => {
                if version.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "A version was already specified.");
                    return DummyResult::any(span);
                }
                version = Some(match tts {
                    [&TtToken(_, token::LitStr(version))] => {
                        version.as_str().to_string()
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid version format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                });
            }
            ("generator", tts) => {
                if generator.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "A generator was already specified.");
                    return DummyResult::any(span);
                }
                generator = Some(match tts {
                    [&TtToken(_, token::LitStr(gen))] if gen.as_str() == "global"
                        => box generators::global_gen::GlobalGenerator as Box<Generator>,
                    [&TtToken(_, token::LitStr(gen))] if gen.as_str() == "struct"
                        => box generators::struct_gen::StructGenerator as Box<Generator>,
                    [&TtToken(_, token::LitStr(gen))] if gen.as_str() == "static"
                        => box generators::static_gen::StaticGenerator as Box<Generator>,
                    [&TtToken(span, token::LitStr(gen))] => {
                        ecx.span_err(span, format!("Unknown generator \"{}\"",
                                                   gen.as_str()).as_slice());
                        return DummyResult::any(span);
                    },
                    _ => {
                        let span = tts.head().map_or(span, |tt| tt.get_span());
                        ecx.span_err(span, "Invalid generator format, expected \
                                            string.");
                        return DummyResult::any(span);
                    },
                });
            }
            ("extensions", tts) => {
                if extensions.is_some() {
                    let span = tts.head().map_or(span, |tt| tt.get_span());
                    ecx.span_err(span, "The list of extensions were already \
                                        specified.");
                    return DummyResult::any(span);
                }
                extensions = Some(match tts {
                    [&TtDelimited(span, ref delimited)] => {
                        let (ref begin, ref tts, ref close) = **delimited;
                        match (&begin.token, &close.token) {
                            (&token::LBracket, &token::RBracket) => {
                                // Drop the trailing comma if it exists
                                let tts = drop_trailing_comma(tts.as_slice());

                                // Collect the extensions, breaking early if a parse
                                // error occurs.
                                let mut failed = false;
                                let exts = tts.split(is_comma).scan((), |_, tts| {
                                    match tts {
                                        [TtToken(_, token::LitStr(ext))] => {
                                            Some(ext.as_str().to_string())
                                        },
                                        _ => {
                                            failed = true;
                                            None
                                        },
                                    }
                                }).collect();

                                // Cause an error if there is still some leftover
                                // tokens.
                                if failed {
                                    ecx.span_err(span, "Invalid extension format, \
                                                        expected string.");
                                    return DummyResult::any(span);
                                } else {
                                    exts
                                }
                            },
                            (_, _) => {
                                ecx.span_err(span, "Expected a comma separated \
                                                    list of extension strings \
                                                    delimited by square brackets: \
                                                    `[]`");
                                return DummyResult::any(span);
                            },
                        }
                    },
                    _ => {
                        ecx.span_err(span, "Expected a comma separated list of \
                                            extension strings.");
                        return DummyResult::any(span);
                    },
                });
            }
            (field, _) => {
                ecx.span_err(span, format!("Unknown field `{}`", field).as_slice());
                return DummyResult::any(span);
            }
        }
    }

    // Use default values if the parameters have not been set
    let (ns, source) = api.unwrap_or((registry::Gl, khronos_api::GL_XML));
    let extensions = extensions.unwrap_or(vec![]);
    let version = version.unwrap_or("1.0".to_string());
    let generator = generator.unwrap_or(box generators::static_gen::StaticGenerator);
    let profile = profile.unwrap_or("core".to_string());

    // Get generator field values, using default values if they have not been
    // specified
    let filter = Some(Filter {
        api: ns.to_string(),
        extensions: extensions,
        version: version,
        profile: profile,
    });

    // Generate the registry of all bindings
    let registry = {
        use std::io::BufReader;
        use std::task;

        let result = task::try(proc() {
            let reader = BufReader::new(source);
            Registry::from_xml(reader, ns, filter)
        });

        match result {
            Ok(reg) => reg,
            Err(err) => {
                use std::any::{Any, AnyRefExt};
                let err: &Any = &*err;

                match err {
                    err if err.is::<String>() => {
                        ecx.span_err(span, "error while parsing the registry");
                        ecx.span_err(span, err.downcast_ref::<String>().unwrap().as_slice());
                    },
                    err if err.is::<&'static str>() => {
                        ecx.span_err(span, "error while parsing the registry");
                        ecx.span_err(span, err.downcast_ref::<&'static str>().unwrap().as_slice());
                    },
                    _ => {
                        ecx.span_err(span, "unknown error while parsing the registry");
                    }
                }

                return DummyResult::any(span);
            }
        }
    };

    // generating the Rust bindings as a source code into "buffer"
    let items = generator.write(ecx, &registry, ns);

    MacItems::new(items.into_iter())
}
<|endoftext|>


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

//! Simple file-locking apis for each OS.
//!
//! This is not meant to be in the standard library, it does nothing with
//! green/native threading. This is just a bare-bones enough solution for
//! librustdoc, it is not production quality at all.

#[allow(non_camel_case_types)];

pub use self::imp::Lock;

#[cfg(unix)]
mod imp {
    use std::libc;

    #[cfg(target_os = "linux")]
    mod os {
        use std::libc;

        pub struct flock {
            l_type: libc::c_short,
            l_whence: libc::c_short,
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,

            // not actually here, but brings in line with freebsd
            l_sysid: libc::c_int,
        }

        pub static F_WRLCK: libc::c_short = 1;
        pub static F_UNLCK: libc::c_short = 2;
        pub static F_SETLK: libc::c_int = 6;
        pub static F_SETLKW: libc::c_int = 7;
    }

    #[cfg(target_os = "freebsd")]
    mod os {
        use std::libc;

        pub struct flock {
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,
            l_type: libc::c_short,
            l_whence: libc::c_short,
            l_sysid: libc::c_int,
        }

        pub static F_UNLCK: libc::c_short = 2;
        pub static F_WRLCK: libc::c_short = 3;
        pub static F_SETLK: libc::c_int = 12;
        pub static F_SETLKW: libc::c_int = 13;
    }

    #[cfg(target_os = "macos")]
    mod os {
        use std::libc;

        pub struct flock {
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,
            l_type: libc::c_short,
            l_whence: libc::c_short,

            // not actually here, but brings in line with freebsd
            l_sysid: libc::c_int,
        }

        pub static F_UNLCK: libc::c_short = 2;
        pub static F_WRLCK: libc::c_short = 3;
        pub static F_SETLK: libc::c_int = 8;
        pub static F_SETLKW: libc::c_int = 9;
    }

    pub struct Lock {
        priv fd: libc::c_int,
    }

    impl Lock {
        pub fn new(p: &Path) -> Lock {
            let fd = p.with_c_str(|s| unsafe {
                libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU)
            });
            assert!(fd > 0);
            let flock = os::flock {
                l_start: 0,
                l_len: 0,
                l_pid: 0,
                l_whence: libc::SEEK_SET as libc::c_short,
                l_type: os::F_WRLCK,
                l_sysid: 0,
            };
            let ret = unsafe {
                libc::fcntl(fd, os::F_SETLKW, &flock as *os::flock)
            };
            if ret == -1 {
                unsafe { libc::close(fd); }
                fail!("could not lock `{}`", p.display())
            }
            Lock { fd: fd }
        }
    }

    impl Drop for Lock {
        fn drop(&mut self) {
            let flock = os::flock {
                l_start: 0,
                l_len: 0,
                l_pid: 0,
                l_whence: libc::SEEK_SET as libc::c_short,
                l_type: os::F_UNLCK,
                l_sysid: 0,
            };
            unsafe {
                libc::fcntl(self.fd, os::F_SETLK, &flock as *os::flock);
                libc::close(self.fd);
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    use std::libc;
    use std::mem;
    use std::os::win32::as_utf16_p;
    use std::ptr;

    static LOCKFILE_EXCLUSIVE_LOCK: libc::DWORD = 0x00000002;

    extern "system" {
        fn LockFileEx(hFile: libc::HANDLE,
                      dwFlags: libc::DWORD,
                      dwReserved: libc::DWORD,
                      nNumberOfBytesToLockLow: libc::DWORD,
                      nNumberOfBytesToLockHigh: libc::DWORD,
                      lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
        fn UnlockFileEx(hFile: libc::HANDLE,
                        dwReserved: libc::DWORD,
                        nNumberOfBytesToLockLow: libc::DWORD,
                        nNumberOfBytesToLockHigh: libc::DWORD,
                        lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
    }

    pub struct Lock {
        priv handle: libc::HANDLE,
    }

    impl Lock {
        pub fn new(p: &Path) -> Lock {
            let handle = as_utf16_p(p.as_str().unwrap(), |p| unsafe {
                libc::CreateFileW(p, libc::GENERIC_READ, 0, ptr::mut_null(),
                                  libc::CREATE_ALWAYS,
                                  libc::FILE_ATTRIBUTE_NORMAL,
                                  ptr::mut_null())
            });
            assert!(handle as uint != libc::INVALID_HANDLE_VALUE as uint);
            let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
            let ret = unsafe {
                LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
                           &mut overlapped)
            };
            if ret == 0 {
                unsafe { libc::CloseHandle(handle); }
                fail!("could not lock `{}`", p.display())
            }
            Lock { handle: handle }
        }
    }

    impl Drop for Lock {
        fn drop(&mut self) {
            let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
            unsafe {
                UnlockFileEx(self.handle, 0, 100, 0, &mut overlapped);
                libc::CloseHandle(self.handle);
            }
        }
    }
}
<commit_msg>rustdoc: Fix file locking on windows<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Simple file-locking apis for each OS.
//!
//! This is not meant to be in the standard library, it does nothing with
//! green/native threading. This is just a bare-bones enough solution for
//! librustdoc, it is not production quality at all.

#[allow(non_camel_case_types)];

pub use self::imp::Lock;

#[cfg(unix)]
mod imp {
    use std::libc;

    #[cfg(target_os = "linux")]
    mod os {
        use std::libc;

        pub struct flock {
            l_type: libc::c_short,
            l_whence: libc::c_short,
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,

            // not actually here, but brings in line with freebsd
            l_sysid: libc::c_int,
        }

        pub static F_WRLCK: libc::c_short = 1;
        pub static F_UNLCK: libc::c_short = 2;
        pub static F_SETLK: libc::c_int = 6;
        pub static F_SETLKW: libc::c_int = 7;
    }

    #[cfg(target_os = "freebsd")]
    mod os {
        use std::libc;

        pub struct flock {
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,
            l_type: libc::c_short,
            l_whence: libc::c_short,
            l_sysid: libc::c_int,
        }

        pub static F_UNLCK: libc::c_short = 2;
        pub static F_WRLCK: libc::c_short = 3;
        pub static F_SETLK: libc::c_int = 12;
        pub static F_SETLKW: libc::c_int = 13;
    }

    #[cfg(target_os = "macos")]
    mod os {
        use std::libc;

        pub struct flock {
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,
            l_type: libc::c_short,
            l_whence: libc::c_short,

            // not actually here, but brings in line with freebsd
            l_sysid: libc::c_int,
        }

        pub static F_UNLCK: libc::c_short = 2;
        pub static F_WRLCK: libc::c_short = 3;
        pub static F_SETLK: libc::c_int = 8;
        pub static F_SETLKW: libc::c_int = 9;
    }

    pub struct Lock {
        priv fd: libc::c_int,
    }

    impl Lock {
        pub fn new(p: &Path) -> Lock {
            let fd = p.with_c_str(|s| unsafe {
                libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU)
            });
            assert!(fd > 0);
            let flock = os::flock {
                l_start: 0,
                l_len: 0,
                l_pid: 0,
                l_whence: libc::SEEK_SET as libc::c_short,
                l_type: os::F_WRLCK,
                l_sysid: 0,
            };
            let ret = unsafe {
                libc::fcntl(fd, os::F_SETLKW, &flock as *os::flock)
            };
            if ret == -1 {
                unsafe { libc::close(fd); }
                fail!("could not lock `{}`", p.display())
            }
            Lock { fd: fd }
        }
    }

    impl Drop for Lock {
        fn drop(&mut self) {
            let flock = os::flock {
                l_start: 0,
                l_len: 0,
                l_pid: 0,
                l_whence: libc::SEEK_SET as libc::c_short,
                l_type: os::F_UNLCK,
                l_sysid: 0,
            };
            unsafe {
                libc::fcntl(self.fd, os::F_SETLK, &flock as *os::flock);
                libc::close(self.fd);
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    use std::libc;
    use std::mem;
    use std::os::win32::as_utf16_p;
    use std::os;
    use std::ptr;

    static LOCKFILE_EXCLUSIVE_LOCK: libc::DWORD = 0x00000002;

    extern "system" {
        fn LockFileEx(hFile: libc::HANDLE,
                      dwFlags: libc::DWORD,
                      dwReserved: libc::DWORD,
                      nNumberOfBytesToLockLow: libc::DWORD,
                      nNumberOfBytesToLockHigh: libc::DWORD,
                      lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
        fn UnlockFileEx(hFile: libc::HANDLE,
                        dwReserved: libc::DWORD,
                        nNumberOfBytesToLockLow: libc::DWORD,
                        nNumberOfBytesToLockHigh: libc::DWORD,
                        lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
    }

    pub struct Lock {
        priv handle: libc::HANDLE,
    }

    impl Lock {
        pub fn new(p: &Path) -> Lock {
            let handle = as_utf16_p(p.as_str().unwrap(), |p| unsafe {
                libc::CreateFileW(p,
                                  libc::FILE_GENERIC_READ |
                                    libc::FILE_GENERIC_WRITE,
                                  libc::FILE_SHARE_READ |
                                    libc::FILE_SHARE_DELETE |
                                    libc::FILE_SHARE_WRITE,
                                  ptr::mut_null(),
                                  libc::CREATE_ALWAYS,
                                  libc::FILE_ATTRIBUTE_NORMAL,
                                  ptr::mut_null())
            });
            if handle as uint == libc::INVALID_HANDLE_VALUE as uint {
                fail!("create file error: {}", os::last_os_error());
            }
            let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
            let ret = unsafe {
                LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
                           &mut overlapped)
            };
            if ret == 0 {
                unsafe { libc::CloseHandle(handle); }
                fail!("could not lock `{}`: {}", p.display(),
                      os::last_os_error())
            }
            Lock { handle: handle }
        }
    }

    impl Drop for Lock {
        fn drop(&mut self) {
            let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
            unsafe {
                UnlockFileEx(self.handle, 0, 100, 0, &mut overlapped);
                libc::CloseHandle(self.handle);
            }
        }
    }
}
<|endoftext|>