<commit_before>use std::iter::Rev;
use core::slice::Items;
use std::collections::hash_map::{HashMap, Entries, Entry};
use std::collections::HashSet;

use util::{OptionBorrowExt, IntoOwned, IteratorClonedPairwiseExt};

pub const NS_XMLNS_PREFIX: &'static str = "xmlns";
pub const NS_XMLNS_URI: &'static str    = "http://www.w3.org/2000/xmlns/";
pub const NS_XML_PREFIX: &'static str   = "xml";
pub const NS_XML_URI: &'static str      = "http://www.w3.org/XML/1998/namespace";
pub const NS_EMPTY_URI: &'static str    = "";

/// Denotes something which contains namespace URI mappings.
///
/// A URI mapping is a pair of type `(Option<&str>, &str)`, where the first item
/// is a namespace prefix (`None` meaning default prefix) and the second item
/// is a URI mapped to this prefix.
pub trait NamespaceIterable<'a, I: Iterator<(Option<&'a str>, &'a str)>> {
    fn uri_mappings(&'a self) -> I;
}

/// Namespace is a map from prefixes to namespace URIs.
///
/// `None` prefix means no prefix (i.e. default namespace).
#[deriving(PartialEq, Clone)]
pub struct Namespace(pub HashMap<Option<String>, String>);

impl Namespace {
    /// Returns an empty namespace.
    #[inline]
    pub fn empty() -> Namespace { Namespace(HashMap::with_capacity(3)) }

    /// Checks whether this namespace is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Checks whether this namespace is essentially empty, that is, it does not contain
    /// anything but the default mappings.
    pub fn is_essentially_empty(&self) -> bool {
        // a shortcut for a namespace which is definitely not empty
        if self.0.len() > 3 { return false; }

        self.0.iter().all(|(k, v)| match (k.borrow_internals(), v[]) {
            (None,                  NS_EMPTY_URI) => true,
            (Some(NS_XMLNS_PREFIX), NS_XMLNS_URI) => true,
            (Some(NS_XML_PREFIX),   NS_XML_URI)   => true,
            _ => false
        })
    }

    /// Puts a mapping into this namespace.
    ///
    /// This method does not override an already existing mapping.
    ///
    /// Returns a boolean flag indicating whether the map already contained
    /// the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
    /// was already present in the namespace.
    pub fn put<S1, S2>(&mut self, prefix: Option<S1>, uri: S2) -> bool
            where S1: IntoOwned<String>, S2: IntoOwned<String> {
        match self.0.entry(prefix.map(|v| v.into_owned())) {
            Entry::Occupied(_) => false,
            Entry::Vacant(ve) => {
                ve.set(uri.into_owned());
                true
            }
        }
    }

    /// Puts a mapping into this namespace forcefully.
    ///
    /// This method, as opposed to `put()`, does replace an already existing mapping.
    ///
    /// Returns previous URI which was assigned to the given prefix, if it is present.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `Some(uri)` with `uri` being a previous URI assigned to the `prefix`, or
    /// `None` if such prefix was not present in the namespace before.
    pub fn force_put<S1, S2>(&mut self, prefix: Option<S1>, uri: S2) -> Option<String>
            where S1: IntoOwned<String>, S2: IntoOwned<String> {
        self.0.insert(prefix.map(|v| v.into_owned()), uri.into_owned())
    }

    /// Queries the namespace for the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace).
    ///
    /// # Return value
    /// Namespace URI corresponding to the given prefix, if it is present.
    pub fn get<'a>(&'a self, prefix: &Option<String>) -> Option<&'a str> {
        self.0.get(prefix).map(|s| &**s)
    }
}

/// An iterator over mappings from prefixes to URIs in a namespace.
///
/// This is a separate structure because `map()` operation on iterators uses an unboxed
/// closure type which can't be named.
pub struct NamespaceMappings<'a> {
    entries: Entries<'a, Option<String>, String>
}

impl<'a> Iterator<(Option<&'a str>, &'a str)> for NamespaceMappings<'a> {
    fn next(&mut self) -> Option<(Option<&'a str>, &'a str)> {
        self.entries.next().map(|(prefix, uri)| {
            (prefix.as_ref().map(|p| p.as_slice()), uri.as_slice())
        })
    }
}

impl<'a> NamespaceIterable<'a, NamespaceMappings<'a>> for Namespace {
    fn uri_mappings(&'a self) -> NamespaceMappings<'a> {
        NamespaceMappings { entries: self.0.iter() }
    }
}

/// Namespace stack is a sequence of namespaces.
///
/// Namespace stack is used to represent cumulative namespace consisting of
/// combined namespaces from nested elements.
#[deriving(Clone, PartialEq)]
pub struct NamespaceStack(pub Vec<Namespace>);

impl NamespaceStack {
    /// Returns an empty namespace stack.
    #[inline]
    pub fn empty() -> NamespaceStack { NamespaceStack(Vec::with_capacity(2)) }

    /// Returns a namespace stack with default items in it.
    ///
    /// Default items are the following:
    ///
    /// * `xml` → `http://www.w3.org/XML/1998/namespace`;
    /// * `xmlns` → `http://www.w3.org/2000/xmlns/`.
    #[inline]
    pub fn default() -> NamespaceStack {
        let mut nst = NamespaceStack::empty();
        nst.push_empty();
        // xml namespace
        nst.put(Some(NS_XML_PREFIX.to_string()), NS_XML_URI.to_string());
        // xmlns namespace
        nst.put(Some(NS_XMLNS_PREFIX.to_string()), NS_XMLNS_URI.to_string());
        // empty namespace
        nst.put(None, NS_EMPTY_URI.to_string());
        nst
    }

    /// Adds an empty namespace to the top of this stack.
    #[inline]
    pub fn push_empty(&mut self) {
        self.0.push(Namespace::empty());
    }

    /// Removes a namespace at the top of the stack.
    ///
    /// Fails if the stack is empty.
    #[inline]
    pub fn pop(&mut self) -> Namespace {
        self.0.pop().unwrap()
    }

    /// Returns a namespace at the top of the stack, leaving the stack intact.
    ///
    /// Fails if the stack is empty.
    #[inline]
    pub fn peek<'a>(&'a mut self) -> &'a mut Namespace {
        self.0.last_mut().unwrap()
    }

    /// Puts a mapping into the topmost namespace in this stack.
    ///
    /// This method does not override a mapping in the topmost namespace if it is
    /// already present, however, it does not depend on other namespaces in the stack,
    /// so it is possible to put a mapping which is present in lower namespaces.
    ///
    /// Returns a boolean flag indicating whether the topmost namespace
    /// already contained the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
    /// was already present in the namespace.
    #[inline]
    pub fn put(&mut self, prefix: Option<String>, uri: String) -> bool {
        self.0.last_mut().unwrap().put(prefix, uri)
    }

    /// Performs a search for the given prefix in the whole stack.
    ///
    /// This method walks the stack from top to bottom, querying each namespace
    /// in order for the given prefix. If none of the namespaces contains the prefix,
    /// `None` is returned.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace)
    #[inline]
    pub fn get<'a>(&'a self, prefix: &Option<String>) -> Option<&'a str> {
        for ns in self.0.iter().rev() {
            match ns.get(prefix) {
                None => {},
                r => return r,
            }
        }
        None
    }

    /// Combines this stack of namespaces into a single namespace.
    ///
    /// Namespaces are combined in left-to-right order, that is, rightmost namespace
    /// elements take priority over leftmost ones.
    pub fn squash(&self) -> Namespace {
        let mut result = HashMap::new();
        for ns in self.0.iter() {
            result.extend(ns.0.iter().cloned_pairwise());
        }
        Namespace(result)
    }
}

/// An iterator over mappings from prefixes to URIs in a namespace stack.
pub struct NamespaceStackMappings<'a> {
    namespaces: Rev<Items<'a, Namespace>>,
    current_namespace: Option<NamespaceMappings<'a>>,
    used_keys: HashSet<Option<&'a str>>
}

impl<'a> NamespaceStackMappings<'a> {
    fn to_next_namespace(&mut self) -> bool {
        self.current_namespace = self.namespaces.next().map(|ns| ns.uri_mappings());
        self.current_namespace.is_some()
    }
}

impl<'a> Iterator<(Option<&'a str>, &'a str)> for NamespaceStackMappings<'a> {
    fn next(&mut self) -> Option<(Option<&'a str>, &'a str)> {
        // If there is no current namespace and no next namespace, we're finished
        if self.current_namespace.is_none() && !self.to_next_namespace() {
            return None;
        }
        let next_item = self.current_namespace.as_mut().unwrap().next();

        match next_item {
            // There is an element in the current namespace
            Some((k, v)) => if self.used_keys.contains(&k) {
                // If the current key is used, go to the next one
                self.next()
            } else {
                // Otherwise insert the current key to the set of used keys and
                // return the mapping
                self.used_keys.insert(k);
                Some((k, v))
            },
            // Current namespace is exhausted
            None => if self.to_next_namespace() {
                // If there is next namespace, continue from it
                self.next()
            } else {
                // No next namespace, exiting
                None
            }
        }
    }
}

impl<'a> NamespaceIterable<'a, NamespaceStackMappings<'a>> for NamespaceStack {
    fn uri_mappings(&'a self) -> NamespaceStackMappings<'a> {
        NamespaceStackMappings {
            namespaces: self.0.iter().rev(),
            current_namespace: None,
            used_keys: HashSet::new()
        }
    }
}
<commit_msg>Replaced `core::slice::Items` with core::slice::Iter`.<commit_after>use std::iter::Rev;
use core::slice::Iter;
use std::collections::hash_map::{HashMap, Entries, Entry};
use std::collections::HashSet;

use util::{OptionBorrowExt, IntoOwned, IteratorClonedPairwiseExt};

pub const NS_XMLNS_PREFIX: &'static str = "xmlns";
pub const NS_XMLNS_URI: &'static str    = "http://www.w3.org/2000/xmlns/";
pub const NS_XML_PREFIX: &'static str   = "xml";
pub const NS_XML_URI: &'static str      = "http://www.w3.org/XML/1998/namespace";
pub const NS_EMPTY_URI: &'static str    = "";

/// Denotes something which contains namespace URI mappings.
///
/// A URI mapping is a pair of type `(Option<&str>, &str)`, where the first item
/// is a namespace prefix (`None` meaning default prefix) and the second item
/// is a URI mapped to this prefix.
pub trait NamespaceIterable<'a, I: Iterator<(Option<&'a str>, &'a str)>> {
    fn uri_mappings(&'a self) -> I;
}

/// Namespace is a map from prefixes to namespace URIs.
///
/// `None` prefix means no prefix (i.e. default namespace).
#[deriving(PartialEq, Clone)]
pub struct Namespace(pub HashMap<Option<String>, String>);

impl Namespace {
    /// Returns an empty namespace.
    #[inline]
    pub fn empty() -> Namespace { Namespace(HashMap::with_capacity(3)) }

    /// Checks whether this namespace is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Checks whether this namespace is essentially empty, that is, it does not contain
    /// anything but the default mappings.
    pub fn is_essentially_empty(&self) -> bool {
        // a shortcut for a namespace which is definitely not empty
        if self.0.len() > 3 { return false; }

        self.0.iter().all(|(k, v)| match (k.borrow_internals(), v[]) {
            (None,                  NS_EMPTY_URI) => true,
            (Some(NS_XMLNS_PREFIX), NS_XMLNS_URI) => true,
            (Some(NS_XML_PREFIX),   NS_XML_URI)   => true,
            _ => false
        })
    }

    /// Puts a mapping into this namespace.
    ///
    /// This method does not override an already existing mapping.
    ///
    /// Returns a boolean flag indicating whether the map already contained
    /// the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
    /// was already present in the namespace.
    pub fn put<S1, S2>(&mut self, prefix: Option<S1>, uri: S2) -> bool
            where S1: IntoOwned<String>, S2: IntoOwned<String> {
        match self.0.entry(prefix.map(|v| v.into_owned())) {
            Entry::Occupied(_) => false,
            Entry::Vacant(ve) => {
                ve.set(uri.into_owned());
                true
            }
        }
    }

    /// Puts a mapping into this namespace forcefully.
    ///
    /// This method, as opposed to `put()`, does replace an already existing mapping.
    ///
    /// Returns previous URI which was assigned to the given prefix, if it is present.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `Some(uri)` with `uri` being a previous URI assigned to the `prefix`, or
    /// `None` if such prefix was not present in the namespace before.
    pub fn force_put<S1, S2>(&mut self, prefix: Option<S1>, uri: S2) -> Option<String>
            where S1: IntoOwned<String>, S2: IntoOwned<String> {
        self.0.insert(prefix.map(|v| v.into_owned()), uri.into_owned())
    }

    /// Queries the namespace for the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace).
    ///
    /// # Return value
    /// Namespace URI corresponding to the given prefix, if it is present.
    pub fn get<'a>(&'a self, prefix: &Option<String>) -> Option<&'a str> {
        self.0.get(prefix).map(|s| &**s)
    }
}

/// An iterator over mappings from prefixes to URIs in a namespace.
///
/// This is a separate structure because `map()` operation on iterators uses an unboxed
/// closure type which can't be named.
pub struct NamespaceMappings<'a> {
    entries: Entries<'a, Option<String>, String>
}

impl<'a> Iterator<(Option<&'a str>, &'a str)> for NamespaceMappings<'a> {
    fn next(&mut self) -> Option<(Option<&'a str>, &'a str)> {
        self.entries.next().map(|(prefix, uri)| {
            (prefix.as_ref().map(|p| p.as_slice()), uri.as_slice())
        })
    }
}

impl<'a> NamespaceIterable<'a, NamespaceMappings<'a>> for Namespace {
    fn uri_mappings(&'a self) -> NamespaceMappings<'a> {
        NamespaceMappings { entries: self.0.iter() }
    }
}

/// Namespace stack is a sequence of namespaces.
///
/// Namespace stack is used to represent cumulative namespace consisting of
/// combined namespaces from nested elements.
#[deriving(Clone, PartialEq)]
pub struct NamespaceStack(pub Vec<Namespace>);

impl NamespaceStack {
    /// Returns an empty namespace stack.
    #[inline]
    pub fn empty() -> NamespaceStack { NamespaceStack(Vec::with_capacity(2)) }

    /// Returns a namespace stack with default items in it.
    ///
    /// Default items are the following:
    ///
    /// * `xml` → `http://www.w3.org/XML/1998/namespace`;
    /// * `xmlns` → `http://www.w3.org/2000/xmlns/`.
    #[inline]
    pub fn default() -> NamespaceStack {
        let mut nst = NamespaceStack::empty();
        nst.push_empty();
        // xml namespace
        nst.put(Some(NS_XML_PREFIX.to_string()), NS_XML_URI.to_string());
        // xmlns namespace
        nst.put(Some(NS_XMLNS_PREFIX.to_string()), NS_XMLNS_URI.to_string());
        // empty namespace
        nst.put(None, NS_EMPTY_URI.to_string());
        nst
    }

    /// Adds an empty namespace to the top of this stack.
    #[inline]
    pub fn push_empty(&mut self) {
        self.0.push(Namespace::empty());
    }

    /// Removes a namespace at the top of the stack.
    ///
    /// Fails if the stack is empty.
    #[inline]
    pub fn pop(&mut self) -> Namespace {
        self.0.pop().unwrap()
    }

    /// Returns a namespace at the top of the stack, leaving the stack intact.
    ///
    /// Fails if the stack is empty.
    #[inline]
    pub fn peek<'a>(&'a mut self) -> &'a mut Namespace {
        self.0.last_mut().unwrap()
    }

    /// Puts a mapping into the topmost namespace in this stack.
    ///
    /// This method does not override a mapping in the topmost namespace if it is
    /// already present, however, it does not depend on other namespaces in the stack,
    /// so it is possible to put a mapping which is present in lower namespaces.
    ///
    /// Returns a boolean flag indicating whether the topmost namespace
    /// already contained the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
    /// was already present in the namespace.
    #[inline]
    pub fn put(&mut self, prefix: Option<String>, uri: String) -> bool {
        self.0.last_mut().unwrap().put(prefix, uri)
    }

    /// Performs a search for the given prefix in the whole stack.
    ///
    /// This method walks the stack from top to bottom, querying each namespace
    /// in order for the given prefix. If none of the namespaces contains the prefix,
    /// `None` is returned.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace)
    #[inline]
    pub fn get<'a>(&'a self, prefix: &Option<String>) -> Option<&'a str> {
        for ns in self.0.iter().rev() {
            match ns.get(prefix) {
                None => {},
                r => return r,
            }
        }
        None
    }

    /// Combines this stack of namespaces into a single namespace.
    ///
    /// Namespaces are combined in left-to-right order, that is, rightmost namespace
    /// elements take priority over leftmost ones.
    pub fn squash(&self) -> Namespace {
        let mut result = HashMap::new();
        for ns in self.0.iter() {
            result.extend(ns.0.iter().cloned_pairwise());
        }
        Namespace(result)
    }
}

/// An iterator over mappings from prefixes to URIs in a namespace stack.
pub struct NamespaceStackMappings<'a> {
    namespaces: Rev<Iter<'a, Namespace>>,
    current_namespace: Option<NamespaceMappings<'a>>,
    used_keys: HashSet<Option<&'a str>>
}

impl<'a> NamespaceStackMappings<'a> {
    fn to_next_namespace(&mut self) -> bool {
        self.current_namespace = self.namespaces.next().map(|ns| ns.uri_mappings());
        self.current_namespace.is_some()
    }
}

impl<'a> Iterator<(Option<&'a str>, &'a str)> for NamespaceStackMappings<'a> {
    fn next(&mut self) -> Option<(Option<&'a str>, &'a str)> {
        // If there is no current namespace and no next namespace, we're finished
        if self.current_namespace.is_none() && !self.to_next_namespace() {
            return None;
        }
        let next_item = self.current_namespace.as_mut().unwrap().next();

        match next_item {
            // There is an element in the current namespace
            Some((k, v)) => if self.used_keys.contains(&k) {
                // If the current key is used, go to the next one
                self.next()
            } else {
                // Otherwise insert the current key to the set of used keys and
                // return the mapping
                self.used_keys.insert(k);
                Some((k, v))
            },
            // Current namespace is exhausted
            None => if self.to_next_namespace() {
                // If there is next namespace, continue from it
                self.next()
            } else {
                // No next namespace, exiting
                None
            }
        }
    }
}

impl<'a> NamespaceIterable<'a, NamespaceStackMappings<'a>> for NamespaceStack {
    fn uri_mappings(&'a self) -> NamespaceStackMappings<'a> {
        NamespaceStackMappings {
            namespaces: self.0.iter().rev(),
            current_namespace: None,
            used_keys: HashSet::new()
        }
    }
}
<|endoftext|>


<commit_before>//! Sprite rendering

use super::{Ppu, Rgb};

use arrayvec::ArrayVec;
use std::mem::replace;

/// Render state stored inside the `Ppu`. We use this to cache the visible sprites for each
/// scanline, just like the real PPU would.
#[derive(Default)]
pub struct SpriteRenderState {
    /// Contains up to 34 `SpriteTile`s that are visible on the current scanline
    visible_sprite_tiles: Vec<SpriteTile>,
}

/// Unpacked OAM entry for internal use.
struct OamEntry {
    /// First tile (0-255), needs to take name table selection bit into account
    tile: u8,
    /// Sprite's name table (0 or 1).
    name_table: u8,
    /// 9 bits, considered signed (-256 - 255)
    x: i16,
    y: u8,
    /// 0-3
    priority: u8,
    /// 0-7. The first palette entry is `128+ppp*16`.
    palette: u8,
    #[allow(dead_code)] // FIXME
    hflip: bool,
    #[allow(dead_code)]
    vflip: bool,
    size_toggle: bool,
}

/// Informations about a single tile of a sprite, needed for drawing.
struct SpriteTile {
    /// Address of character data for this tile
    chr_addr: u16,
    /// X position of the tile on the screen.
    x: i16,
    /// Y position of the scanline inside the tile (0-7)
    /// FIXME Can we just store the pixel row that's on the scanline? (for each priority)
    y_off: u8,
    /// Priority of the sprite (0-3)
    priority: u8,
    /// Palette of the sprite (0-7)
    palette: u8,

    // FIXME hflip/vflip
}

impl Ppu {
    /// Returns the OAM entry of the given sprite. Always returns a valid entry if `index` is valid
    /// (0...127), panics otherwise.
    fn get_oam_entry(&self, index: u8) -> OamEntry {
        debug_assert!(index <= 127, "attempted to access sprite #{}", index);

        // OAM entry start address (low table)
        let start = index as u16 * 4;
        let mut x = self.oam[start] as u16;

        // vhoopppN
        let byte4 = self.oam[start + 3];
        let vflip = byte4 & 0x80 != 0;
        let hflip = byte4 & 0x40 != 0;
        let priority = (byte4 & 0x30) >> 4;
        let palette = (byte4 & 0x0e) >> 1;

        // Read the second table. Each byte contains information of 4 sprites (2 bits per sprite):
        // Bits 1/3/5/6 is the size-toggle bit, bits 0/2/4/6 is the MSb of the x coord
        let byte = self.oam[512 + index as u16 / 4];
        let index_in_byte = index & 0b11;
        let msb_mask = 1 << (index_in_byte * 2);
        let size_mask = 2 << (index_in_byte * 2);
        let size_toggle = byte & size_mask != 0;
        if byte & msb_mask != 0 {
            // MSb of `x` is set, so `x` is negative. Since `x` is a signed 9-bit value, we have to
            // sign-extend it to 16 bits by setting all bits starting from the MSb to 1.
            x = 0xff00 | x;
        }

        OamEntry {
            tile: self.oam[start + 2],
            name_table: byte4 & 1,
            x: x as i16,
            y: self.oam[start + 1],
            priority: priority,
            palette: palette,
            hflip: hflip,
            vflip: vflip,
            size_toggle: size_toggle,
        }
    }

    /// Collects visible sprites and sprite tiles for the current scanline.
    ///
    /// Called when rendering the first pixel on a scanline.
    pub fn collect_sprite_data_for_scanline(&mut self) {
        let first_sprite = if self.oamaddh & 0x80 == 0 {
            0
        } else {
            // Priority rotation enabled
            (self.oamaddl as u16 & 0xfe) >> 1
        };

        // Find the first 32 sprites on the current scanline
        // NB Priority is ignored for this step, it's only used for drawing, which isn't done here
        let mut visible_sprites = ArrayVec::<[_; 32]>::new();
        for i in first_sprite..first_sprite+128 {
            let entry = self.get_oam_entry((i & 0x7f) as u8);   // limit to 127
            if self.sprite_on_scanline(&entry) {
                if let Some(_) = visible_sprites.push(entry) {
                    // FIXME: Sprite overflow. Set bit 6 of $213e.
                    break
                }
            }
        }

        // "Starting with the last sprite in Range, load up to 34 8x8 tiles (from left-to-right,
        // after flipping). If there are more than 34 tiles in Range, set bit 7 of $213e. Only
        // those tiles with -8 < X < 256 are counted."
        // A few notes:
        // * Sprite tiles are always 8x8 pixels
        // * Sprites do not have tile maps like BGs do
        // * "left-to-right" refers to how tiles of sprites are loaded, not the sprite order
        // * Tiles are loaded iff they are on the current scanline (and have `-8 < X < 256`)
        // FIXME Is this ^^ correct?

        // FIXME Use `ArrayVec<[_; 34]>` when it works
        let mut visible_tiles = replace(&mut self.sprite_render_state.visible_sprite_tiles, Vec::new());
        visible_tiles.clear();

        // Word address of first sprite character table
        let name_base: u16 = (self.obsel as u16 & 0b111) << 13;
        let name_select: u16 = (self.obsel as u16 >> 3) & 0b11;

        // Start at the last sprite found
        'collect_tiles: for sprite in visible_sprites.iter().rev() {
            // How many tiles are there?
            let (sprite_w, _) = self.obj_size(sprite.size_toggle);
            let sprite_w_tiles = sprite_w / 8;
            // Offset into the sprite
            let sprite_y_off = self.scanline - sprite.y as u16;
            // Tile Y coordinate of the tile row we're interested in (tiles on the scanline)
            let y_tile = sprite_y_off / 8;
            // Y offset into the tile row
            let tile_y_off = (sprite_y_off % 8) as u8;

            // Calculate VRAM word address of first tile. Depends on base/name bits in `$2101`.
            let tile_start_word_addr =
                (name_base |
                ((sprite.tile as u16) << 4) |
                (sprite.name_table as u16 * ((name_select + 1) << 12))) & 0x7fff;
            let tile_start_addr = tile_start_word_addr * 2;

            // The character data for the first tile is stored at `tile_start_addr`, in the same
            // format as BG character data (bitplanes, etc.). Keep in mind that sprites do not have
            // tilemaps.
            // One 8x8 tile is 32 Bytes large (4 bits per pixel).
            // Tiles in a single (8 pixel high) row of the sprite are stored sequentially: Tile
            // coord (1,0) is stored directly behind (0,0), which is stored at `tile_start_addr`.
            // Rows of tiles, however, are always stored 512 Bytes (or 16 tiles/128 pixels) apart:
            // If tile (0,0) is at address $0000, tile (0,1) is at $0200. This is independent of
            // the sprite size, which means that there are "holes" in the sprite character data,
            // which are used to store the data of other sprites.

            // Start address of the row of tiles on the scanline
            let y_row_start_addr = tile_start_addr.wrapping_add(512 * y_tile);

            // FIXME "Only those tiles with -8 < X < 256 are counted."
            // Add all tiles in this row to our tile list (left to right)
            for i in 0..sprite_w_tiles as i16 {
                if visible_tiles.len() < 34 {
                    visible_tiles.push(SpriteTile {
                        chr_addr: y_row_start_addr + 32 * i as u16,
                        x: sprite.x + 8 * i,
                        y_off: tile_y_off,
                        priority: sprite.priority,
                        palette: sprite.palette,
                    });
                } else {
                    // FIXME Set sprite tile overflow flag
                    break 'collect_tiles
                }
            }
        }

        self.sprite_render_state.visible_sprite_tiles = visible_tiles;
    }

    /// Determines if the given sprite has any tiles on the current scanline
    fn sprite_on_scanline(&self, sprite: &OamEntry) -> bool {
        let (w, h) = self.obj_size(sprite.size_toggle);
        let (w, h) = (w as i16, h as u16);

        // "If any OBJ is at X=256 (or X=-256, same difference), consider it as being at X=0 when
        // considering Range and Time."
        // X=256 can not occur, since X is a signed 9-bit value (range is -256 - 255)
        let x = if sprite.x == -256 { 0 } else { sprite.x };
        let y = sprite.y as u16;

        // "Only those sprites with -size < X < 256 are considered in Range." (`size` is `w` here)
        // We don't check `X < 256`, since that cannot occur (X is a signed 9-bit integer)
        // A sprite moved past the right edge of the screen will wrap to `-256`, which is handled
        // by this check.
        if -w < x {
            if y <= self.scanline && y + h >= self.scanline {
                // Sprite is on scanline
                true
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Returns the current pixel on the sprite layer.
    ///
    /// Searches for a sprite tile overlapping with the current pixel and looks up its color.
    pub fn maybe_draw_sprite_pixel(&self, prio: u8) -> Option<Rgb> {
        if self.tm & 0x10 == 0 { return None }  // OBJ layer disabled

        for tile in &self.sprite_render_state.visible_sprite_tiles {
            if tile.priority == prio {
                // The tile must be on this scanline, we just have to check X
                if tile.x <= self.x as i16 && tile.x + 8 > self.x as i16 {
                    let x_offset = self.x as i16 - tile.x;
                    debug_assert!(0 <= x_offset && x_offset <= 7, "x_offset = {}", x_offset);
                    let rel_color = self.read_chr_entry(4,  // 16 colors
                                                        tile.chr_addr,
                                                        8,  // 8x8 tiles
                                                        (x_offset as u8, tile.y_off));
                    debug_assert!(rel_color < 16, "rel_color = {} (but is 4-bit!)", rel_color);

                    // color index 0 is always transparent
                    if rel_color == 0 { return None }

                    let abs_color = 128 + tile.palette * 16 + rel_color;
                    // FIXME Color math
                    let rgb = self.lookup_color(abs_color);
                    return Some(rgb)
                }
            }
        }

        None
    }
}
<commit_msg>Don't bail out when a sprite pixel is transparent<commit_after>//! Sprite rendering

use super::{Ppu, Rgb};

use arrayvec::ArrayVec;
use std::mem::replace;

/// Render state stored inside the `Ppu`. We use this to cache the visible sprites for each
/// scanline, just like the real PPU would.
#[derive(Default)]
pub struct SpriteRenderState {
    /// Contains up to 34 `SpriteTile`s that are visible on the current scanline
    visible_sprite_tiles: Vec<SpriteTile>,
}

/// Unpacked OAM entry for internal use.
struct OamEntry {
    /// First tile (0-255), needs to take name table selection bit into account
    tile: u8,
    /// Sprite's name table (0 or 1).
    name_table: u8,
    /// 9 bits, considered signed (-256 - 255)
    x: i16,
    y: u8,
    /// 0-3
    priority: u8,
    /// 0-7. The first palette entry is `128+ppp*16`.
    palette: u8,
    #[allow(dead_code)] // FIXME
    hflip: bool,
    #[allow(dead_code)]
    vflip: bool,
    size_toggle: bool,
}

/// Informations about a single tile of a sprite, needed for drawing.
struct SpriteTile {
    /// Address of character data for this tile
    chr_addr: u16,
    /// X position of the tile on the screen.
    x: i16,
    /// Y position of the scanline inside the tile (0-7)
    /// FIXME Can we just store the pixel row that's on the scanline? (for each priority)
    y_off: u8,
    /// Priority of the sprite (0-3)
    priority: u8,
    /// Palette of the sprite (0-7)
    palette: u8,

    // FIXME hflip/vflip
}

impl Ppu {
    /// Returns the OAM entry of the given sprite. Always returns a valid entry if `index` is valid
    /// (0...127), panics otherwise.
    fn get_oam_entry(&self, index: u8) -> OamEntry {
        debug_assert!(index <= 127, "attempted to access sprite #{}", index);

        // OAM entry start address (low table)
        let start = index as u16 * 4;
        let mut x = self.oam[start] as u16;

        // vhoopppN
        let byte4 = self.oam[start + 3];
        let vflip = byte4 & 0x80 != 0;
        let hflip = byte4 & 0x40 != 0;
        let priority = (byte4 & 0x30) >> 4;
        let palette = (byte4 & 0x0e) >> 1;

        // Read the second table. Each byte contains information of 4 sprites (2 bits per sprite):
        // Bits 1/3/5/6 is the size-toggle bit, bits 0/2/4/6 is the MSb of the x coord
        let byte = self.oam[512 + index as u16 / 4];
        let index_in_byte = index & 0b11;
        let msb_mask = 1 << (index_in_byte * 2);
        let size_mask = 2 << (index_in_byte * 2);
        let size_toggle = byte & size_mask != 0;
        if byte & msb_mask != 0 {
            // MSb of `x` is set, so `x` is negative. Since `x` is a signed 9-bit value, we have to
            // sign-extend it to 16 bits by setting all bits starting from the MSb to 1.
            x = 0xff00 | x;
        }

        OamEntry {
            tile: self.oam[start + 2],
            name_table: byte4 & 1,
            x: x as i16,
            y: self.oam[start + 1],
            priority: priority,
            palette: palette,
            hflip: hflip,
            vflip: vflip,
            size_toggle: size_toggle,
        }
    }

    /// Collects visible sprites and sprite tiles for the current scanline.
    ///
    /// Called when rendering the first pixel on a scanline.
    pub fn collect_sprite_data_for_scanline(&mut self) {
        let first_sprite = if self.oamaddh & 0x80 == 0 {
            0
        } else {
            // Priority rotation enabled
            (self.oamaddl as u16 & 0xfe) >> 1
        };

        // Find the first 32 sprites on the current scanline
        // NB Priority is ignored for this step, it's only used for drawing, which isn't done here
        let mut visible_sprites = ArrayVec::<[_; 32]>::new();
        for i in first_sprite..first_sprite+128 {
            let entry = self.get_oam_entry((i & 0x7f) as u8);   // limit to 127
            if self.sprite_on_scanline(&entry) {
                if let Some(_) = visible_sprites.push(entry) {
                    // FIXME: Sprite overflow. Set bit 6 of $213e.
                    break
                }
            }
        }

        // "Starting with the last sprite in Range, load up to 34 8x8 tiles (from left-to-right,
        // after flipping). If there are more than 34 tiles in Range, set bit 7 of $213e. Only
        // those tiles with -8 < X < 256 are counted."
        // A few notes:
        // * Sprite tiles are always 8x8 pixels
        // * Sprites do not have tile maps like BGs do
        // * "left-to-right" refers to how tiles of sprites are loaded, not the sprite order
        // * Tiles are loaded iff they are on the current scanline (and have `-8 < X < 256`)
        // FIXME Is this ^^ correct?

        // FIXME Use `ArrayVec<[_; 34]>` when it works
        let mut visible_tiles = replace(&mut self.sprite_render_state.visible_sprite_tiles, Vec::new());
        visible_tiles.clear();

        // Word address of first sprite character table
        let name_base: u16 = (self.obsel as u16 & 0b111) << 13;
        let name_select: u16 = (self.obsel as u16 >> 3) & 0b11;

        // Start at the last sprite found
        'collect_tiles: for sprite in visible_sprites.iter().rev() {
            // How many tiles are there?
            let (sprite_w, _) = self.obj_size(sprite.size_toggle);
            let sprite_w_tiles = sprite_w / 8;
            // Offset into the sprite
            let sprite_y_off = self.scanline - sprite.y as u16;
            // Tile Y coordinate of the tile row we're interested in (tiles on the scanline)
            let y_tile = sprite_y_off / 8;
            // Y offset into the tile row
            let tile_y_off = (sprite_y_off % 8) as u8;

            // Calculate VRAM word address of first tile. Depends on base/name bits in `$2101`.
            let tile_start_word_addr =
                (name_base |
                ((sprite.tile as u16) << 4) |
                (sprite.name_table as u16 * ((name_select + 1) << 12))) & 0x7fff;
            let tile_start_addr = tile_start_word_addr * 2;

            // The character data for the first tile is stored at `tile_start_addr`, in the same
            // format as BG character data (bitplanes, etc.). Keep in mind that sprites do not have
            // tilemaps.
            // One 8x8 tile is 32 Bytes large (4 bits per pixel).
            // Tiles in a single (8 pixel high) row of the sprite are stored sequentially: Tile
            // coord (1,0) is stored directly behind (0,0), which is stored at `tile_start_addr`.
            // Rows of tiles, however, are always stored 512 Bytes (or 16 tiles/128 pixels) apart:
            // If tile (0,0) is at address $0000, tile (0,1) is at $0200. This is independent of
            // the sprite size, which means that there are "holes" in the sprite character data,
            // which are used to store the data of other sprites.

            // Start address of the row of tiles on the scanline
            let y_row_start_addr = tile_start_addr.wrapping_add(512 * y_tile);

            // FIXME "Only those tiles with -8 < X < 256 are counted."
            // Add all tiles in this row to our tile list (left to right)
            for i in 0..sprite_w_tiles as i16 {
                if visible_tiles.len() < 34 {
                    visible_tiles.push(SpriteTile {
                        chr_addr: y_row_start_addr + 32 * i as u16,
                        x: sprite.x + 8 * i,
                        y_off: tile_y_off,
                        priority: sprite.priority,
                        palette: sprite.palette,
                    });
                } else {
                    // FIXME Set sprite tile overflow flag
                    break 'collect_tiles
                }
            }
        }

        self.sprite_render_state.visible_sprite_tiles = visible_tiles;
    }

    /// Determines if the given sprite has any tiles on the current scanline
    fn sprite_on_scanline(&self, sprite: &OamEntry) -> bool {
        let (w, h) = self.obj_size(sprite.size_toggle);
        let (w, h) = (w as i16, h as u16);

        // "If any OBJ is at X=256 (or X=-256, same difference), consider it as being at X=0 when
        // considering Range and Time."
        // X=256 can not occur, since X is a signed 9-bit value (range is -256 - 255)
        let x = if sprite.x == -256 { 0 } else { sprite.x };
        let y = sprite.y as u16;

        // "Only those sprites with -size < X < 256 are considered in Range." (`size` is `w` here)
        // We don't check `X < 256`, since that cannot occur (X is a signed 9-bit integer)
        // A sprite moved past the right edge of the screen will wrap to `-256`, which is handled
        // by this check.
        if -w < x {
            if y <= self.scanline && y + h >= self.scanline {
                // Sprite is on scanline
                true
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Returns the current pixel on the sprite layer.
    ///
    /// Searches for a sprite tile overlapping with the current pixel and looks up its color.
    pub fn maybe_draw_sprite_pixel(&self, prio: u8) -> Option<Rgb> {
        if self.tm & 0x10 == 0 { return None }  // OBJ layer disabled

        for tile in &self.sprite_render_state.visible_sprite_tiles {
            if tile.priority == prio {
                // The tile must be on this scanline, we just have to check X
                if tile.x <= self.x as i16 && tile.x + 8 > self.x as i16 {
                    let x_offset = self.x as i16 - tile.x;
                    debug_assert!(0 <= x_offset && x_offset <= 7, "x_offset = {}", x_offset);
                    let rel_color = self.read_chr_entry(4,  // 16 colors
                                                        tile.chr_addr,
                                                        8,  // 8x8 tiles
                                                        (x_offset as u8, tile.y_off));
                    debug_assert!(rel_color < 16, "rel_color = {} (but is 4-bit!)", rel_color);

                    // color index 0 is always transparent
                    if rel_color == 0 { continue }

                    let abs_color = 128 + tile.palette * 16 + rel_color;
                    // FIXME Color math
                    let rgb = self.lookup_color(abs_color);
                    return Some(rgb)
                }
            }
        }

        None
    }
}
<|endoftext|>


<commit_before>pub use self::os::{netent};
pub use self::os::{hostent};
pub use self::os::{servent};
pub use self::os::{protoent};
pub use self::os::{addrinfo};
pub use self::os::{IPPORT_RESERVED};
pub use self::os::{AI_PASSIVE};
pub use self::os::{AI_CANONNAME};
pub use self::os::{AI_NUMERICHOST};
pub use self::os::{AI_NUMERICSERV};
pub use self::os::{AI_V4MAPPED};
pub use self::os::{AI_ALL};
pub use self::os::{AI_ADDRCONFIG};
pub use self::os::{NI_NOFQDN};
pub use self::os::{NI_NUMERICHOST};
pub use self::os::{NI_NAMEREQD};
pub use self::os::{NI_NUMERICSERV};
pub use self::os::{NI_DGRAM};
pub use self::os::{EAI_AGAIN};
pub use self::os::{EAI_BADFLAGS};
pub use self::os::{EAI_FAIL};
pub use self::os::{EAI_FAMILY};
pub use self::os::{EAI_MEMORY};
pub use self::os::{EAI_NONAME};
pub use self::os::{EAI_SERVICE};
pub use self::os::{EAI_SOCKTYPE};
pub use self::os::{EAI_SYSTEM};
pub use self::os::{EAI_OVERFLOW};

#[cfg(target_os = "linux")]
#[path = "linux/mod.rs"]
mod os;

pub fn endhostent() {
    extern { fn endhostent(); }
    unsafe { endhostent() }
}

pub fn endnetent() {
    extern { fn endnetent(); }
    unsafe { endnetent() }
}

pub fn endprotoent() {
    extern { fn endprotoent(); }
    unsafe { endprotoent() }
}

pub fn endservent() {
    extern { fn endservent(); }
    unsafe { endservent() }
}

pub fn freeaddrinfo(ai: *mut addrinfo) {
    extern { fn freeaddrinfo(ai: *mut addrinfo); }
    unsafe { freeaddrinfo(ai) }
}

pub fn gai_strerror(ecode: ::int_t) -> *const ::char_t {
    extern { fn gai_strerror(ecode: ::int_t) -> *const ::char_t; }
    unsafe { gai_strerror(ecode) }
}

pub fn getaddrinfo<T: ::NTStr, U: ::NTStr>
                   (name: &T, service: &U, req: &addrinfo, pai: &mut *mut addrinfo) -> ::int_t {
    extern { fn getaddrinfo(name: *const ::char_t, service: *const ::char_t,
                            req: *const addrinfo, pai: *mut *mut addrinfo) -> ::int_t; }
    unsafe { getaddrinfo(name.as_ptr(), service.as_ptr(), req as *const _,
                         pai as *mut _) }
}

pub fn getnameinfo(sa: &[u8], host: Option<&mut [u8]>, serv: Option<&mut [u8]>,
                   flags: ::int_t) -> ::int_t {
    extern { fn getnameinfo(sa: *const ::sys::socket::sockaddr, salen: ::sys::socket::socklen_t,
                            host: *mut ::char_t, hostlen: ::sys::socket::socklen_t,
                            serv: *mut ::char_t, servlen: ::sys::socket::socklen_t,
                            flags: ::int_t) -> ::int_t; }
    let host_len = host.as_ref().map(|v| v.len() as ::sys::socket::socklen_t).unwrap_or(0);
    let serv_len = serv.as_ref().map(|v| v.len() as ::sys::socket::socklen_t).unwrap_or(0);
    let host_ptr = host.map(|v| v.as_mut_ptr() as *mut _).unwrap_or(0 as *mut _);
    let serv_ptr = serv.map(|v| v.as_mut_ptr() as *mut _).unwrap_or(0 as *mut _);
    if host_len + serv_len == 0 {
        return EAI_OVERFLOW;
    }
    unsafe { getnameinfo(sa.as_ptr() as *const _, sa.len() as ::sys::socket::socklen_t,
                         host_ptr, host_len, serv_ptr, serv_len, flags) }
}

pub fn getnetbyaddr(net: u32, ty: ::int_t) -> &'static mut netent {
    extern { fn getnetbyaddr(net: u32, ty: ::int_t) -> *mut netent; }
    unsafe { ::std::mem::transmute(getnetbyaddr(net, ty)) }
}

pub fn getnetbyname<T: ::NTStr>(name: &T) -> &'static mut netent {
    extern { fn getnetbyname(name: *const ::char_t) -> *mut netent; }
    unsafe { ::std::mem::transmute(getnetbyname(name.as_ptr())) }
}

pub fn getprotobyname<T: ::NTStr>(name: &T) -> &'static mut protoent {
    extern { fn getprotobyname(name: *const ::char_t) -> *mut protoent; }
    unsafe { ::std::mem::transmute(getprotobyname(name.as_ptr())) }
}

pub fn getprotobynumber(proto: ::int_t) -> &'static mut protoent {
    extern { fn getprotobynumber(proto: ::int_t) -> *mut protoent; }
    unsafe { ::std::mem::transmute(getprotobynumber(proto)) }
}

pub fn getservbyname<T: ::NTStr, U: ::NTStr>(name: &T,
                                             proto: &U) -> &'static mut servent {
    extern { fn getservbyname(name: *const ::char_t,
                              proto: *const ::char_t) -> *mut servent; }
    unsafe { ::std::mem::transmute(getservbyname(name.as_ptr(), proto.as_ptr())) }
}

extern "C" {
    pub fn gethostent() -> *mut hostent;
    pub fn getnetent() -> *mut netent;
    pub fn getprotoent() -> *mut protoent;
    pub fn getservent() -> *mut servent;
    pub fn sethostent(stay_open: ::int_t);
    pub fn setnetent(stay_open: ::int_t);
    pub fn setprotoent(stay_open: ::int_t);
    pub fn setservent(stay_open: ::int_t);
}
<commit_msg>netdb.h<commit_after>pub use self::os::{netent};
pub use self::os::{hostent};
pub use self::os::{servent};
pub use self::os::{protoent};
pub use self::os::{addrinfo};
pub use self::os::{IPPORT_RESERVED};
pub use self::os::{AI_PASSIVE};
pub use self::os::{AI_CANONNAME};
pub use self::os::{AI_NUMERICHOST};
pub use self::os::{AI_NUMERICSERV};
pub use self::os::{AI_V4MAPPED};
pub use self::os::{AI_ALL};
pub use self::os::{AI_ADDRCONFIG};
pub use self::os::{NI_NOFQDN};
pub use self::os::{NI_NUMERICHOST};
pub use self::os::{NI_NAMEREQD};
pub use self::os::{NI_NUMERICSERV};
pub use self::os::{NI_DGRAM};
pub use self::os::{EAI_AGAIN};
pub use self::os::{EAI_BADFLAGS};
pub use self::os::{EAI_FAIL};
pub use self::os::{EAI_FAMILY};
pub use self::os::{EAI_MEMORY};
pub use self::os::{EAI_NONAME};
pub use self::os::{EAI_SERVICE};
pub use self::os::{EAI_SOCKTYPE};
pub use self::os::{EAI_SYSTEM};
pub use self::os::{EAI_OVERFLOW};

use std::mem::{transmute};
use {NTStr, int_t, char_t};
use sys::socket::{sockaddr, socklen_t};

#[cfg(target_os = "linux")]
#[path = "linux/mod.rs"]
mod os;

pub fn endhostent() {
    extern { fn endhostent(); }
    unsafe { endhostent() }
}

pub fn endnetent() {
    extern { fn endnetent(); }
    unsafe { endnetent() }
}

pub fn endprotoent() {
    extern { fn endprotoent(); }
    unsafe { endprotoent() }
}

pub fn endservent() {
    extern { fn endservent(); }
    unsafe { endservent() }
}

pub fn freeaddrinfo(ai: *mut addrinfo) {
    extern { fn freeaddrinfo(ai: *mut addrinfo); }
    unsafe { freeaddrinfo(ai) }
}

pub fn gai_strerror(ecode: int_t) -> *const char_t {
    extern { fn gai_strerror(ecode: int_t) -> *const char_t; }
    unsafe { gai_strerror(ecode) }
}

pub fn getaddrinfo<T: NTStr, U: NTStr>
                   (name: &T, service: &U, req: &addrinfo, pai: &mut *mut addrinfo) -> int_t {
    extern { fn getaddrinfo(name: *const char_t, service: *const char_t,
                            req: *const addrinfo, pai: *mut *mut addrinfo) -> int_t; }
    unsafe { getaddrinfo(name.as_ptr(), service.as_ptr(), req as *const _,
                         pai as *mut _) }
}

pub fn getnameinfo(sa: &[u8], host: Option<&mut [u8]>, serv: Option<&mut [u8]>,
                   flags: int_t) -> int_t {
    extern { fn getnameinfo(sa: *const sockaddr, salen: socklen_t,
                            host: *mut char_t, hostlen: socklen_t,
                            serv: *mut char_t, servlen: socklen_t,
                            flags: int_t) -> int_t; }
    let host_len = host.as_ref().map(|v| v.len() as socklen_t).unwrap_or(0);
    let serv_len = serv.as_ref().map(|v| v.len() as socklen_t).unwrap_or(0);
    let host_ptr = host.map(|v| v.as_mut_ptr() as *mut _).unwrap_or(0 as *mut _);
    let serv_ptr = serv.map(|v| v.as_mut_ptr() as *mut _).unwrap_or(0 as *mut _);
    if host_len + serv_len == 0 {
        return EAI_OVERFLOW;
    }
    unsafe { getnameinfo(sa.as_ptr() as *const _, sa.len() as socklen_t,
                         host_ptr, host_len, serv_ptr, serv_len, flags) }
}

pub fn getnetbyaddr(net: u32, ty: int_t) -> &'static mut netent {
    extern { fn getnetbyaddr(net: u32, ty: int_t) -> *mut netent; }
    unsafe { transmute(getnetbyaddr(net, ty)) }
}

pub fn getnetbyname<T: NTStr>(name: &T) -> &'static mut netent {
    extern { fn getnetbyname(name: *const char_t) -> *mut netent; }
    unsafe { transmute(getnetbyname(name.as_ptr())) }
}

pub fn getprotobyname<T: NTStr>(name: &T) -> &'static mut protoent {
    extern { fn getprotobyname(name: *const char_t) -> *mut protoent; }
    unsafe { transmute(getprotobyname(name.as_ptr())) }
}

pub fn getprotobynumber(proto: int_t) -> &'static mut protoent {
    extern { fn getprotobynumber(proto: int_t) -> *mut protoent; }
    unsafe { transmute(getprotobynumber(proto)) }
}

pub fn getservbyname<T: NTStr, U: NTStr>(name: &T, proto: &U) -> &'static mut servent {
    extern { fn getservbyname(name: *const char_t,
                              proto: *const char_t) -> *mut servent; }
    unsafe { transmute(getservbyname(name.as_ptr(), proto.as_ptr())) }
}

extern "C" {
    pub fn gethostent() -> *mut hostent;
    pub fn getnetent() -> *mut netent;
    pub fn getprotoent() -> *mut protoent;
    pub fn getservent() -> *mut servent;
    pub fn sethostent(stay_open: int_t);
    pub fn setnetent(stay_open: int_t);
    pub fn setprotoent(stay_open: int_t);
    pub fn setservent(stay_open: int_t);
}
<|endoftext|>


<commit_before>// (c) 2016-2017 Joost Yervante Damad <joost@productize.be>

extern crate kicad_parse_gen as kicad;

extern crate difference;

#[test]
fn parse_and_compare() {
    let mut file_name = String::new();
    file_name.push_str(env!("CARGO_MANIFEST_DIR"));
    file_name.push_str("/tests/data/");
    file_name.push_str("usbser.kicad_pcb");

    let content = kicad::read_file(&file_name).unwrap();

    let layout = kicad::read_layout(&file_name).unwrap();
    let s = kicad::layout::layout_to_string(&layout, 0).unwrap();

    kicad::write_file("/tmp/dump.kicad_pcb", &s).unwrap();

    // very inefficient...
    let (n, d) = difference::diff(&content, &s, "\n");
    if n > 1 {
        difference::print_diff(&content, &s, "\n");
        println!("{:?}", d);
        assert_eq!(n, 1);
    }
}
<commit_msg>don't write temp file<commit_after>// (c) 2016-2017 Joost Yervante Damad <joost@productize.be>

extern crate kicad_parse_gen as kicad;

extern crate difference;

#[test]
fn parse_and_compare() {
    let mut file_name = String::new();
    file_name.push_str(env!("CARGO_MANIFEST_DIR"));
    file_name.push_str("/tests/data/");
    file_name.push_str("usbser.kicad_pcb");

    let content = kicad::read_file(&file_name).unwrap();

    let layout = kicad::read_layout(&file_name).unwrap();
    let s = kicad::layout::layout_to_string(&layout, 0).unwrap();

    // kicad::write_file("/tmp/dump.kicad_pcb", &s).unwrap();

    // very inefficient...
    let (n, d) = difference::diff(&content, &s, "\n");
    if n > 1 {
        difference::print_diff(&content, &s, "\n");
        println!("{:?}", d);
        assert_eq!(n, 1);
    }
}
<|endoftext|>


<commit_before>use std::mem;

pub struct Any {
    ptr: *mut (),
    drop: fn(*mut ()),
    fingerprint: Fingerprint,
}

// These functions are all unsafe. They are not exposed to the user. Declaring
// them as `unsafe fn` would not make the rest of erased-serde any safer or more
// readable.
impl Any {
    // This is unsafe -- caller must not hold on to the Any beyond the lifetime
    // of T.
    //
    // Example of bad code:
    //
    //    let s = "bad".to_owned();
    //    let a = Any::new(&s);
    //    drop(s);
    //
    // Now `a.view()` and `a.take()` return references to a dead String.
    pub(crate) fn new<T>(t: T) -> Self {
        let ptr = Box::into_raw(Box::new(t));
        Any {
            ptr: ptr as *mut (),
            drop: |ptr| drop(unsafe { Box::from_raw(ptr as *mut T) }),
            fingerprint: Fingerprint::of::<T>(),
        }
    }

    // This is unsafe -- caller is responsible that T is the correct type.
    pub(crate) fn view<T>(&mut self) -> &mut T {
        if self.fingerprint != Fingerprint::of::<T>() {
            panic!("invalid cast");
        }
        let ptr = self.ptr as *mut T;
        unsafe { &mut *ptr }
    }

    // This is unsafe -- caller is responsible that T is the correct type.
    pub(crate) fn take<T>(self) -> T {
        if self.fingerprint != Fingerprint::of::<T>() {
            panic!("invalid cast");
        }
        let ptr = self.ptr as *mut T;
        let box_t = unsafe { Box::from_raw(ptr) };
        mem::forget(self);
        *box_t
    }
}

impl Drop for Any {
    fn drop(&mut self) {
        (self.drop)(self.ptr);
    }
}

#[derive(Eq, PartialEq)]
struct Fingerprint {
    size: usize,
    align: usize,
    id: usize,
}

impl Fingerprint {
    fn of<T>() -> Fingerprint {
        Fingerprint {
            size: mem::size_of::<T>(),
            align: mem::align_of::<T>(),
            // This is not foolproof -- theoretically Rust or LLVM could
            // deduplicate some or all of these methods. But in practice it's
            // great and I am comfortable relying on this in debug mode to catch
            // bugs early.
            id: Fingerprint::of::<T> as usize,
        }
    }
}
<commit_msg>Basic test of fingerprint<commit_after>use std::mem;

pub struct Any {
    ptr: *mut (),
    drop: fn(*mut ()),
    fingerprint: Fingerprint,
}

// These functions are all unsafe. They are not exposed to the user. Declaring
// them as `unsafe fn` would not make the rest of erased-serde any safer or more
// readable.
impl Any {
    // This is unsafe -- caller must not hold on to the Any beyond the lifetime
    // of T.
    //
    // Example of bad code:
    //
    //    let s = "bad".to_owned();
    //    let a = Any::new(&s);
    //    drop(s);
    //
    // Now `a.view()` and `a.take()` return references to a dead String.
    pub(crate) fn new<T>(t: T) -> Self {
        let ptr = Box::into_raw(Box::new(t));
        Any {
            ptr: ptr as *mut (),
            drop: |ptr| drop(unsafe { Box::from_raw(ptr as *mut T) }),
            fingerprint: Fingerprint::of::<T>(),
        }
    }

    // This is unsafe -- caller is responsible that T is the correct type.
    pub(crate) fn view<T>(&mut self) -> &mut T {
        if self.fingerprint != Fingerprint::of::<T>() {
            panic!("invalid cast");
        }
        let ptr = self.ptr as *mut T;
        unsafe { &mut *ptr }
    }

    // This is unsafe -- caller is responsible that T is the correct type.
    pub(crate) fn take<T>(self) -> T {
        if self.fingerprint != Fingerprint::of::<T>() {
            panic!("invalid cast");
        }
        let ptr = self.ptr as *mut T;
        let box_t = unsafe { Box::from_raw(ptr) };
        mem::forget(self);
        *box_t
    }
}

impl Drop for Any {
    fn drop(&mut self) {
        (self.drop)(self.ptr);
    }
}

#[derive(Debug, Eq, PartialEq)]
struct Fingerprint {
    size: usize,
    align: usize,
    id: usize,
}

impl Fingerprint {
    fn of<T>() -> Fingerprint {
        Fingerprint {
            size: mem::size_of::<T>(),
            align: mem::align_of::<T>(),
            // This is not foolproof -- theoretically Rust or LLVM could
            // deduplicate some or all of these methods. But in practice it's
            // great and I am comfortable relying on this in debug mode to catch
            // bugs early.
            id: Fingerprint::of::<T> as usize,
        }
    }
}

#[test]
fn test_fingerprint() {
    assert_eq!(Fingerprint::of::<usize>(), Fingerprint::of::<usize>());
    assert_eq!(Fingerprint::of::<&str>(), Fingerprint::of::<&'static str>());

    assert_ne!(Fingerprint::of::<usize>(), Fingerprint::of::<isize>());
    assert_ne!(Fingerprint::of::<usize>(), Fingerprint::of::<&usize>());
    assert_ne!(Fingerprint::of::<&usize>(), Fingerprint::of::<&&usize>());
    assert_ne!(Fingerprint::of::<&usize>(), Fingerprint::of::<&mut usize>());

    struct A;
    struct B;
    assert_ne!(Fingerprint::of::<A>(), Fingerprint::of::<B>());
}
<|endoftext|>


<commit_before>use vm::{VM, Value, Int, Float, Function, Userdata, StackFrame, Data};
use typecheck::{TcType, Typed, FunctionType, bool_type_tc, int_type_tc, float_type_tc};
use compiler::CallGlobal;
use std::any::{Any, AnyRefExt};
use std::boxed::BoxAny;

pub trait VMValue {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType;
    fn push(self, stack: &mut StackFrame);
    fn from_value(value: Value) -> Option<Self>;
}
impl VMValue for int {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &int_type_tc
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Int(self));
    }
    fn from_value(value: Value) -> Option<int> {
        match value {
            Int(i) => Some(i),
            _ => None
        }
    }
}
impl VMValue for f64 {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &float_type_tc
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Float(self));
    }
    fn from_value(value: Value) -> Option<f64> {
        match value {
            Float(f) => Some(f),
            _ => None
        }
    }
}
impl VMValue for bool {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &bool_type_tc
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Int(if self { 1 } else { 0 }));
    }
    fn from_value(value: Value) -> Option<bool> {
        match value {
            Int(1) => Some(true),
            Int(0) => Some(false),
            _ => None
        }
    }
}
impl <T: 'static + BoxAny + Clone> VMValue for Box<T> {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<T>()
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Userdata(Data::new(self as Box<Any>)));
    }
    fn from_value(value: Value) -> Option<Box<T>> {
        match value {
            Userdata(v) => v.data.borrow().downcast_ref::<T>().map(|x| box x.clone()),
            _ => None
        }
    }
}
impl <T: 'static> VMValue for *mut T {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<T>()
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Userdata(Data::new(box self as Box<Any>)));
    }
    fn from_value(value: Value) -> Option<*mut T> {
        match value {
            Userdata(v) => v.data.borrow().downcast_ref::<*mut T>().map(|x| *x),
            _ => None
        }
    }
}

fn vm_type<'a, T: VMValue>(vm: &'a VM) -> &'a TcType {
    let t: T = unsafe { ::std::mem::uninitialized() };
    let typ = t.vm_type(vm);
    unsafe { ::std::mem::forget(t) }
    typ
}

trait Get<'a> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Self>;
}
macro_rules! make_get(
    ($($args:ident),* -> $result:ident) => (
impl <'a, $($args : VMValue),*, $result: VMValue> Get<'a> for Callable<'a, ($($args),*), $result> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Callable<'a, ($($args),*), $result>> {
        let value = match vm.get_global(name) {
            Some((function_ref, global)) => {
                match global.type_of() {
                    &FunctionType(ref args, ref return_type) => {
                        let mut arg_iter = args.iter();
                        let ok = $({
                            arg_iter.next().unwrap() == vm_type::<$args>(vm)
                            })&&*;
                        if arg_iter.next().is_none() && ok && **return_type == *vm_type::<$result>(vm) {
                            Some(FunctionRef { value: function_ref })
                        }
                        else {
                            None
                        }
                    }
                    _ => None
                }
            }
            None => None
        };
        match value {
            Some(value) => Some(Callable { vm: vm, value: value }),
            None => None
        }
    }
}
))

make_get!(A, B -> R)

impl <'a, T: VMValue, R: VMValue> Get<'a> for Callable<'a, (T,), R> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Callable<'a, (T,), R>> {
        let value = match vm.get_global(name) {
            Some((function_ref, global)) => {
                match global.type_of() {
                    &FunctionType(ref args, ref return_type) => {
                        if args.len() == 1 {
                            let ok = args[0] == *vm_type::<T>(vm);
                            if ok && **return_type == *vm_type::<R>(vm) {
                                Some(FunctionRef { value: function_ref })
                            }
                            else {
                                None
                            }
                        }
                        else {
                            None
                        }
                    }
                    _ => None
                }
            }
            None => None
        };
        match value {
            Some(value) => Some(Callable { vm: vm, value: value }),
            None => None
        }
    }
}

pub struct Callable<'a, Args, R> {
    vm: &'a mut VM,
    value: FunctionRef<Args, R>
}
struct FunctionRef<Args, R> {
    value: uint
}

impl <Args, R> VMValue for FunctionRef<Args, R> {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<|Args|:'static -> R>()
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Function(self.value));
    }
    fn from_value(value: Value) -> Option<FunctionRef<Args, R>> {
        match value {
            Function(i) => Some(FunctionRef { value: i }),//TODO not type safe
            _ => None
        }
    }
}

impl <'a, A: VMValue, R: VMValue> Callable<'a, (A,), R> {
    pub fn call(&mut self, a: A) -> R {
        let mut vec = Vec::new();
        {
            let mut stack = StackFrame::new(&mut vec, 0, None);
            self.value.push(&mut stack);
            a.push(&mut stack);
            self.vm.execute(stack, &[CallGlobal(1)]);
        }
        vec.pop().and_then(|value| VMValue::from_value(value))
            .expect("Wrong type")
    }
}
impl <'a, A: VMValue, B: VMValue, R: VMValue> Callable<'a, (A, B), R> {
    pub fn call2(&mut self, a: A, b: B) -> R {
        let mut vec = Vec::new();
        {
            let mut stack = StackFrame::new(&mut vec, 0, None);
            self.value.push(&mut stack);
            a.push(&mut stack);
            b.push(&mut stack);
            self.vm.execute(stack, &[CallGlobal(2)]);
        }
        vec.pop().and_then(|value| VMValue::from_value(value))
            .expect("Wrong type")
    }
}

pub fn get_function<'a, T: Get<'a>>(vm: &'a mut VM, name: &str) -> Option<T> {
    Get::get_function(vm, name)
}

#[cfg(test)]
mod tests {
    use super::{Get, Callable};

    use vm::{VM, load_script, StackFrame};
    use typecheck::{bool_type_tc};
    use std::io::BufReader;
    use std::any::AnyMutRefExt;

    #[test]
    fn call_function() {
        let s =
r"
fn add10(x: int) -> int {
    x + 10
}
fn mul(x: float, y: float) -> float {
    x * y
}
";
        let mut vm = VM::new();
        let mut buffer = BufReader::new(s.as_bytes());
        load_script(&mut vm, &mut buffer)
            .unwrap_or_else(|err| fail!("{}", err));
        {
            let mut f: Callable<(int,), int> = Get::get_function(&mut vm, "add10")
                .expect("No function");
            let result = f.call(2);
            assert_eq!(result, 12);
        }
        let mut f: Callable<(f64, f64), f64> = Get::get_function(&mut vm, "mul")
            .expect("No function");
        let result = f.call2(4., 5.);
        assert_eq!(result, 20.);
    }
    #[test]
    fn pass_userdata() {
        let s =
r"
fn id(x: Test) -> Test {
    x
}
";
        let mut vm = VM::new();
        fn test(_: &VM, mut stack: StackFrame) {
            use vm::{Int, Userdata};
            let v = match stack.pop() {
                Userdata(ptr) => {
                    let mut cell = ptr.data.borrow_mut();
                    let test: &mut Test = unsafe { &mut **cell.downcast_mut::<*mut Test>().expect("Expected Test type") };
                    let x = if test.x == 123 { 1 } else { 0 };
                    test.x *= 2;
                    x
                }
                _ => 0
            };
            stack.push(Int(v));
        }
        struct Test {
            x: int
        }
        let test_type = vm.register_type::<Test>("Test")
            .unwrap_or_else(|_| fail!("Could not add type"))
            .clone();
        vm.extern_function("test", vec![test_type], bool_type_tc.clone(), test);
        let mut buffer = BufReader::new(s.as_bytes());
        load_script(&mut vm, &mut buffer)
            .unwrap_or_else(|err| fail!("{}", err));

        let mut test = Test { x: 123 };
        {
            let mut f: Callable<(*mut Test,), *mut Test> = Get::get_function(&mut vm, "id")
                .expect("No function id");
            let result = f.call(&mut test);
            assert!(result == &mut test as *mut Test);
        }
        let mut f: Callable<(*mut Test,), bool> = Get::get_function(&mut vm, "test")
            .expect("No function test");
        let result = f.call(&mut test);
        assert!(result);
        assert_eq!(test.x, 123 * 2);
    }
}
<commit_msg>Added vm_function macro which turns and ordinary function into a function that can be used in the vm<commit_after>use vm::{VM, Value, Int, Float, Function, Userdata, StackFrame, Data};
use typecheck::{TcType, Typed, FunctionType, unit_type_tc, bool_type_tc, int_type_tc, float_type_tc};
use compiler::CallGlobal;
use std::any::{Any, AnyRefExt};
use std::boxed::BoxAny;

pub trait VMValue {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType;
    fn push(self, stack: &mut StackFrame);
    fn from_value(value: Value) -> Option<Self>;
}
impl VMValue for () {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &unit_type_tc
    }
    fn push(self, _: &mut StackFrame) {
    }
    fn from_value(_: Value) -> Option<()> {
        Some(())
    }
}
impl VMValue for int {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &int_type_tc
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Int(self));
    }
    fn from_value(value: Value) -> Option<int> {
        match value {
            Int(i) => Some(i),
            _ => None
        }
    }
}
impl VMValue for f64 {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &float_type_tc
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Float(self));
    }
    fn from_value(value: Value) -> Option<f64> {
        match value {
            Float(f) => Some(f),
            _ => None
        }
    }
}
impl VMValue for bool {
    fn vm_type<'a>(&self, _: &'a VM) -> &'a TcType {
        &bool_type_tc
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Int(if self { 1 } else { 0 }));
    }
    fn from_value(value: Value) -> Option<bool> {
        match value {
            Int(1) => Some(true),
            Int(0) => Some(false),
            _ => None
        }
    }
}
impl <T: 'static + BoxAny + Clone> VMValue for Box<T> {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<T>()
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Userdata(Data::new(self as Box<Any>)));
    }
    fn from_value(value: Value) -> Option<Box<T>> {
        match value {
            Userdata(v) => v.data.borrow().downcast_ref::<T>().map(|x| box x.clone()),
            _ => None
        }
    }
}
impl <T: 'static> VMValue for *mut T {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<T>()
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Userdata(Data::new(box self as Box<Any>)));
    }
    fn from_value(value: Value) -> Option<*mut T> {
        match value {
            Userdata(v) => v.data.borrow().downcast_ref::<*mut T>().map(|x| *x),
            _ => None
        }
    }
}

fn vm_type<'a, T: VMValue>(vm: &'a VM) -> &'a TcType {
    let t: T = unsafe { ::std::mem::uninitialized() };
    let typ = t.vm_type(vm);
    unsafe { ::std::mem::forget(t) }
    typ
}

trait Get<'a> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Self>;
}
macro_rules! make_get(
    ($($args:ident),* -> $result:ident) => (
impl <'a, $($args : VMValue),*, $result: VMValue> Get<'a> for Callable<'a, ($($args),*), $result> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Callable<'a, ($($args),*), $result>> {
        let value = match vm.get_global(name) {
            Some((function_ref, global)) => {
                match global.type_of() {
                    &FunctionType(ref args, ref return_type) => {
                        let mut arg_iter = args.iter();
                        let ok = $({
                            arg_iter.next().unwrap() == vm_type::<$args>(vm)
                            })&&*;
                        if arg_iter.next().is_none() && ok && **return_type == *vm_type::<$result>(vm) {
                            Some(FunctionRef { value: function_ref })
                        }
                        else {
                            None
                        }
                    }
                    _ => None
                }
            }
            None => None
        };
        match value {
            Some(value) => Some(Callable { vm: vm, value: value }),
            None => None
        }
    }
}
))

make_get!(A, B -> R)

impl <'a, T: VMValue, R: VMValue> Get<'a> for Callable<'a, (T,), R> {
    fn get_function(vm: &'a mut VM, name: &str) -> Option<Callable<'a, (T,), R>> {
        let value = match vm.get_global(name) {
            Some((function_ref, global)) => {
                match global.type_of() {
                    &FunctionType(ref args, ref return_type) => {
                        if args.len() == 1 {
                            let ok = args[0] == *vm_type::<T>(vm);
                            if ok && **return_type == *vm_type::<R>(vm) {
                                Some(FunctionRef { value: function_ref })
                            }
                            else {
                                None
                            }
                        }
                        else {
                            None
                        }
                    }
                    _ => None
                }
            }
            None => None
        };
        match value {
            Some(value) => Some(Callable { vm: vm, value: value }),
            None => None
        }
    }
}

pub struct Callable<'a, Args, R> {
    vm: &'a mut VM,
    value: FunctionRef<Args, R>
}
struct FunctionRef<Args, R> {
    value: uint
}

impl <Args, R> VMValue for FunctionRef<Args, R> {
    fn vm_type<'a>(&self, vm: &'a VM) -> &'a TcType {
        vm.get_type::<|Args|:'static -> R>()
    }
    fn push(self, stack: &mut StackFrame) {
        stack.push(Function(self.value));
    }
    fn from_value(value: Value) -> Option<FunctionRef<Args, R>> {
        match value {
            Function(i) => Some(FunctionRef { value: i }),//TODO not type safe
            _ => None
        }
    }
}

impl <'a, A: VMValue, R: VMValue> Callable<'a, (A,), R> {
    pub fn call(&mut self, a: A) -> R {
        let mut vec = Vec::new();
        {
            let mut stack = StackFrame::new(&mut vec, 0, None);
            self.value.push(&mut stack);
            a.push(&mut stack);
            self.vm.execute(stack, &[CallGlobal(1)]);
        }
        vec.pop().and_then(|value| VMValue::from_value(value))
            .expect("Wrong type")
    }
}
impl <'a, A: VMValue, B: VMValue, R: VMValue> Callable<'a, (A, B), R> {
    pub fn call2(&mut self, a: A, b: B) -> R {
        let mut vec = Vec::new();
        {
            let mut stack = StackFrame::new(&mut vec, 0, None);
            self.value.push(&mut stack);
            a.push(&mut stack);
            b.push(&mut stack);
            self.vm.execute(stack, &[CallGlobal(2)]);
        }
        vec.pop().and_then(|value| VMValue::from_value(value))
            .expect("Wrong type")
    }
}

pub fn get_function<'a, T: Get<'a>>(vm: &'a mut VM, name: &str) -> Option<T> {
    Get::get_function(vm, name)
}

trait VMFunction {
    fn unpack_and_call(mut stack: StackFrame, f: Self);
}

impl <R: VMValue> VMFunction for fn () -> R {
    fn unpack_and_call(mut stack: StackFrame, f: fn () -> R) {
        let r = f();
        r.push(&mut stack);
    }
}

macro_rules! make_vm_function(
    ($($args:ident),*) => (
impl <$($args : VMValue),*, R: VMValue> VMFunction for fn ($($args),*) -> R {
    fn unpack_and_call(mut stack: StackFrame, f: fn ($($args),*) -> R) {
        let mut i = 0;
        $(let $args = {
            let x = VMValue::from_value(stack[i].clone()).unwrap();
            i += 1;
            x
        });*;
        drop(i);//Avoid unused warnings
        let r = f($($args),*);
        r.push(&mut stack);
    }
}
    )
)

make_vm_function!(a)
make_vm_function!(a, b)
make_vm_function!(a, b, c)
make_vm_function!(a, b, c, d)
make_vm_function!(a, b, c, d, e)
make_vm_function!(a, b, c, d, e, f)
make_vm_function!(a, b, c, d, e, f, g)

macro_rules! vm_function(
    ($func: expr) => ({
        fn wrapper(_: &VM, stack: StackFrame) {
            VMFunction::unpack_and_call(stack, $func)
        }
        wrapper
    })
)

#[cfg(test)]
mod tests {
    use super::{Get, Callable, VMFunction};

    use vm::{VM, load_script, StackFrame};
    use typecheck::{bool_type_tc};
    use std::io::BufReader;

    #[test]
    fn call_function() {
        let s =
r"
fn add10(x: int) -> int {
    x + 10
}
fn mul(x: float, y: float) -> float {
    x * y
}
";
        let mut vm = VM::new();
        let mut buffer = BufReader::new(s.as_bytes());
        load_script(&mut vm, &mut buffer)
            .unwrap_or_else(|err| fail!("{}", err));
        {
            let mut f: Callable<(int,), int> = Get::get_function(&mut vm, "add10")
                .expect("No function");
            let result = f.call(2);
            assert_eq!(result, 12);
        }
        let mut f: Callable<(f64, f64), f64> = Get::get_function(&mut vm, "mul")
            .expect("No function");
        let result = f.call2(4., 5.);
        assert_eq!(result, 20.);
    }
    #[test]
    fn pass_userdata() {
        let s =
r"
fn id(x: Test) -> Test {
    x
}
";
        let mut vm = VM::new();
        fn test(test: *mut Test) -> bool {
            let test = unsafe { &mut *test };
            let x = test.x == 123;
            test.x *= 2;
            x
        }
        struct Test {
            x: int
        }
        let test_type = vm.register_type::<Test>("Test")
            .unwrap_or_else(|_| fail!("Could not add type"))
            .clone();
        vm.extern_function("test", vec![test_type], bool_type_tc.clone(), vm_function!(test));
        let mut buffer = BufReader::new(s.as_bytes());
        load_script(&mut vm, &mut buffer)
            .unwrap_or_else(|err| fail!("{}", err));

        let mut test = Test { x: 123 };
        {
            let mut f: Callable<(*mut Test,), *mut Test> = Get::get_function(&mut vm, "id")
                .expect("No function id");
            let result = f.call(&mut test);
            assert!(result == &mut test as *mut Test);
        }
        let mut f: Callable<(*mut Test,), bool> = Get::get_function(&mut vm, "test")
            .expect("No function test");
        let result = f.call(&mut test);
        assert!(result);
        assert_eq!(test.x, 123 * 2);
    }
}
<|endoftext|>


<commit_before>use std::str;
use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::sync::Arc;
use std::clone::Clone;

use hyper::status::StatusCode;
use hyper::server::{Handler, Server, Request, Response};
use mime_types::Types as MimeTypes;

pub use typemap::Key;
pub use hyper::header::Headers;
pub use hyper::header;
pub use hyper::mime;
pub use request::SapperRequest;
pub use response::SapperResponse;
pub use router_m::Router;
pub use router::SapperRouter;
pub use handler::SapperHandler;

#[derive(Clone)]
pub struct PathParams;

/// Status Codes
pub mod status {
    pub use hyper::status::StatusCode as Status;
    pub use hyper::status::StatusCode::*;
}

#[derive(Debug, PartialEq, Clone)]
pub enum Error {
    NotFound(String),
    InvalidConfig,
    InvalidRouterConfig,
    FileNotExist,
    ShouldRedirect(String),
    Break(String),
    Fatal(String),
    Custom(String),
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub trait SapperModule: Sync + Send {
    fn before(&self, req: &mut SapperRequest) -> Result<()> {
        Ok(())
    }

    fn after(&self, req: &SapperRequest, res: &mut SapperResponse) -> Result<()> {
        Ok(())
    }

    fn router(&self, &mut SapperRouter) -> Result<()>;

}

pub trait SapperAppShell {
    fn before(&self, &mut SapperRequest) -> Result<()>;
    fn after(&self, &SapperRequest, &mut SapperResponse) -> Result<()>;
}

pub type GlobalInitClosure = Box<Fn(&mut SapperRequest) -> Result<()> + 'static + Send + Sync>;
pub type SapperAppShellType = Box<SapperAppShell + 'static + Send + Sync>;

pub struct SapperApp {
    pub address:        String,
    pub port:           u32,
    // for app entry, global middeware
    pub shell:          Option<Arc<SapperAppShellType>>,
    // for actually use to recognize
    pub routers:        Router,
    // do simple static file service
    pub static_service: bool,

    pub init_closure:   Option<Arc<GlobalInitClosure>>
}

impl SapperApp {
    pub fn new() -> SapperApp {
        SapperApp {
            address: String::new(),
            port: 0,
            shell: None,
            routers: Router::new(),
            static_service: true,
            init_closure: None
        }
    }

    pub fn address(&mut self, address: &str) -> &mut Self {
        self.address = address.to_owned();
        self
    }

    pub fn port(&mut self, port: u32) -> &mut Self {
        self.port = port;
        self
    }

    pub fn static_service(&mut self, open: bool) -> &mut Self {
        self.static_service = open;
        self
    }

    pub fn with_shell(&mut self, w: SapperAppShellType) -> &mut Self {
        self.shell = Some(Arc::new(w));
        self
    }

    pub fn init_global(&mut self, clos: GlobalInitClosure) -> &mut Self {
        self.init_closure = Some(Arc::new(clos));
        self
    }

    // add methods of this sapper module
    pub fn add_module(&mut self, sm: Box<SapperModule>) -> &mut Self {

        let mut router = SapperRouter::new();
        // get the sm router
        sm.router(&mut router).unwrap();
        let sm = Arc::new(sm);

        for (method, handler_vec) in router.into_router() {
            // add to wrapped router
            for &(glob, ref handler) in handler_vec.iter() {
                let method = method.clone();
                let glob = glob.clone();
                let handler = handler.clone();
                let sm = sm.clone();
                let shell = self.shell.clone();
                let init_closure = self.init_closure.clone();

                self.routers.route(method, glob, Arc::new(Box::new(move |req: &mut SapperRequest| -> Result<SapperResponse> {
                    if let Some(ref c) = init_closure {
                        c(req)?;
                    }
                    if let Some(ref shell) = shell {
                        shell.before(req)?;
                    }
                    sm.before(req)?;
                    let mut response: SapperResponse = handler.handle(req)?;
                    sm.after(req, &mut response)?;
                    if let Some(ref shell) = shell {
                        shell.after(req, &mut response)?;
                    }
                    Ok(response)
                })));
            }
        }

        self
    }

    pub fn run_http(self) {

        let addr = self.address.clone() + ":" + &self.port.to_string();
        //let self_box = Arc::new(Box::new(self));

        Server::http(&addr[..]).unwrap()
                .handle(self).unwrap();

    }
}

impl Handler for SapperApp {

    fn handle(&self, req: Request, mut res: Response) {

        let mut sreq = SapperRequest::new(Box::new(req));
        let (path, query) = sreq.uri();

        // pass req to routers, execute matched biz handler
        let response_w = self.routers.handle_method(&mut sreq, &path).unwrap();
        if response_w.is_err() {

            if self.static_service {
                match simple_file_get(&path) {
                    Ok((file_u8vec, file_mime)) => {
                        res.headers_mut().set_raw("Content-Type", vec![file_mime.as_bytes().to_vec()]);

                        return res.send(&file_u8vec[..]).unwrap();
                    },
                    Err(_) => {
                        return res.send(&"".as_bytes()).unwrap();
                    }
                }
            }

            // return 404 NotFound now
            *res.status_mut() = StatusCode::NotFound;
            return res.send(&"".as_bytes()).unwrap();
        }

        let sres = response_w.unwrap();
        *res.status_mut() = sres.status();
        match sres.body() {
            &Some(ref vec) => {

                for header in sres.headers().iter() {
                    res.headers_mut()
                        .set_raw(header.name().to_owned(),
                            vec![header.value_string().as_bytes().to_vec()]);
                }

                return res.send(&vec[..]).unwrap();
            },
            &None => {
                return res.send(&"".as_bytes()).unwrap();
            }
        }

    }

}

// this is very expensive in time
// should make it as global
lazy_static! {
    static ref MTYPES: MimeTypes = { MimeTypes::new().unwrap() };
}

fn simple_file_get(path: &str) -> Result<(Vec<u8>, String)> {
    let new_path;
    if &path[(path.len()-1)..] == "/" {
        new_path = "static/".to_owned() + path + "index.html";
    }
    else {
        new_path = "static/".to_owned() + path;
    }
    //println!("file path: {}", new_path);
    match File::open(&new_path) {
        Ok(ref mut file) => {
            let mut s: Vec<u8> = vec![];
            file.read_to_end(&mut s).unwrap_or(0);

            let mt_str = MTYPES.mime_for_path(Path::new(&new_path));

            Ok((s, mt_str.to_owned()))
        },
        Err(_) => Err(Error::FileNotExist)
    }
}

<commit_msg>fix a status bug when not pattern match.<commit_after>use std::str;
use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::sync::Arc;
use std::clone::Clone;

use hyper::status::StatusCode;
use hyper::server::{Handler, Server, Request, Response};
use mime_types::Types as MimeTypes;

pub use typemap::Key;
pub use hyper::header::Headers;
pub use hyper::header;
pub use hyper::mime;
pub use request::SapperRequest;
pub use response::SapperResponse;
pub use router_m::Router;
pub use router::SapperRouter;
pub use handler::SapperHandler;

#[derive(Clone)]
pub struct PathParams;

/// Status Codes
pub mod status {
    pub use hyper::status::StatusCode as Status;
    pub use hyper::status::StatusCode::*;
}

#[derive(Debug, PartialEq, Clone)]
pub enum Error {
    NotFound(String),
    InvalidConfig,
    InvalidRouterConfig,
    FileNotExist,
    ShouldRedirect(String),
    Break(String),
    Fatal(String),
    Custom(String),
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub trait SapperModule: Sync + Send {
    fn before(&self, req: &mut SapperRequest) -> Result<()> {
        Ok(())
    }

    fn after(&self, req: &SapperRequest, res: &mut SapperResponse) -> Result<()> {
        Ok(())
    }

    fn router(&self, &mut SapperRouter) -> Result<()>;

}

pub trait SapperAppShell {
    fn before(&self, &mut SapperRequest) -> Result<()>;
    fn after(&self, &SapperRequest, &mut SapperResponse) -> Result<()>;
}

pub type GlobalInitClosure = Box<Fn(&mut SapperRequest) -> Result<()> + 'static + Send + Sync>;
pub type SapperAppShellType = Box<SapperAppShell + 'static + Send + Sync>;

pub struct SapperApp {
    pub address:        String,
    pub port:           u32,
    // for app entry, global middeware
    pub shell:          Option<Arc<SapperAppShellType>>,
    // for actually use to recognize
    pub routers:        Router,
    // do simple static file service
    pub static_service: bool,

    pub init_closure:   Option<Arc<GlobalInitClosure>>
}

impl SapperApp {
    pub fn new() -> SapperApp {
        SapperApp {
            address: String::new(),
            port: 0,
            shell: None,
            routers: Router::new(),
            static_service: true,
            init_closure: None
        }
    }

    pub fn address(&mut self, address: &str) -> &mut Self {
        self.address = address.to_owned();
        self
    }

    pub fn port(&mut self, port: u32) -> &mut Self {
        self.port = port;
        self
    }

    pub fn static_service(&mut self, open: bool) -> &mut Self {
        self.static_service = open;
        self
    }

    pub fn with_shell(&mut self, w: SapperAppShellType) -> &mut Self {
        self.shell = Some(Arc::new(w));
        self
    }

    pub fn init_global(&mut self, clos: GlobalInitClosure) -> &mut Self {
        self.init_closure = Some(Arc::new(clos));
        self
    }

    // add methods of this sapper module
    pub fn add_module(&mut self, sm: Box<SapperModule>) -> &mut Self {

        let mut router = SapperRouter::new();
        // get the sm router
        sm.router(&mut router).unwrap();
        let sm = Arc::new(sm);

        for (method, handler_vec) in router.into_router() {
            // add to wrapped router
            for &(glob, ref handler) in handler_vec.iter() {
                let method = method.clone();
                let glob = glob.clone();
                let handler = handler.clone();
                let sm = sm.clone();
                let shell = self.shell.clone();
                let init_closure = self.init_closure.clone();

                self.routers.route(method, glob, Arc::new(Box::new(move |req: &mut SapperRequest| -> Result<SapperResponse> {
                    if let Some(ref c) = init_closure {
                        c(req)?;
                    }
                    if let Some(ref shell) = shell {
                        shell.before(req)?;
                    }
                    sm.before(req)?;
                    let mut response: SapperResponse = handler.handle(req)?;
                    sm.after(req, &mut response)?;
                    if let Some(ref shell) = shell {
                        shell.after(req, &mut response)?;
                    }
                    Ok(response)
                })));
            }
        }

        self
    }

    pub fn run_http(self) {

        let addr = self.address.clone() + ":" + &self.port.to_string();
        //let self_box = Arc::new(Box::new(self));

        Server::http(&addr[..]).unwrap()
                .handle(self).unwrap();

    }
}

impl Handler for SapperApp {

    fn handle(&self, req: Request, mut res: Response) {

        let mut sreq = SapperRequest::new(Box::new(req));
        let (path, query) = sreq.uri();

        // pass req to routers, execute matched biz handler
        let response_w = self.routers.handle_method(&mut sreq, &path).unwrap();
        if response_w.is_err() {

            if self.static_service {
                match simple_file_get(&path) {
                    Ok((file_u8vec, file_mime)) => {
                        res.headers_mut().set_raw("Content-Type", vec![file_mime.as_bytes().to_vec()]);

                        return res.send(&file_u8vec[..]).unwrap();
                    },
                    Err(_) => {
                        *res.status_mut() = StatusCode::NotFound;
                        return res.send(&"".as_bytes()).unwrap();
                    }
                }
            }

            // return 404 NotFound now
            *res.status_mut() = StatusCode::NotFound;
            return res.send(&"".as_bytes()).unwrap();
        }

        let sres = response_w.unwrap();
        *res.status_mut() = sres.status();
        match sres.body() {
            &Some(ref vec) => {

                for header in sres.headers().iter() {
                    res.headers_mut()
                        .set_raw(header.name().to_owned(),
                            vec![header.value_string().as_bytes().to_vec()]);
                }

                return res.send(&vec[..]).unwrap();
            },
            &None => {
                return res.send(&"".as_bytes()).unwrap();
            }
        }

    }

}

// this is very expensive in time
// should make it as global
lazy_static! {
    static ref MTYPES: MimeTypes = { MimeTypes::new().unwrap() };
}

fn simple_file_get(path: &str) -> Result<(Vec<u8>, String)> {
    let new_path;
    if &path[(path.len()-1)..] == "/" {
        new_path = "static/".to_owned() + path + "index.html";
    }
    else {
        new_path = "static/".to_owned() + path;
    }
    //println!("file path: {}", new_path);
    match File::open(&new_path) {
        Ok(ref mut file) => {
            let mut s: Vec<u8> = vec![];
            file.read_to_end(&mut s).unwrap_or(0);

            let mt_str = MTYPES.mime_for_path(Path::new(&new_path));

            Ok((s, mt_str.to_owned()))
        },
        Err(_) => Err(Error::FileNotExist)
    }
}

<|endoftext|>