<commit_before>use base64;
use crate::buffer;
use crate::image;
use std::{fs, io};

use image_crate::ImageFormat::{JPEG as Jpeg, PNG as Png};
use std::path::Path;
use crate::{Document, Error, Gltf, Result};

/// Return type of `import`.
type Import = (Document, Vec<buffer::Data>, Vec<image::Data>);

/// Represents the set of URI schemes the importer supports.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum Scheme<'a> {
    /// `data:[<media type>];base64,<data>`.
    Data(Option<&'a str>, &'a str),

    /// `file:[//]<absolute file path>`.
    ///
    /// Note: The file scheme does not implement authority.
    File(&'a str),

    /// `../foo`, etc.
    Relative,

    /// Placeholder for an unsupported URI scheme identifier.
    Unsupported,
}

impl<'a> Scheme<'a> {
    fn parse<'s>(uri: &'s str) -> Scheme<'s> {
        if uri.contains(":") {
            if uri.starts_with("data:") {
                let match0 = &uri["data:".len()..].split(";base64,").nth(0);
                let match1 = &uri["data:".len()..].split(";base64,").nth(1);
                if match1.is_some() {
                    Scheme::Data(Some(match0.unwrap()), match1.unwrap())
                } else if match0.is_some() {
                    Scheme::Data(None, match0.unwrap())
                } else {
                    Scheme::Unsupported
                }
            } else if uri.starts_with("file://") {
                Scheme::File(&uri["file://".len()..])
            } else if uri.starts_with("file:") {
                Scheme::File(&uri["file:".len()..])
            } else {
                Scheme::Unsupported
            }
        } else {
            Scheme::Relative
        }
    }

    fn read(base: &Path, uri: &str) -> Result<Vec<u8>> {
        match Scheme::parse(uri) {
            Scheme::Data(_, base64) => base64::decode(&base64).map_err(Error::Base64),
            Scheme::File(path) => read_to_end(path),
            Scheme::Relative => read_to_end(base.join(uri)),
            Scheme::Unsupported => Err(Error::UnsupportedScheme),
        }
    }
}

fn read_to_end<P>(path: P) -> Result<Vec<u8>>
where P: AsRef<Path>
{
    use io::Read;
    let file = fs::File::open(path.as_ref()).map_err(Error::Io)?;
    let length = file.metadata().map(|x| x.len()).unwrap_or(0);
    let mut reader = io::BufReader::new(file);
    let mut data = Vec::with_capacity(length as usize);
    reader.read_to_end(&mut data).map_err(Error::Io)?;
    Ok(data)
}

/// Import the buffer data referenced by a glTF document.
pub fn import_buffer_data(
    document: &Document,
    base: &Path,
    mut blob: Option<Vec<u8>>,
) -> Result<Vec<buffer::Data>> {
    let mut buffers = Vec::new();
    for buffer in document.buffers() {
        let mut data = match buffer.source() {
            buffer::Source::Uri(uri) => Scheme::read(base, uri),
            buffer::Source::Bin => blob.take().ok_or(Error::MissingBlob),
        }?;
        if data.len() < buffer.length() {
            return Err(
                Error::BufferLength {
                    buffer: buffer.index(),
                    expected: buffer.length(),
                    actual: data.len(),
                }
            );
        }
        while data.len() % 4 != 0 {
            data.push(0);
        }
        buffers.push(buffer::Data(data));
    }
    Ok(buffers)
}

/// Import the image data referenced by a glTF document.
pub fn import_image_data(
    document: &Document,
    base: &Path,
    buffer_data: &[buffer::Data],
) -> Result<Vec<image::Data>> {
    let mut images = Vec::new();
    for image in document.images() {
        match image.source() {
            image::Source::Uri { uri, mime_type } => {
                match Scheme::parse(uri) {
                    Scheme::Data(Some(annoying_case), base64) => {
                        let format = match annoying_case.as_ref() {
                            "image/png" => Png,
                            "image/jpeg" => Jpeg,
                            _ => return Err(Error::UnsupportedImageEncoding),
                        };
                        let encoded_image = base64::decode(&base64).map_err(Error::Base64)?;
                        let decoded_image = image_crate::load_from_memory_with_format(&encoded_image, format)?;
                        images.push(image::Data::new(decoded_image));
                        continue;
                    },
                    Scheme::Unsupported => return Err(Error::UnsupportedScheme),
                    _ => {},
                }
                let encoded_image = Scheme::read(base, uri)?;
                let encoded_format =  match mime_type {
                    Some("image/png") => Png,
                    Some("image/jpeg") => Jpeg,
                    Some(_) => return Err(Error::UnsupportedImageEncoding),
                    None => match uri.rsplit(".").next() {
                        Some("png") => Png,
                        Some("jpg") | Some("jpeg") => Jpeg,
                        _ => return Err(Error::UnsupportedImageEncoding),
                    },
                };
                let decoded_image = image_crate::load_from_memory_with_format(&encoded_image, encoded_format)?;
                images.push(image::Data::new(decoded_image));
            },
            image::Source::View { view, mime_type } => {
                let parent_buffer_data = &buffer_data[view.buffer().index()].0;
                let begin = view.offset();
                let end = begin + view.length();
                let encoded_image = &parent_buffer_data[begin..end];
                let encoded_format = match mime_type {
                    "image/png" => Png,
                    "image/jpeg" => Jpeg,
                    _ => return Err(Error::UnsupportedImageEncoding)
                };
                let decoded_image = image_crate::load_from_memory_with_format(encoded_image, encoded_format)?;
                images.push(image::Data::new(decoded_image));
            },
        }
    }

    Ok(images)
}

fn import_impl(Gltf { document, blob }: Gltf, base: &Path) -> Result<Import> {
    let buffer_data = import_buffer_data(&document, base, blob)?;
    let image_data = import_image_data(&document, base, &buffer_data)?;
    let import = (document, buffer_data, image_data);
    Ok(import)
}

/// Import some glTF 2.0 from the file system.
///
/// ```
/// # fn run() -> Result<(), gltf::Error> {
/// # let path = "examples/Box.gltf";
/// # #[allow(unused)]
/// let (document, buffers, images) = gltf::import(path)?;
/// # Ok(())
/// # }
/// # fn main() {
/// #     run().expect("test failure");
/// # }
/// ```
///
/// ### Note
///
/// This function is provided as a convenience for loading glTF and associated
/// resources from the file system. It is suitable for real world use but may
/// not be suitable for all real world use cases. More complex import scenarios
/// such downloading from web URLs are not handled by this function. These
/// scenarios are delegated to the user.
///
/// You can read glTF without loading resources by constructing the [`Gltf`]
/// (standard glTF) or [`Glb`] (binary glTF) data structures explicitly.
///
/// [`Gltf`]: struct.Gltf.html
/// [`Glb`]: struct.Glb.html
pub fn import<P>(path: P) -> Result<Import>
    where P: AsRef<Path>
{
    let path = path.as_ref();
    let base = path.parent().unwrap_or(Path::new("./"));
    let file = fs::File::open(path).map_err(Error::Io)?;
    let reader = io::BufReader::new(file);
    import_impl(Gltf::from_reader(reader)?, base)
}

/// Import some glTF 2.0 from a slice
///
/// ```
/// # extern crate gltf;
/// # use std::fs;
/// # use std::io::Read;
/// # fn run() -> Result<(), gltf::Error> {
/// # let path = "examples/Box.glb";
/// # let mut file = fs::File::open(path).map_err(gltf::Error::Io)?;
/// # let mut bytes = Vec::new();
/// # file.read_to_end(&mut bytes).map_err(gltf::Error::Io)?;
/// # #[allow(unused)]
/// let (document, buffers, images) = gltf::import_slice(bytes.as_slice())?;
/// # Ok(())
/// # }
/// # fn main() {
/// #     run().expect("test failure");
/// # }
/// ```
pub fn import_slice(slice: &[u8]) -> Result<Import> {
    import_impl(Gltf::from_slice(slice)?, Path::new("./"))
}
<commit_msg>make path an option and error if there's a reference in a slice only import<commit_after>use base64;
use crate::buffer;
use crate::image;
use std::{fs, io};

use image_crate::ImageFormat::{JPEG as Jpeg, PNG as Png};
use std::path::Path;
use crate::{Document, Error, Gltf, Result};

/// Return type of `import`.
type Import = (Document, Vec<buffer::Data>, Vec<image::Data>);

/// Represents the set of URI schemes the importer supports.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum Scheme<'a> {
    /// `data:[<media type>];base64,<data>`.
    Data(Option<&'a str>, &'a str),

    /// `file:[//]<absolute file path>`.
    ///
    /// Note: The file scheme does not implement authority.
    File(&'a str),

    /// `../foo`, etc.
    Relative,

    /// Placeholder for an unsupported URI scheme identifier.
    Unsupported,
}

impl<'a> Scheme<'a> {
    fn parse<'s>(uri: &'s str) -> Scheme<'s> {
        if uri.contains(":") {
            if uri.starts_with("data:") {
                let match0 = &uri["data:".len()..].split(";base64,").nth(0);
                let match1 = &uri["data:".len()..].split(";base64,").nth(1);
                if match1.is_some() {
                    Scheme::Data(Some(match0.unwrap()), match1.unwrap())
                } else if match0.is_some() {
                    Scheme::Data(None, match0.unwrap())
                } else {
                    Scheme::Unsupported
                }
            } else if uri.starts_with("file://") {
                Scheme::File(&uri["file://".len()..])
            } else if uri.starts_with("file:") {
                Scheme::File(&uri["file:".len()..])
            } else {
                Scheme::Unsupported
            }
        } else {
            Scheme::Relative
        }
    }

    fn read(base: &Path, uri: &str) -> Result<Vec<u8>> {
        match Scheme::parse(uri) {
            Scheme::Data(_, base64) => base64::decode(&base64).map_err(Error::Base64),
            Scheme::File(path) => read_to_end(path),
            Scheme::Relative => read_to_end(base.join(uri)),
            Scheme::Unsupported => Err(Error::UnsupportedScheme),
        }
    }
}

fn read_to_end<P>(path: P) -> Result<Vec<u8>>
where P: AsRef<Path>
{
    use io::Read;
    let file = fs::File::open(path.as_ref()).map_err(Error::Io)?;
    let length = file.metadata().map(|x| x.len()).unwrap_or(0);
    let mut reader = io::BufReader::new(file);
    let mut data = Vec::with_capacity(length as usize);
    reader.read_to_end(&mut data).map_err(Error::Io)?;
    Ok(data)
}

/// Import the buffer data referenced by a glTF document.
pub fn import_buffer_data(
    document: &Document,
    base: Option<&Path>,
    mut blob: Option<Vec<u8>>,
) -> Result<Vec<buffer::Data>> {
    let mut buffers = Vec::new();
    for buffer in document.buffers() {
        let mut data = match buffer.source() {
            buffer::Source::Uri(uri) if base.is_some() => Scheme::read(base.unwrap(), uri),
            buffer::Source::Bin => blob.take().ok_or(Error::MissingBlob),
            _ => Err(Error::MissingBlob)
        }?;
        if data.len() < buffer.length() {
            return Err(
                Error::BufferLength {
                    buffer: buffer.index(),
                    expected: buffer.length(),
                    actual: data.len(),
                }
            );
        }
        while data.len() % 4 != 0 {
            data.push(0);
        }
        buffers.push(buffer::Data(data));
    }
    Ok(buffers)
}

/// Import the image data referenced by a glTF document.
pub fn import_image_data(
    document: &Document,
    base: Option<&Path>,
    buffer_data: &[buffer::Data],
) -> Result<Vec<image::Data>> {
    let mut images = Vec::new();
    for image in document.images() {
        match image.source() {
            image::Source::Uri { uri, mime_type } if base.is_some() => {
                match Scheme::parse(uri) {
                    Scheme::Data(Some(annoying_case), base64) => {
                        let format = match annoying_case.as_ref() {
                            "image/png" => Png,
                            "image/jpeg" => Jpeg,
                            _ => return Err(Error::UnsupportedImageEncoding),
                        };
                        let encoded_image = base64::decode(&base64).map_err(Error::Base64)?;
                        let decoded_image = image_crate::load_from_memory_with_format(&encoded_image, format)?;
                        images.push(image::Data::new(decoded_image));
                        continue;
                    },
                    Scheme::Unsupported => return Err(Error::UnsupportedScheme),
                    _ => {},
                }
                let encoded_image = Scheme::read(base.unwrap(), uri)?;
                let encoded_format =  match mime_type {
                    Some("image/png") => Png,
                    Some("image/jpeg") => Jpeg,
                    Some(_) => return Err(Error::UnsupportedImageEncoding),
                    None => match uri.rsplit(".").next() {
                        Some("png") => Png,
                        Some("jpg") | Some("jpeg") => Jpeg,
                        _ => return Err(Error::UnsupportedImageEncoding),
                    },
                };
                let decoded_image = image_crate::load_from_memory_with_format(&encoded_image, encoded_format)?;
                images.push(image::Data::new(decoded_image));
            },
            image::Source::View { view, mime_type } => {
                let parent_buffer_data = &buffer_data[view.buffer().index()].0;
                let begin = view.offset();
                let end = begin + view.length();
                let encoded_image = &parent_buffer_data[begin..end];
                let encoded_format = match mime_type {
                    "image/png" => Png,
                    "image/jpeg" => Jpeg,
                    _ => return Err(Error::UnsupportedImageEncoding)
                };
                let decoded_image = image_crate::load_from_memory_with_format(encoded_image, encoded_format)?;
                images.push(image::Data::new(decoded_image));
            },
            _ => Err(Error::MissingBlob)
        }
    }

    Ok(images)
}

fn import_impl(Gltf { document, blob }: Gltf, base: Option<&Path>) -> Result<Import> {
    let buffer_data = import_buffer_data(&document, base, blob)?;
    let image_data = import_image_data(&document, base, &buffer_data)?;
    let import = (document, buffer_data, image_data);
    Ok(import)
}

/// Import some glTF 2.0 from the file system.
///
/// ```
/// # fn run() -> Result<(), gltf::Error> {
/// # let path = "examples/Box.gltf";
/// # #[allow(unused)]
/// let (document, buffers, images) = gltf::import(path)?;
/// # Ok(())
/// # }
/// # fn main() {
/// #     run().expect("test failure");
/// # }
/// ```
///
/// ### Note
///
/// This function is provided as a convenience for loading glTF and associated
/// resources from the file system. It is suitable for real world use but may
/// not be suitable for all real world use cases. More complex import scenarios
/// such downloading from web URLs are not handled by this function. These
/// scenarios are delegated to the user.
///
/// You can read glTF without loading resources by constructing the [`Gltf`]
/// (standard glTF) or [`Glb`] (binary glTF) data structures explicitly.
///
/// [`Gltf`]: struct.Gltf.html
/// [`Glb`]: struct.Glb.html
pub fn import<P>(path: P) -> Result<Import>
    where P: AsRef<Path>
{
    let path = path.as_ref();
    let base = path.parent().unwrap_or(Path::new("./"));
    let file = fs::File::open(path).map_err(Error::Io)?;
    let reader = io::BufReader::new(file);
    import_impl(Gltf::from_reader(reader)?, Some(base))
}

/// Import some glTF 2.0 from a slice
///
/// ```
/// # extern crate gltf;
/// # use std::fs;
/// # use std::io::Read;
/// # fn run() -> Result<(), gltf::Error> {
/// # let path = "examples/Box.glb";
/// # let mut file = fs::File::open(path).map_err(gltf::Error::Io)?;
/// # let mut bytes = Vec::new();
/// # file.read_to_end(&mut bytes).map_err(gltf::Error::Io)?;
/// # #[allow(unused)]
/// let (document, buffers, images) = gltf::import_slice(bytes.as_slice())?;
/// # Ok(())
/// # }
/// # fn main() {
/// #     run().expect("test failure");
/// # }
/// ```
pub fn import_slice(slice: &[u8]) -> Result<Import> {
    import_impl(Gltf::from_slice(slice)?, None)
}
<|endoftext|>


<commit_before>//! Input/Output abstraction for memory, ROM and I/O mapped registers

use gpu::Gpu;

pub mod rom;
pub mod ram;
pub mod timer;

/// Interconnect struct used by the CPU and GPU to access the ROM, RAM
/// and registers
pub struct Interconnect<'a> {
    rom:        rom::Rom,
    /// Bankable RAM
    ram:        ram::Ram,
    /// internal RAM
    iram:       ram::Ram,
    /// 0-page RAM
    zpage:      ram::Ram,
    /// Timer instance
    timer:      timer::Timer,
    /// GPU instance
    gpu:        Gpu<'a>,
    /// Used to store the value of IO Port when not properly
    /// implemented.
    io:         [u8, ..0x4c],
    /// Enabled interrupts
    it_enabled: Interrupts,
    /// Current DMA source address
    dma_src:    u16,
    /// Current DMA index in OAM
    dma_idx:    u16,
}

impl<'a> Interconnect<'a> {
    /// Create a new Interconnect
    pub fn new<'n>(rom: rom::Rom, gpu: Gpu<'n>) -> Interconnect<'n> {

        let ram = ram::Ram::new(0x2000);
        let iram = ram::Ram::new(0x2000);
        let zpage = ram::Ram::new(0x7f);
        let io = [0, ..0x4c];

        let timer = timer::Timer::new();

        let it_enabled = Interrupts::from_register(0);

        Interconnect { rom:        rom,
                       ram:        ram,
                       iram:       iram,
                       zpage:      zpage,
                       timer:      timer,
                       gpu:        gpu,
                       io:         io,
                       it_enabled: it_enabled,
                       dma_src:    0,
                       dma_idx:    map::range_size(map::OAM),
        }
    }

    pub fn reset(&mut self) {
        self.ram.reset();
        self.iram.reset();
        self.gpu.reset();
        self.zpage.reset();

        self.timer.reset();

        self.it_enabled = Interrupts::from_register(0);

        self.dma_src = 0;
        self.dma_idx = map::range_size(map::OAM);

        for b in self.io.iter_mut() {
            *b = 0;
        }
    }

    pub fn step(&mut self) {
        self.gpu.step();
        self.dma_step();
        self.timer.step();
    }

    pub fn dma_step(&mut self) {
        let end = map::range_size(map::OAM);

        if self.dma_idx >= end {
            // No dma transfer in progress
            return;
        }

        let b = self.get_byte(self.dma_src);
        self.gpu.set_oam(self.dma_idx, b);

        self.dma_src += 1;
        self.dma_idx += 1;
    }

    /// Get byte from peripheral mapped at `addr`
    pub fn get_byte(&self, addr: u16) -> u8 {

        if let Some(off) = map::in_range(addr, map::ROM) {
            return self.rom.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::VRAM) {
            return self.gpu.get_vram(off);
        }

        if let Some(off) = map::in_range(addr, map::RAM_BANK) {
            return self.ram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::IRAM) {
            return self.iram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::IRAM_ECHO) {
            return self.iram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::OAM) {
            return self.gpu.get_oam(off);
        }

        if let Some(off) = map::in_range(addr, map::IO) {
            return self.get_io(off);
        }

        if let Some(off) = map::in_range(addr, map::ZERO_PAGE) {
            return self.zpage.get_byte(off);
        }

        if addr == map::IEN {
            return self.it_enabled.as_register();
        }

        println!("Read from unmapped memory {:04x}", addr);
        0
    }

    /// Store `val` into peripheral mapped at `addr`
    pub fn set_byte(&mut self, addr: u16, val: u8) {
        if let Some(_) = map::in_range(addr, map::ROM) {
            println!("Writing to ROM: {:04x}: {:02x}", addr, val);
        }

        if let Some(off) = map::in_range(addr, map::VRAM) {
            return self.gpu.set_vram(off, val);
        }

        if let Some(off) = map::in_range(addr, map::RAM_BANK) {
            return self.ram.set_byte(off, val);
        }

        if let Some(off) = map::in_range(addr, map::IRAM) {
            return self.iram.set_byte(off, val);
        }

        if let Some(off) = map::in_range(addr, map::IRAM_ECHO) {
            return self.iram.set_byte(off, val);
        }

        if let Some(off) = map::in_range(addr, map::OAM) {
            return self.gpu.set_oam(off, val);
        }

        if let Some(off) = map::in_range(addr, map::IO) {
            return self.set_io(off, val);
        }

        if let Some(off) = map::in_range(addr, map::ZERO_PAGE) {
            return self.zpage.set_byte(off, val);
        }

        if addr == map::IEN {
            return self.it_enabled = Interrupts::from_register(val);
        }

        println!("Write to unmapped memory {:04x}: {:02x}", addr, val);
    }

    /// Return the highest priority `Interrupt` (after acknowledging it)
    /// currently triggered. If no interrupt is pending return `None`.
    pub fn next_interrupt(&mut self) -> Option<Interrupt> {
        if self.it_enabled.vblank && self.gpu.it_vblank() {
            self.gpu.ack_it_vblank();
            Some(VBlank)
        } else if self.it_enabled.lcdc && self.gpu.it_lcd() {
            self.gpu.ack_it_lcd();
            Some(Lcdc)
        } else if self.it_enabled.timer && self.timer.interrupt() {
            self.timer.ack_interrupt();
            Some(Timer)
        } else {
            None
        }
    }

    /// Retrieve value from IO port
    fn get_io(&self, addr: u16) -> u8 {
        match addr {
            io_map::DIV => {
                return self.timer.div();
            }
            io_map::TIMA => {
                return self.timer.counter();
            }
            io_map::TMA => {
                return self.timer.modulo();
            }
            io_map::TAC => {
                return self.timer.config();
            }
            io_map::DMA => {
                return self.dma_addr();
            }
            io_map::IF => {
                return Interrupts {
                    vblank: self.gpu.it_vblank(),
                    lcdc:   false,
                    timer:  false,
                    serial: false,
                    button: false,
                }.as_register();
            }
            io_map::LCD_STAT => {
                return self.gpu.stat()
            }
            io_map::LCD_SCY => {
                return self.gpu.scy()
            }
            io_map::LCD_SCX => {
                return self.gpu.scx()
            }
            io_map::LCDC => {
                return self.gpu.lcdc()
            }
            io_map::LCD_LY => {
                return self.gpu.line()
            }
            io_map::LCD_LYC => {
                return self.gpu.lyc()
            }
            io_map::LCD_BGP => {
                return self.gpu.bgp()
            }
            io_map::LCD_WY => {
                return self.gpu.wy()
            }
            io_map::LCD_WX => {
                return self.gpu.wx()
            }
            _ => {
                println!("Unhandled IO read from 0x{:04x}", 0xff00 | addr);
            }
        }

        self.io[(addr & 0xff) as uint]
    }

    /// Set value of IO port
    fn set_io(&mut self, addr: u16, val: u8) {
        self.io[(addr & 0xff) as uint] = val;

        match addr {
            io_map::DIV => {
                return self.timer.reset_div();
            }
            io_map::TIMA => {
                return self.timer.set_counter(val);
            }
            io_map::TMA => {
                return self.timer.set_modulo(val);
            }
            io_map::TAC => {
                return self.timer.set_config(val);
            }
            io_map::DMA => {
                return self.start_dma(val);
            }
            io_map::IF => {
                let f = Interrupts::from_register(val);

                self.gpu.force_it_vblank(f.vblank);
                self.gpu.force_it_lcd(f.lcdc);
            }
            io_map::LCD_STAT => {
                return self.gpu.set_stat(val);
            }
            io_map::LCD_SCY => {
                return self.gpu.set_scy(val);
            }
            io_map::LCD_SCX => {
                return self.gpu.set_scx(val);
            }
            io_map::LCDC => {
                return self.gpu.set_lcdc(val);
            },
            io_map::LCD_LY => {
                // Read Only
            },
            io_map::LCD_LYC => {
                return self.gpu.set_lyc(val);
            }
            io_map::LCD_BGP => {
                return self.gpu.set_bgp(val);
            }
            io_map::LCD_WY => {
                return self.gpu.set_wy(val);
            }
            io_map::LCD_WX => {
                return self.gpu.set_wx(val);
            }
            _ => {
                println!("Unhandled IO write to 0x{:04x}: 0x{:02x}",
                         0xff00 | addr, val);
            }
        }
    }

    /// Return the base of the last DMA transfer (only the high byte,
    /// the low byte is always 0)
    fn dma_addr(&self) -> u8 {
        (self.dma_src >> 8) as u8
    }

    /// Start a new transfer from (`src` << 8) into OAM
    fn start_dma(&mut self, src: u8) {
        self.dma_idx = 0;
        self.dma_src = (src as u16) << 8;

        self.dma_step();
    }
}

/// The various sources of interrupt, from highest to lowest priority
pub enum Interrupt {
    /// GPU entered vertical blanking
    VBlank,
    /// Configurable LCD Controller interrupt
    Lcdc,
    /// Timer overflow
    Timer,
    // TODO: implement other interrupts
}

/// GB Interrupts, from highest to lowest priority
struct Interrupts {
    /// GPU entered vertical blanking
    vblank: bool,
    /// Configurable LCDC interrupt
    lcdc:   bool,
    /// Timer overflow interrupt
    timer:  bool,
    /// Serial I/O done
    serial: bool,
    /// P10-13 transited from high to low (user pressed button)
    button: bool,
}

impl Interrupts {
    /// Convert IE/IF register to Interrupt struct
    fn from_register(reg: u8) -> Interrupts {
        Interrupts {
            vblank: reg & 0x01 != 0,
            lcdc:   reg & 0x02 != 0,
            timer:  reg & 0x04 != 0,
            serial: reg & 0x08 != 0,
            button: reg & 0x10 != 0,
        }
    }

    /// Convert Interrupts into IE/IF register
    fn as_register(&self) -> u8 {
        let mut r = 0;

        r |= (self.vblank as u8) << 0;
        r |= (self.lcdc   as u8) << 1;
        r |= (self.timer  as u8) << 2;
        r |= (self.serial as u8) << 3;
        r |= (self.button as u8) << 4;

        r
    }
}

mod map {
    //! Game Boy memory map. Memory ranges are inclusive.

    /// ROM
    pub const ROM:       (u16, u16) = (0x0000, 0x7fff);
    /// Video RAM
    pub const VRAM:      (u16, u16) = (0x8000, 0x9fff);
    /// RAM Bank N
    pub const RAM_BANK:  (u16, u16) = (0xa000, 0xbfff);
    /// Internal RAM
    pub const IRAM:      (u16, u16) = (0xc000, 0xdfff);
    /// Internal RAM echo
    pub const IRAM_ECHO: (u16, u16) = (0xe000, 0xfdff);
    /// Object Attribute Memory
    pub const OAM:       (u16, u16) = (0xfe00, 0xfe9f);
    /// IO ports
    pub const IO:        (u16, u16) = (0xff00, 0xff4b);
    /// Zero page memory
    pub const ZERO_PAGE: (u16, u16) = (0xff80, 0xfffe);
    /// Interrupt Enable register
    pub const IEN:       u16        = 0xffff;

    /// Return `Some(offset)` if the given address is in the inclusive
    /// range `range`, Where `offset` is an u16 equal to the offset of
    /// `addr` within the `range`.
    pub fn in_range(addr: u16, range: (u16, u16)) -> Option<u16> {
        let (first, last) = range;

        if addr >= first && addr <= last {
            Some(addr - first)
        } else {
            None
        }
    }

    /// Return the size of `range` in bytes
    pub fn range_size(range: (u16, u16)) -> u16 {
        let (first, last) = range;

        return last - first + 1;
    }
}

mod io_map {
    //! IO Address Map (offset from 0xff00)

    /// 16.384kHz free-running counter. Writing to it resets it to 0.
    pub const DIV:      u16 = 0x04;
    /// Configurable timer counter
    pub const TIMA:     u16 = 0x05;
    /// Configurable timer modulo (value reloaded in the counter after
    /// oveflow)
    pub const TMA:      u16 = 0x06;
    /// Timer control register
    pub const TAC:      u16 = 0x07;
    /// Interrupt Flag register
    pub const IF:       u16 = 0x0f;
    /// LCD Control
    pub const LCDC:     u16 = 0x40;
    /// LCDC Status + IT selection
    pub const LCD_STAT: u16 = 0x41;
    /// LCDC Background Y position
    pub const LCD_SCY:  u16 = 0x42;
    /// LCDC Background X position
    pub const LCD_SCX:  u16 = 0x43;
    /// Currently displayed line
    pub const LCD_LY:   u16 = 0x44;
    /// Currently line compare
    pub const LCD_LYC:  u16 = 0x45;
    /// DMA transfer from ROM/RAM to OAM
    pub const DMA:      u16 = 0x46;
    /// Background palette
    pub const LCD_BGP:  u16 = 0x47;
    /// Window Y position
    pub const LCD_WY:   u16 = 0x4a;
    /// Window X position + 7
    pub const LCD_WX:   u16 = 0x4b;

}
<commit_msg>Fix bogus message when writing to ROM<commit_after>//! Input/Output abstraction for memory, ROM and I/O mapped registers

use gpu::Gpu;

pub mod rom;
pub mod ram;
pub mod timer;

/// Interconnect struct used by the CPU and GPU to access the ROM, RAM
/// and registers
pub struct Interconnect<'a> {
    rom:        rom::Rom,
    /// Bankable RAM
    ram:        ram::Ram,
    /// internal RAM
    iram:       ram::Ram,
    /// 0-page RAM
    zpage:      ram::Ram,
    /// Timer instance
    timer:      timer::Timer,
    /// GPU instance
    gpu:        Gpu<'a>,
    /// Used to store the value of IO Port when not properly
    /// implemented.
    io:         [u8, ..0x4c],
    /// Enabled interrupts
    it_enabled: Interrupts,
    /// Current DMA source address
    dma_src:    u16,
    /// Current DMA index in OAM
    dma_idx:    u16,
}

impl<'a> Interconnect<'a> {
    /// Create a new Interconnect
    pub fn new<'n>(rom: rom::Rom, gpu: Gpu<'n>) -> Interconnect<'n> {

        let ram = ram::Ram::new(0x2000);
        let iram = ram::Ram::new(0x2000);
        let zpage = ram::Ram::new(0x7f);
        let io = [0, ..0x4c];

        let timer = timer::Timer::new();

        let it_enabled = Interrupts::from_register(0);

        Interconnect { rom:        rom,
                       ram:        ram,
                       iram:       iram,
                       zpage:      zpage,
                       timer:      timer,
                       gpu:        gpu,
                       io:         io,
                       it_enabled: it_enabled,
                       dma_src:    0,
                       dma_idx:    map::range_size(map::OAM),
        }
    }

    pub fn reset(&mut self) {
        self.ram.reset();
        self.iram.reset();
        self.gpu.reset();
        self.zpage.reset();

        self.timer.reset();

        self.it_enabled = Interrupts::from_register(0);

        self.dma_src = 0;
        self.dma_idx = map::range_size(map::OAM);

        for b in self.io.iter_mut() {
            *b = 0;
        }
    }

    pub fn step(&mut self) {
        self.gpu.step();
        self.dma_step();
        self.timer.step();
    }

    pub fn dma_step(&mut self) {
        let end = map::range_size(map::OAM);

        if self.dma_idx >= end {
            // No dma transfer in progress
            return;
        }

        let b = self.get_byte(self.dma_src);
        self.gpu.set_oam(self.dma_idx, b);

        self.dma_src += 1;
        self.dma_idx += 1;
    }

    /// Get byte from peripheral mapped at `addr`
    pub fn get_byte(&self, addr: u16) -> u8 {

        if let Some(off) = map::in_range(addr, map::ROM) {
            return self.rom.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::VRAM) {
            return self.gpu.get_vram(off);
        }

        if let Some(off) = map::in_range(addr, map::RAM_BANK) {
            return self.ram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::IRAM) {
            return self.iram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::IRAM_ECHO) {
            return self.iram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::OAM) {
            return self.gpu.get_oam(off);
        }

        if let Some(off) = map::in_range(addr, map::IO) {
            return self.get_io(off);
        }

        if let Some(off) = map::in_range(addr, map::ZERO_PAGE) {
            return self.zpage.get_byte(off);
        }

        if addr == map::IEN {
            return self.it_enabled.as_register();
        }

        println!("Read from unmapped memory {:04x}", addr);
        0
    }

    /// Store `val` into peripheral mapped at `addr`
    pub fn set_byte(&mut self, addr: u16, val: u8) {
        if let Some(_) = map::in_range(addr, map::ROM) {
            println!("Writing to ROM: {:04x}: {:02x}", addr, val);
            return;
        }

        if let Some(off) = map::in_range(addr, map::VRAM) {
            return self.gpu.set_vram(off, val);
        }

        if let Some(off) = map::in_range(addr, map::RAM_BANK) {
            return self.ram.set_byte(off, val);
        }

        if let Some(off) = map::in_range(addr, map::IRAM) {
            return self.iram.set_byte(off, val);
        }

        if let Some(off) = map::in_range(addr, map::IRAM_ECHO) {
            return self.iram.set_byte(off, val);
        }

        if let Some(off) = map::in_range(addr, map::OAM) {
            return self.gpu.set_oam(off, val);
        }

        if let Some(off) = map::in_range(addr, map::IO) {
            return self.set_io(off, val);
        }

        if let Some(off) = map::in_range(addr, map::ZERO_PAGE) {
            return self.zpage.set_byte(off, val);
        }

        if addr == map::IEN {
            return self.it_enabled = Interrupts::from_register(val);
        }

        println!("Write to unmapped memory {:04x}: {:02x}", addr, val);
    }

    /// Return the highest priority `Interrupt` (after acknowledging it)
    /// currently triggered. If no interrupt is pending return `None`.
    pub fn next_interrupt(&mut self) -> Option<Interrupt> {
        if self.it_enabled.vblank && self.gpu.it_vblank() {
            self.gpu.ack_it_vblank();
            Some(VBlank)
        } else if self.it_enabled.lcdc && self.gpu.it_lcd() {
            self.gpu.ack_it_lcd();
            Some(Lcdc)
        } else if self.it_enabled.timer && self.timer.interrupt() {
            self.timer.ack_interrupt();
            Some(Timer)
        } else {
            None
        }
    }

    /// Retrieve value from IO port
    fn get_io(&self, addr: u16) -> u8 {
        match addr {
            io_map::DIV => {
                return self.timer.div();
            }
            io_map::TIMA => {
                return self.timer.counter();
            }
            io_map::TMA => {
                return self.timer.modulo();
            }
            io_map::TAC => {
                return self.timer.config();
            }
            io_map::DMA => {
                return self.dma_addr();
            }
            io_map::IF => {
                return Interrupts {
                    vblank: self.gpu.it_vblank(),
                    lcdc:   false,
                    timer:  false,
                    serial: false,
                    button: false,
                }.as_register();
            }
            io_map::LCD_STAT => {
                return self.gpu.stat()
            }
            io_map::LCD_SCY => {
                return self.gpu.scy()
            }
            io_map::LCD_SCX => {
                return self.gpu.scx()
            }
            io_map::LCDC => {
                return self.gpu.lcdc()
            }
            io_map::LCD_LY => {
                return self.gpu.line()
            }
            io_map::LCD_LYC => {
                return self.gpu.lyc()
            }
            io_map::LCD_BGP => {
                return self.gpu.bgp()
            }
            io_map::LCD_WY => {
                return self.gpu.wy()
            }
            io_map::LCD_WX => {
                return self.gpu.wx()
            }
            _ => {
                println!("Unhandled IO read from 0x{:04x}", 0xff00 | addr);
            }
        }

        self.io[(addr & 0xff) as uint]
    }

    /// Set value of IO port
    fn set_io(&mut self, addr: u16, val: u8) {
        self.io[(addr & 0xff) as uint] = val;

        match addr {
            io_map::DIV => {
                return self.timer.reset_div();
            }
            io_map::TIMA => {
                return self.timer.set_counter(val);
            }
            io_map::TMA => {
                return self.timer.set_modulo(val);
            }
            io_map::TAC => {
                return self.timer.set_config(val);
            }
            io_map::DMA => {
                return self.start_dma(val);
            }
            io_map::IF => {
                let f = Interrupts::from_register(val);

                self.gpu.force_it_vblank(f.vblank);
                self.gpu.force_it_lcd(f.lcdc);
            }
            io_map::LCD_STAT => {
                return self.gpu.set_stat(val);
            }
            io_map::LCD_SCY => {
                return self.gpu.set_scy(val);
            }
            io_map::LCD_SCX => {
                return self.gpu.set_scx(val);
            }
            io_map::LCDC => {
                return self.gpu.set_lcdc(val);
            },
            io_map::LCD_LY => {
                // Read Only
            },
            io_map::LCD_LYC => {
                return self.gpu.set_lyc(val);
            }
            io_map::LCD_BGP => {
                return self.gpu.set_bgp(val);
            }
            io_map::LCD_WY => {
                return self.gpu.set_wy(val);
            }
            io_map::LCD_WX => {
                return self.gpu.set_wx(val);
            }
            _ => {
                println!("Unhandled IO write to 0x{:04x}: 0x{:02x}",
                         0xff00 | addr, val);
            }
        }
    }

    /// Return the base of the last DMA transfer (only the high byte,
    /// the low byte is always 0)
    fn dma_addr(&self) -> u8 {
        (self.dma_src >> 8) as u8
    }

    /// Start a new transfer from (`src` << 8) into OAM
    fn start_dma(&mut self, src: u8) {
        self.dma_idx = 0;
        self.dma_src = (src as u16) << 8;

        self.dma_step();
    }
}

/// The various sources of interrupt, from highest to lowest priority
pub enum Interrupt {
    /// GPU entered vertical blanking
    VBlank,
    /// Configurable LCD Controller interrupt
    Lcdc,
    /// Timer overflow
    Timer,
    // TODO: implement other interrupts
}

/// GB Interrupts, from highest to lowest priority
struct Interrupts {
    /// GPU entered vertical blanking
    vblank: bool,
    /// Configurable LCDC interrupt
    lcdc:   bool,
    /// Timer overflow interrupt
    timer:  bool,
    /// Serial I/O done
    serial: bool,
    /// P10-13 transited from high to low (user pressed button)
    button: bool,
}

impl Interrupts {
    /// Convert IE/IF register to Interrupt struct
    fn from_register(reg: u8) -> Interrupts {
        Interrupts {
            vblank: reg & 0x01 != 0,
            lcdc:   reg & 0x02 != 0,
            timer:  reg & 0x04 != 0,
            serial: reg & 0x08 != 0,
            button: reg & 0x10 != 0,
        }
    }

    /// Convert Interrupts into IE/IF register
    fn as_register(&self) -> u8 {
        let mut r = 0;

        r |= (self.vblank as u8) << 0;
        r |= (self.lcdc   as u8) << 1;
        r |= (self.timer  as u8) << 2;
        r |= (self.serial as u8) << 3;
        r |= (self.button as u8) << 4;

        r
    }
}

mod map {
    //! Game Boy memory map. Memory ranges are inclusive.

    /// ROM
    pub const ROM:       (u16, u16) = (0x0000, 0x7fff);
    /// Video RAM
    pub const VRAM:      (u16, u16) = (0x8000, 0x9fff);
    /// RAM Bank N
    pub const RAM_BANK:  (u16, u16) = (0xa000, 0xbfff);
    /// Internal RAM
    pub const IRAM:      (u16, u16) = (0xc000, 0xdfff);
    /// Internal RAM echo
    pub const IRAM_ECHO: (u16, u16) = (0xe000, 0xfdff);
    /// Object Attribute Memory
    pub const OAM:       (u16, u16) = (0xfe00, 0xfe9f);
    /// IO ports
    pub const IO:        (u16, u16) = (0xff00, 0xff4b);
    /// Zero page memory
    pub const ZERO_PAGE: (u16, u16) = (0xff80, 0xfffe);
    /// Interrupt Enable register
    pub const IEN:       u16        = 0xffff;

    /// Return `Some(offset)` if the given address is in the inclusive
    /// range `range`, Where `offset` is an u16 equal to the offset of
    /// `addr` within the `range`.
    pub fn in_range(addr: u16, range: (u16, u16)) -> Option<u16> {
        let (first, last) = range;

        if addr >= first && addr <= last {
            Some(addr - first)
        } else {
            None
        }
    }

    /// Return the size of `range` in bytes
    pub fn range_size(range: (u16, u16)) -> u16 {
        let (first, last) = range;

        return last - first + 1;
    }
}

mod io_map {
    //! IO Address Map (offset from 0xff00)

    /// 16.384kHz free-running counter. Writing to it resets it to 0.
    pub const DIV:      u16 = 0x04;
    /// Configurable timer counter
    pub const TIMA:     u16 = 0x05;
    /// Configurable timer modulo (value reloaded in the counter after
    /// oveflow)
    pub const TMA:      u16 = 0x06;
    /// Timer control register
    pub const TAC:      u16 = 0x07;
    /// Interrupt Flag register
    pub const IF:       u16 = 0x0f;
    /// LCD Control
    pub const LCDC:     u16 = 0x40;
    /// LCDC Status + IT selection
    pub const LCD_STAT: u16 = 0x41;
    /// LCDC Background Y position
    pub const LCD_SCY:  u16 = 0x42;
    /// LCDC Background X position
    pub const LCD_SCX:  u16 = 0x43;
    /// Currently displayed line
    pub const LCD_LY:   u16 = 0x44;
    /// Currently line compare
    pub const LCD_LYC:  u16 = 0x45;
    /// DMA transfer from ROM/RAM to OAM
    pub const DMA:      u16 = 0x46;
    /// Background palette
    pub const LCD_BGP:  u16 = 0x47;
    /// Window Y position
    pub const LCD_WY:   u16 = 0x4a;
    /// Window X position + 7
    pub const LCD_WX:   u16 = 0x4b;

}
<|endoftext|>


<commit_before>use std::os::unix::io::RawFd;
use std::collections::HashMap;
use std::slice;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::os::unix::io::AsRawFd;
use nix::sys::event::{ev_set, kqueue, kevent, KEvent, EventFilter, EventFlag, FilterFlag};
use libc::{uintptr_t, intptr_t};
use std::io::Result;
use event::Event;
use notification::Notification;
use user_event::UserEvent;
use nix_err_to_io_err;

type UserData = intptr_t;

static KQUEUE_EVENT_SIZE: usize = 1024;

pub struct KernelPoller {
    kqueue: RawFd,
    registrar: KernelRegistrar,
    eventlist: Vec<KEvent>,
    notifications: HashMap<RawFd, Notification>
}

impl KernelPoller {
    pub fn new() -> Result<KernelPoller> {
        let kq = kqueue().map_err(nix_err_to_io_err)?;
        let registrations = Arc::new(AtomicUsize::new(1));
        Ok(KernelPoller {
            kqueue: kq,
            registrar: KernelRegistrar::new(kq, registrations),
            eventlist: Vec::with_capacity(KQUEUE_EVENT_SIZE),
            notifications: HashMap::with_capacity(KQUEUE_EVENT_SIZE)
        })
    }

    // This will always succeed. We implement it this way for api compatibility with epoll.
    pub fn get_registrar(&self) -> Result<KernelRegistrar> {
        Ok(self.registrar.clone())
    }

    // Wait for kevents and return a list of Notifications. Coalesce reads and writes for the same
    // socket into a single notification. If only a read or a write event for a given socket is
    // present in the eventlist, check the registration to see if there is another kevent registered
    //  and remove it if so. We do this removal to prevent aliasing a pointer to the same
    // registration structure.
    pub fn wait(&mut self, timeout_ms: usize) -> Result<Vec<Notification>> {

        // Create a buffer to read events into
        let dst = unsafe {
            slice::from_raw_parts_mut(self.eventlist.as_mut_ptr(), self.eventlist.capacity())
        };

        let count = kevent(self.kqueue, &[], dst, timeout_ms).map_err(nix_err_to_io_err)?;

        // Set the length of the vector to the number of events that was returned by kevent
        unsafe { self.eventlist.set_len(count); }

        self.coalesce_events();
        Ok(self.notifications.drain().map(|(_, v)| v).collect())
    }

    // Combine read and write events for the same socket into a single notification.
    fn coalesce_events(&mut self) {
        for e in self.eventlist.drain(..) {
            let event = event_from_filter(e.filter());
            let new_notification = Notification {
                id: e.udata() as usize,
                event: event.clone()
            };

            let mut notification = self.notifications.entry(e.ident() as RawFd)
                                                     .or_insert(new_notification);
            if notification.event != event {
                notification.event = Event::Both
            }
        }
    }
}

#[derive(Debug, Clone)]
pub struct KernelRegistrar {
    kqueue: RawFd,
    total_registrations: Arc<AtomicUsize>
}

impl KernelRegistrar {
    // Explicitly not public. KernelRegistrar's are tied to KernelPollers and are retreived via
    // calls to poller.get_registrar().
    fn new(kq: RawFd, registrations: Arc<AtomicUsize>) -> KernelRegistrar {
        KernelRegistrar {
            kqueue: kq,
            total_registrations: registrations
        }
    }

    // This will always succeed. We implement this to provide api compatibility with epoll.
    pub fn try_clone(&self) -> Result<KernelRegistrar> {
        Ok(self.clone())
    }

    pub fn register<T: AsRawFd>(&self, sock: &T, event: Event) -> Result<usize> {
        let sock_fd = sock.as_raw_fd();
        let id = self.total_registrations.fetch_add(1, Ordering::SeqCst);
        let changes = make_changelist(sock_fd, event, id as UserData);
        kevent(self.kqueue, &changes, &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(id)
    }

    pub fn reregister<T: AsRawFd>(&self, id: usize, sock: &T, event: Event) -> Result<()> {
        let sock_fd = sock.as_raw_fd();
        let changes = make_changelist(sock_fd, event, id as UserData);
        kevent(self.kqueue, &changes, &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    pub fn deregister<T: AsRawFd>(&self, sock: &T) -> Result<()> {
        let sock_fd = sock.as_raw_fd();
        let mut changes = make_changelist(sock_fd, Event::Both, 0);
        for e in changes.iter_mut() {
            set_flags(e, EventFlag::EV_DELETE);
        }
        // Just ignore errors because, one of the events may not be present, but the deregister
        // signature ignores that fact. At this point, ownership of the socket is taken so it's
        // irrelevant anyway.
        let _ = kevent(self.kqueue, &changes, &mut[], 0);
        Ok(())
    }

    pub fn register_user_event(&mut self) -> Result<UserEvent> {
        let id = self.total_registrations.fetch_add(1, Ordering::SeqCst);
        let changes = vec![make_user_event(id)];
        kevent(self.kqueue, &changes, &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(UserEvent {id: id, registrar: self.clone()})
    }

    pub fn trigger_user_event(&self, event: &UserEvent) -> Result<()> {
        let mut e = make_user_event(event.get_id());
        set_fflags(&mut e, FilterFlag::NOTE_TRIGGER);
        kevent(self.kqueue, &vec![e], &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    pub fn clear_user_event(&self, event: &UserEvent) -> Result<()> {
        let mut user_event = make_user_event(event.get_id());
        set_flags(&mut user_event, EventFlag::EV_DISABLE);
        kevent(self.kqueue, &vec![user_event], &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    pub fn deregister_user_event(&self, event_id: usize) -> Result<()> {
        let mut user_event = make_user_event(event_id);
        set_flags(&mut user_event, EventFlag::EV_DELETE);
        kevent(self.kqueue, &vec![user_event], &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    pub fn set_timeout(&self, timeout: usize) -> Result<usize> {
        self.set_timer(timeout, false)
    }

    pub fn set_interval(&self, timeout: usize) -> Result<usize> {
        self.set_timer(timeout, true)
    }

    pub fn cancel_timeout(&self, timer_id: usize) -> Result<()> {
        let mut e = make_timer(timer_id, 0, false);
        set_flags(&mut e, EventFlag::EV_DELETE);
        kevent(self.kqueue, &vec![e], &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    fn set_timer(&self, timeout: usize, recurring: bool) -> Result<usize> {
        let id = self.total_registrations.fetch_add(1, Ordering::SeqCst);
        let changes = vec![make_timer(id, timeout, recurring)];
        kevent(self.kqueue, &changes, &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(id)
    }
}

fn event_from_filter(filter: EventFilter) -> Event {
    // TODO: Change Event to allow returning TIMER events instead of marking them READ
    if filter == EventFilter::EVFILT_READ ||
       filter == EventFilter::EVFILT_TIMER ||
       filter == EventFilter::EVFILT_USER {
        Event::Read
    } else {
        Event::Write
    }
}

// Each event in kqueue must have its own filter. In other words, there are seperate events for
// reads and writes on the same socket. We create the proper number of KEvents based on the enum
// variant in the `event` paramter.
fn make_changelist(sock_fd: RawFd, event: Event, user_data: UserData) -> Vec<KEvent> {
    let mut ev = KEvent::new(
        sock_fd as uintptr_t,
        EventFilter::EVFILT_READ,
        EventFlag::EV_ADD | EventFlag::EV_CLEAR,
        FilterFlag::empty(),
        0,
        user_data
    );

    match event {
        Event::Read => vec![ev],
        Event::Write => {
            set_filter(&mut ev, EventFilter::EVFILT_WRITE);
            vec![KEvent::new(ev.ident(), EventFilter::EVFILT_WRITE, ev.flags(), ev.fflags(), ev.data(), ev.udata())]
        },
        Event::Both => vec![ev, KEvent::new(ev.ident(), EventFilter::EVFILT_WRITE, ev.flags(), ev.fflags(), ev.data(), ev.udata())]
    }
}

fn make_user_event(id: usize) -> KEvent {
    KEvent::new(
        id as uintptr_t,
        EventFilter::EVFILT_USER,
        EventFlag::EV_ADD | EventFlag::EV_CLEAR | EventFlag::EV_ENABLE,
        FilterFlag::empty(),
        0,
        id as UserData
    )
}

fn set_filter(e: &mut KEvent, filter: EventFilter) {
    let ident = e.ident();
    let flags = e.flags();
    let fflags = e.fflags();
    let udata = e.udata();
    ev_set(e, ident, filter, flags, fflags, udata);
}

fn set_flags(e: &mut KEvent, flags: EventFlag) {
    let ident = e.ident();
    let filter = e.filter();
    let fflags = e.fflags();
    let udata = e.udata();
    ev_set(e, ident, filter, flags, fflags, udata);
}

fn set_fflags(e: &mut KEvent, fflags: FilterFlag) {
    let ident = e.ident();
    let filter = e.filter();
    let flags = e.flags();
    let udata = e.udata();
    ev_set(e, ident, filter, flags, fflags, udata);
}

fn make_timer(id: usize, timeout: usize, recurring: bool) -> KEvent {
    let mut flags = EventFlag::EV_ADD;
    if !recurring {
        flags |= EventFlag::EV_ONESHOT;
    }
    let ev = KEvent::new(
        id as uintptr_t,
        EventFilter::EVFILT_TIMER,
        flags,
        FilterFlag::empty(), // timeouts are in ms by default
        timeout as intptr_t,
        id as UserData
    );
    ev
}
<commit_msg>Ensure user events are properly reported to kqueue<commit_after>use std::os::unix::io::RawFd;
use std::collections::HashMap;
use std::slice;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::os::unix::io::AsRawFd;
use nix::sys::event::{ev_set, kqueue, kevent, KEvent, EventFilter, EventFlag, FilterFlag};
use libc::{uintptr_t, intptr_t};
use std::io::Result;
use event::Event;
use notification::Notification;
use user_event::UserEvent;
use nix_err_to_io_err;

type UserData = intptr_t;

static KQUEUE_EVENT_SIZE: usize = 1024;

pub struct KernelPoller {
    kqueue: RawFd,
    registrar: KernelRegistrar,
    eventlist: Vec<KEvent>,
    notifications: HashMap<RawFd, Notification>
}

impl KernelPoller {
    pub fn new() -> Result<KernelPoller> {
        let kq = kqueue().map_err(nix_err_to_io_err)?;
        let registrations = Arc::new(AtomicUsize::new(1));
        Ok(KernelPoller {
            kqueue: kq,
            registrar: KernelRegistrar::new(kq, registrations),
            eventlist: Vec::with_capacity(KQUEUE_EVENT_SIZE),
            notifications: HashMap::with_capacity(KQUEUE_EVENT_SIZE)
        })
    }

    // This will always succeed. We implement it this way for api compatibility with epoll.
    pub fn get_registrar(&self) -> Result<KernelRegistrar> {
        Ok(self.registrar.clone())
    }

    // Wait for kevents and return a list of Notifications. Coalesce reads and writes for the same
    // socket into a single notification. If only a read or a write event for a given socket is
    // present in the eventlist, check the registration to see if there is another kevent registered
    //  and remove it if so. We do this removal to prevent aliasing a pointer to the same
    // registration structure.
    pub fn wait(&mut self, timeout_ms: usize) -> Result<Vec<Notification>> {

        // Create a buffer to read events into
        let dst = unsafe {
            slice::from_raw_parts_mut(self.eventlist.as_mut_ptr(), self.eventlist.capacity())
        };

        let count = kevent(self.kqueue, &[], dst, timeout_ms).map_err(nix_err_to_io_err)?;

        // Set the length of the vector to the number of events that was returned by kevent
        unsafe { self.eventlist.set_len(count); }

        self.coalesce_events();
        Ok(self.notifications.drain().map(|(_, v)| v).collect())
    }

    // Combine read and write events for the same socket into a single notification.
    fn coalesce_events(&mut self) {
        for e in self.eventlist.drain(..) {
            let event = event_from_filter(e.filter());
            let new_notification = Notification {
                id: e.udata() as usize,
                event: event.clone()
            };

            let mut notification = self.notifications.entry(e.ident() as RawFd)
                                                     .or_insert(new_notification);
            if notification.event != event {
                notification.event = Event::Both
            }
        }
    }
}

#[derive(Debug, Clone)]
pub struct KernelRegistrar {
    kqueue: RawFd,
    total_registrations: Arc<AtomicUsize>
}

impl KernelRegistrar {
    // Explicitly not public. KernelRegistrar's are tied to KernelPollers and are retreived via
    // calls to poller.get_registrar().
    fn new(kq: RawFd, registrations: Arc<AtomicUsize>) -> KernelRegistrar {
        KernelRegistrar {
            kqueue: kq,
            total_registrations: registrations
        }
    }

    // This will always succeed. We implement this to provide api compatibility with epoll.
    pub fn try_clone(&self) -> Result<KernelRegistrar> {
        Ok(self.clone())
    }

    pub fn register<T: AsRawFd>(&self, sock: &T, event: Event) -> Result<usize> {
        let sock_fd = sock.as_raw_fd();
        let id = self.total_registrations.fetch_add(1, Ordering::SeqCst);
        let changes = make_changelist(sock_fd, event, id as UserData);
        kevent(self.kqueue, &changes, &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(id)
    }

    pub fn reregister<T: AsRawFd>(&self, id: usize, sock: &T, event: Event) -> Result<()> {
        let sock_fd = sock.as_raw_fd();
        let changes = make_changelist(sock_fd, event, id as UserData);
        kevent(self.kqueue, &changes, &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    pub fn deregister<T: AsRawFd>(&self, sock: &T) -> Result<()> {
        let sock_fd = sock.as_raw_fd();
        let mut changes = make_changelist(sock_fd, Event::Both, 0);
        for e in changes.iter_mut() {
            set_flags(e, EventFlag::EV_DELETE);
        }
        // Just ignore errors because, one of the events may not be present, but the deregister
        // signature ignores that fact. At this point, ownership of the socket is taken so it's
        // irrelevant anyway.
        let _ = kevent(self.kqueue, &changes, &mut[], 0);
        Ok(())
    }

    pub fn register_user_event(&mut self) -> Result<UserEvent> {
        let id = self.total_registrations.fetch_add(1, Ordering::SeqCst);
        let changes = vec![make_user_event(id)];
        kevent(self.kqueue, &changes, &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(UserEvent {id: id, registrar: self.clone()})
    }

    pub fn trigger_user_event(&self, event: &UserEvent) -> Result<()> {
        let mut e = make_user_event(event.get_id());
        set_flags(&mut e, EventFlag::EV_ENABLE);
        set_fflags(&mut e, FilterFlag::NOTE_TRIGGER);
        kevent(self.kqueue, &vec![e], &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    pub fn clear_user_event(&self, event: &UserEvent) -> Result<()> {
        let mut user_event = make_user_event(event.get_id());
        set_flags(&mut user_event, EventFlag::EV_DISABLE);
        kevent(self.kqueue, &vec![user_event], &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    pub fn deregister_user_event(&self, event_id: usize) -> Result<()> {
        let mut user_event = make_user_event(event_id);
        set_flags(&mut user_event, EventFlag::EV_DELETE);
        kevent(self.kqueue, &vec![user_event], &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    pub fn set_timeout(&self, timeout: usize) -> Result<usize> {
        self.set_timer(timeout, false)
    }

    pub fn set_interval(&self, timeout: usize) -> Result<usize> {
        self.set_timer(timeout, true)
    }

    pub fn cancel_timeout(&self, timer_id: usize) -> Result<()> {
        let mut e = make_timer(timer_id, 0, false);
        set_flags(&mut e, EventFlag::EV_DELETE);
        kevent(self.kqueue, &vec![e], &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(())
    }

    fn set_timer(&self, timeout: usize, recurring: bool) -> Result<usize> {
        let id = self.total_registrations.fetch_add(1, Ordering::SeqCst);
        let changes = vec![make_timer(id, timeout, recurring)];
        kevent(self.kqueue, &changes, &mut[], 0).map_err(nix_err_to_io_err)?;
        Ok(id)
    }
}

fn event_from_filter(filter: EventFilter) -> Event {
    // TODO: Change Event to allow returning TIMER events instead of marking them READ
    if filter == EventFilter::EVFILT_READ ||
       filter == EventFilter::EVFILT_TIMER ||
       filter == EventFilter::EVFILT_USER {
        Event::Read
    } else {
        Event::Write
    }
}

// Each event in kqueue must have its own filter. In other words, there are seperate events for
// reads and writes on the same socket. We create the proper number of KEvents based on the enum
// variant in the `event` paramter.
fn make_changelist(sock_fd: RawFd, event: Event, user_data: UserData) -> Vec<KEvent> {
    let mut ev = KEvent::new(
        sock_fd as uintptr_t,
        EventFilter::EVFILT_READ,
        EventFlag::EV_ADD | EventFlag::EV_CLEAR,
        FilterFlag::empty(),
        0,
        user_data
    );

    match event {
        Event::Read => vec![ev],
        Event::Write => {
            set_filter(&mut ev, EventFilter::EVFILT_WRITE);
            vec![KEvent::new(ev.ident(), EventFilter::EVFILT_WRITE, ev.flags(), ev.fflags(), ev.data(), ev.udata())]
        },
        Event::Both => vec![ev, KEvent::new(ev.ident(), EventFilter::EVFILT_WRITE, ev.flags(), ev.fflags(), ev.data(), ev.udata())]
    }
}

fn make_user_event(id: usize) -> KEvent {
    KEvent::new(
        id as uintptr_t,
        EventFilter::EVFILT_USER,
        EventFlag::EV_ADD | EventFlag::EV_CLEAR | EventFlag::EV_ENABLE,
        FilterFlag::empty(),
        0,
        id as UserData
    )
}

fn set_filter(e: &mut KEvent, filter: EventFilter) {
    let ident = e.ident();
    let flags = e.flags();
    let fflags = e.fflags();
    let udata = e.udata();
    ev_set(e, ident, filter, flags, fflags, udata);
}

fn set_flags(e: &mut KEvent, flags: EventFlag) {
    let ident = e.ident();
    let filter = e.filter();
    let fflags = e.fflags();
    let udata = e.udata();
    ev_set(e, ident, filter, flags, fflags, udata);
}

fn set_fflags(e: &mut KEvent, fflags: FilterFlag) {
    let ident = e.ident();
    let filter = e.filter();
    let flags = e.flags();
    let udata = e.udata();
    ev_set(e, ident, filter, flags, fflags, udata);
}

fn make_timer(id: usize, timeout: usize, recurring: bool) -> KEvent {
    let mut flags = EventFlag::EV_ADD;
    if !recurring {
        flags |= EventFlag::EV_ONESHOT;
    }
    let ev = KEvent::new(
        id as uintptr_t,
        EventFilter::EVFILT_TIMER,
        flags,
        FilterFlag::empty(), // timeouts are in ms by default
        timeout as intptr_t,
        id as UserData
    );
    ev
}
<|endoftext|>


<commit_before>use chrono::prelude::Local;
use ansi_term::Colour::{Green, Red, Cyan, Yellow, Purple};

pub enum LogType {
    PASS,
    FAIL,
    INFO,
    WARN,
}
pub struct Logger {
    _pass: i32,
    _fail: i32,
    _warn: i32,
    _info: i32,
}
impl Logger {
    pub fn new() -> Logger {
        Logger {
            _pass: 0,
            _fail: 0,
            _warn: 0,
            _info: 0,
        }
    }
    fn log(&mut self, log_type: LogType, message: String) {
        let mark = match log_type {
            LogType::PASS => {
                self._pass += 1;
                Green.paint("PASS")
            }
            LogType::FAIL => {
                self._fail += 1;
                Red.paint("FAIL")
            }
            LogType::INFO => {
                self._info += 1;
                Cyan.paint("INFO")
            }
            LogType::WARN => {
                self._warn += 1;
                Yellow.paint("WARN")
            }
        };
        println!("{} {}: {}",
                 Purple.paint(Local::now().format("%Y-%m-%d %H:%M:%S").to_string()),
                 mark,
                 message);
    }
    pub fn pass(&mut self, message: String) {
        self.log(LogType::PASS, message);
    }
    pub fn fail(&mut self, message: String) {
        self.log(LogType::FAIL, message);
    }
    pub fn info(&mut self, message: String) {
        self.log(LogType::INFO, message);
    }
    pub fn warn(&mut self, message: String) {
        self.log(LogType::WARN, message);
    }
    pub fn get_num_pass(&self) -> i32 {
        self._pass
    }
    pub fn get_num_fail(&self) -> i32 {
        self._fail
    }
    pub fn get_num_warn(&self) -> i32 {
        self._warn
    }
    pub fn get_num_info(&self) -> i32 {
        self._info
    }
}
impl Drop for Logger {
    fn drop(&mut self) {
        let formatted_pass = format!("{} {}", self.get_num_pass(), Green.paint("PASS"));
        let formatted_fail = format!("{} {}", self.get_num_fail(), Red.paint("PASS"));
        let formatted_warn = format!("{} {}", self.get_num_warn(), Yellow.paint("PASS"));
        let formatted_info = format!("{} {}", self.get_num_info(), Cyan.paint("PASS"));
        println!("{}  {}  {}  {}",
                 formatted_pass,
                 formatted_fail,
                 formatted_warn,
                 formatted_info);
    }
}
<commit_msg>typo correction<commit_after>use chrono::prelude::Local;
use ansi_term::Colour::{Green, Red, Cyan, Yellow, Purple};

pub enum LogType {
    PASS,
    FAIL,
    INFO,
    WARN,
}
pub struct Logger {
    _pass: i32,
    _fail: i32,
    _warn: i32,
    _info: i32,
}
impl Logger {
    pub fn new() -> Logger {
        Logger {
            _pass: 0,
            _fail: 0,
            _warn: 0,
            _info: 0,
        }
    }
    fn log(&mut self, log_type: LogType, message: String) {
        let mark = match log_type {
            LogType::PASS => {
                self._pass += 1;
                Green.paint("PASS")
            }
            LogType::FAIL => {
                self._fail += 1;
                Red.paint("FAIL")
            }
            LogType::INFO => {
                self._info += 1;
                Cyan.paint("INFO")
            }
            LogType::WARN => {
                self._warn += 1;
                Yellow.paint("WARN")
            }
        };
        println!("{} {}: {}",
                 Purple.paint(Local::now().format("%Y-%m-%d %H:%M:%S").to_string()),
                 mark,
                 message);
    }
    pub fn pass(&mut self, message: String) {
        self.log(LogType::PASS, message);
    }
    pub fn fail(&mut self, message: String) {
        self.log(LogType::FAIL, message);
    }
    pub fn info(&mut self, message: String) {
        self.log(LogType::INFO, message);
    }
    pub fn warn(&mut self, message: String) {
        self.log(LogType::WARN, message);
    }
    pub fn get_num_pass(&self) -> i32 {
        self._pass
    }
    pub fn get_num_fail(&self) -> i32 {
        self._fail
    }
    pub fn get_num_warn(&self) -> i32 {
        self._warn
    }
    pub fn get_num_info(&self) -> i32 {
        self._info
    }
}
impl Drop for Logger {
    fn drop(&mut self) {
        let formatted_pass = format!("{} {}", self.get_num_pass(), Green.paint("PASS"));
        let formatted_fail = format!("{} {}", self.get_num_fail(), Red.paint("FAIL"));
        let formatted_warn = format!("{} {}", self.get_num_warn(), Yellow.paint("WARN"));
        let formatted_info = format!("{} {}", self.get_num_info(), Cyan.paint("INFO"));
        println!("{}  {}  {}  {}",
                 formatted_pass,
                 formatted_fail,
                 formatted_warn,
                 formatted_info);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

include!("../relm-state/src/macros.rs");
<commit_msg>Temporary fix to publish the crate<commit_after>/*
 * Copyright (c) 2017-2019 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/// Connect events to sending a message.
///
/// ## Rules
/// 1. Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// 3. Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// 4. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// ## Rules
/// 1. Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}

/// Connect an asynchronous method call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        // TODO: remove any use of Fragile when gio callbacks stop requiring Send.
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });
    }};
}

/// Connect an asynchronous function call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async_func {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

    }};
}

/// Like `connect_async!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_full {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}

/// Like `connect_async_func!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_func_full {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}
<|endoftext|>


<commit_before>//! Define trait for general matrix

use std::cmp::min;
use ndarray::prelude::*;
use ndarray::LinalgScalar;

use error::LapackError;
use qr::ImplQR;
use svd::ImplSVD;
use norm::ImplNorm;

/// Methods for general matrices
pub trait Matrix: Sized {
    type Scalar;
    type Vector;
    /// number of (rows, columns)
    fn size(&self) -> (usize, usize);
    /// Operator norm for L-1 norm
    fn norm_1(&self) -> Self::Scalar;
    /// Operator norm for L-inf norm
    fn norm_i(&self) -> Self::Scalar;
    /// Frobenius norm
    fn norm_f(&self) -> Self::Scalar;
    /// singular-value decomposition (SVD)
    fn svd(self) -> Result<(Self, Self::Vector, Self), LapackError>;
    fn qr(self) -> Result<(Self, Self), LapackError>;
}

impl<A> Matrix for Array<A, (Ix, Ix)>
    where A: ImplQR + ImplSVD + ImplNorm + LinalgScalar
{
    type Scalar = A;
    type Vector = Array<A, Ix>;
    fn size(&self) -> (usize, usize) {
        (self.rows(), self.cols())
    }
    fn norm_1(&self) -> Self::Scalar {
        let (m, n) = self.size();
        let strides = self.strides();
        if strides[0] > strides[1] {
            ImplNorm::norm_i(n, m, self.clone().into_raw_vec())
        } else {
            ImplNorm::norm_1(m, n, self.clone().into_raw_vec())
        }
    }
    fn norm_i(&self) -> Self::Scalar {
        let (m, n) = self.size();
        let strides = self.strides();
        if strides[0] > strides[1] {
            ImplNorm::norm_1(n, m, self.clone().into_raw_vec())
        } else {
            ImplNorm::norm_i(m, n, self.clone().into_raw_vec())
        }
    }
    fn norm_f(&self) -> Self::Scalar {
        let (m, n) = self.size();
        ImplNorm::norm_f(m, n, self.clone().into_raw_vec())
    }
    fn svd(self) -> Result<(Self, Self::Vector, Self), LapackError> {
        let strides = self.strides();
        let (m, n) = if strides[0] > strides[1] {
            self.size()
        } else {
            let (n, m) = self.size();
            (m, n)
        };
        let (u, s, vt) = try!(ImplSVD::svd(m, n, self.clone().into_raw_vec()));
        let sv = Array::from_vec(s);
        if strides[0] > strides[1] {
            let ua = Array::from_vec(u).into_shape((n, n)).unwrap();
            let va = Array::from_vec(vt).into_shape((m, m)).unwrap();
            Ok((va, sv, ua))
        } else {
            let ua = Array::from_vec(u).into_shape((n, n)).unwrap().reversed_axes();
            let va = Array::from_vec(vt).into_shape((m, m)).unwrap().reversed_axes();
            Ok((ua, sv, va))
        }
    }
    fn qr(self) -> Result<(Self, Self), LapackError> {
        let (n, m) = self.size();
        let strides = self.strides();
        let k = min(n, m);
        let (q, r) = if strides[0] < strides[1] {
            try!(ImplQR::qr(m, n, self.clone().into_raw_vec()))
        } else {
            try!(ImplQR::lq(n, m, self.clone().into_raw_vec()))
        };
        let (qa, ra) = if strides[0] < strides[1] {
            (Array::from_vec(q).into_shape((m, n)).unwrap().reversed_axes(),
             Array::from_vec(r).into_shape((m, n)).unwrap().reversed_axes())
        } else {
            (Array::from_vec(q).into_shape((n, m)).unwrap(),
             Array::from_vec(r).into_shape((n, m)).unwrap())
        };
        let qm = if m > k {
            let (qsl, _) = qa.view().split_at(Axis(1), k);
            qsl.to_owned()
        } else {
            qa
        };
        let mut rm = if n > k {
            let (rsl, _) = ra.view().split_at(Axis(0), k);
            rsl.to_owned()
        } else {
            ra
        };
        for ((i, j), val) in rm.indexed_iter_mut() {
            if i > j {
                *val = A::zero();
            }
        }
        Ok((qm, rm))
    }
}
<commit_msg>Add short doc<commit_after>//! Define trait for general matrix

use std::cmp::min;
use ndarray::prelude::*;
use ndarray::LinalgScalar;

use error::LapackError;
use qr::ImplQR;
use svd::ImplSVD;
use norm::ImplNorm;

/// Methods for general matrices
pub trait Matrix: Sized {
    type Scalar;
    type Vector;
    /// number of (rows, columns)
    fn size(&self) -> (usize, usize);
    /// Operator norm for L-1 norm
    fn norm_1(&self) -> Self::Scalar;
    /// Operator norm for L-inf norm
    fn norm_i(&self) -> Self::Scalar;
    /// Frobenius norm
    fn norm_f(&self) -> Self::Scalar;
    /// singular-value decomposition (SVD)
    fn svd(self) -> Result<(Self, Self::Vector, Self), LapackError>;
    /// QR decomposition
    fn qr(self) -> Result<(Self, Self), LapackError>;
}

impl<A> Matrix for Array<A, (Ix, Ix)>
    where A: ImplQR + ImplSVD + ImplNorm + LinalgScalar
{
    type Scalar = A;
    type Vector = Array<A, Ix>;
    fn size(&self) -> (usize, usize) {
        (self.rows(), self.cols())
    }
    fn norm_1(&self) -> Self::Scalar {
        let (m, n) = self.size();
        let strides = self.strides();
        if strides[0] > strides[1] {
            ImplNorm::norm_i(n, m, self.clone().into_raw_vec())
        } else {
            ImplNorm::norm_1(m, n, self.clone().into_raw_vec())
        }
    }
    fn norm_i(&self) -> Self::Scalar {
        let (m, n) = self.size();
        let strides = self.strides();
        if strides[0] > strides[1] {
            ImplNorm::norm_1(n, m, self.clone().into_raw_vec())
        } else {
            ImplNorm::norm_i(m, n, self.clone().into_raw_vec())
        }
    }
    fn norm_f(&self) -> Self::Scalar {
        let (m, n) = self.size();
        ImplNorm::norm_f(m, n, self.clone().into_raw_vec())
    }
    fn svd(self) -> Result<(Self, Self::Vector, Self), LapackError> {
        let strides = self.strides();
        let (m, n) = if strides[0] > strides[1] {
            self.size()
        } else {
            let (n, m) = self.size();
            (m, n)
        };
        let (u, s, vt) = try!(ImplSVD::svd(m, n, self.clone().into_raw_vec()));
        let sv = Array::from_vec(s);
        if strides[0] > strides[1] {
            let ua = Array::from_vec(u).into_shape((n, n)).unwrap();
            let va = Array::from_vec(vt).into_shape((m, m)).unwrap();
            Ok((va, sv, ua))
        } else {
            let ua = Array::from_vec(u).into_shape((n, n)).unwrap().reversed_axes();
            let va = Array::from_vec(vt).into_shape((m, m)).unwrap().reversed_axes();
            Ok((ua, sv, va))
        }
    }
    fn qr(self) -> Result<(Self, Self), LapackError> {
        let (n, m) = self.size();
        let strides = self.strides();
        let k = min(n, m);
        let (q, r) = if strides[0] < strides[1] {
            try!(ImplQR::qr(m, n, self.clone().into_raw_vec()))
        } else {
            try!(ImplQR::lq(n, m, self.clone().into_raw_vec()))
        };
        let (qa, ra) = if strides[0] < strides[1] {
            (Array::from_vec(q).into_shape((m, n)).unwrap().reversed_axes(),
             Array::from_vec(r).into_shape((m, n)).unwrap().reversed_axes())
        } else {
            (Array::from_vec(q).into_shape((n, m)).unwrap(),
             Array::from_vec(r).into_shape((n, m)).unwrap())
        };
        let qm = if m > k {
            let (qsl, _) = qa.view().split_at(Axis(1), k);
            qsl.to_owned()
        } else {
            qa
        };
        let mut rm = if n > k {
            let (rsl, _) = ra.view().split_at(Axis(0), k);
            rsl.to_owned()
        } else {
            ra
        };
        for ((i, j), val) in rm.indexed_iter_mut() {
            if i > j {
                *val = A::zero();
            }
        }
        Ok((qm, rm))
    }
}
<|endoftext|>


<commit_before>use super::*;
use std::collections::HashMap;
use std::collections::hash_map;
use std::iter;
//use linked_hash_map;
//use linked_hash_map::LinkedHashMap;

pub trait ModuleStruct<'a> {
	fn init_module(&mut self);
}

struct TorchBackend {}
pub struct Parameter<'a> {
	data: &'a mut Tensor,
}
impl <'a>Parameter<'a> {
	fn valid(&self) -> bool {
		true
	}
}

pub struct Module<'a> {
	pub _name: &'a str,
	_backend : TorchBackend,
//	_buffers: HashTable<&str, Tensor>
//	_backward_hooks:
//	_forward_hooks:
    //_modulesp: LinkedHashMap<&'a str, *mut Module<'a>>,
    _params: HashMap<&'a str, *mut Parameter<'a>>,
    _modulesp: HashMap<&'a str, *mut Module<'a>>,
	training: bool,
}
pub struct PtrIterMut<'a, T: 'a> {
	//mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
	mod_iter: hash_map::IterMut<'a, &'a str, *mut T>,
}

impl <'a, T>Iterator for PtrIterMut<'a, T> {
	type Item = (&'a str, &'a mut T);
	fn next(&mut self) -> Option<Self::Item> {
		if let Some((name, t)) = self.mod_iter.next() {
			Some((name, unsafe { &mut **t as &mut T}))
		} else {
			None
		}
	}
}

impl <'a>Module<'a> {
	pub fn new() -> Module<'a> {
		Module {_name: "", _backend: TorchBackend {}, _params: HashMap::new(),
		//_modulesp: LinkedHashMap::new(),
		_modulesp: HashMap::new(),
		training: true }
	}
	#[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<'a> {
        self as *mut Module<'a>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<'a>) {
    	let m = module.delegate();
    	self._modulesp.insert(m._name, m.as_mut_ptr());

    }
	pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<'a> > {
		PtrIterMut {mod_iter: self._modulesp.iter_mut()}
	}
	pub fn params_iter_mut(&mut self) -> PtrIterMut<Parameter<'a> > {
		PtrIterMut {mod_iter: self._params.iter_mut()}
	}
	fn _apply(&mut self, callback: fn(&mut Tensor))  {
		for (_, module) in self.modules_iter_mut() { module._apply(callback) }
		for param in self.params_iter_mut().filter_map(|(_, p)| {if p.valid() {Some(p)} else {None} }) {
			callback(param.data);
/*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
			/* see also _buffers */
		}
	}
	fn apply(&mut self, callback: fn(&mut Self)) {
		for (_, module) in self.modules_iter_mut() {
			module.apply(callback)
		}
		callback(self)
	}
	pub fn eval(&mut self) {
		self.train(false)
	}
	fn train(&mut self, mode: bool) {
		self.training = mode;
		for (_, module) in self.modules_iter_mut() {
			module.train(mode)
		}

	}
}

pub trait ModIntf<'a> {
	fn delegate(&mut self) -> &mut Module<'a>;
	fn forward(&mut self /* Tensor */ ) /* -> Tensor */;
}

#[derive(ModParse)]
pub struct Linear<'a> {
	delegate: Module<'a> ,
	in_features: u32,
}

impl <'a>Linear<'a> {
	pub fn new(/* args: LinearArgs */) -> Linear<'a> {
		let mut t = Linear {delegate: Module::new(), in_features: 0 };
		t.init_module();
		t
	}
}

impl <'a> ModIntf<'a> for Linear<'a>  {
	fn delegate(&mut self) -> &mut Module<'a> {
		&mut self.delegate
	}
	fn forward(&mut self/* Tensor */) /* -> Tensor */ {

	}
}

<commit_msg>rustfmt<commit_after>use super::*;
use std::collections::HashMap;
use std::collections::hash_map;
use std::iter;
//use linked_hash_map;
//use linked_hash_map::LinkedHashMap;

pub trait ModuleStruct<'a> {
    fn init_module(&mut self);
}

struct TorchBackend {}
pub struct Parameter<'a> {
    data: &'a mut Tensor,
}
impl<'a> Parameter<'a> {
    fn valid(&self) -> bool {
        true
    }
}

pub struct Module<'a> {
    pub _name: &'a str,
    _backend: TorchBackend,
    //	_buffers: HashTable<&str, Tensor>
    //	_backward_hooks:
    //	_forward_hooks:
    //_modulesp: LinkedHashMap<&'a str, *mut Module<'a>>,
    _params: HashMap<&'a str, *mut Parameter<'a>>,
    _modulesp: HashMap<&'a str, *mut Module<'a>>,
    training: bool,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, &'a str, *mut T>,
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a str, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

impl<'a> Module<'a> {
    pub fn new() -> Module<'a> {
        Module {
            _name: "",
            _backend: TorchBackend {},
            _params: HashMap::new(),
            //_modulesp: LinkedHashMap::new(),
            _modulesp: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<'a> {
        self as *mut Module<'a>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<'a>) {
        let m = module.delegate();
        self._modulesp.insert(m._name, m.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<'a>> {
        PtrIterMut { mod_iter: self._modulesp.iter_mut() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<Parameter<'a>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    fn _apply(&mut self, callback: fn(&mut Tensor)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for param in self.params_iter_mut()
                .filter_map(|(_, p)| if p.valid() { Some(p) } else { None }) {
            callback(param.data);
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }

    }
}

pub trait ModIntf<'a> {
    fn delegate(&mut self) -> &mut Module<'a>;
    fn forward(&mut self);
}

#[derive(ModParse)]
pub struct Linear<'a> {
    delegate: Module<'a>,
    in_features: u32,
}

impl<'a> Linear<'a> {
    pub fn new() -> Linear<'a> {
        let mut t = Linear {
            delegate: Module::new(),
            in_features: 0,
        };
        t.init_module();
        t
    }
}

impl<'a> ModIntf<'a> for Linear<'a> {
    fn delegate(&mut self) -> &mut Module<'a> {
        &mut self.delegate
    }
    fn forward(&mut self) {}
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::io::{Result, Write};
use std::fs::{File, create_dir_all};

pub trait Output {
    fn get_writer(&self, &Path) -> Result<Box<Write>>;
}

pub struct FsOutput {
    pub root: PathBuf,
}

impl Output for FsOutput {
    fn get_writer(&self, path: &Path) -> Result<Box<Write>> {
        assert!(path.is_relative());
        let file_path = self.root.join(&path);
        if let Some(parent) = file_path.parent() {
            create_dir_all(parent.as_os_str())?;
        }
        let file = File::create(file_path.as_os_str())?;
        Ok(Box::new(file))
    }
}
<commit_msg>Pass paths instead of OS strings to fs functions<commit_after>use std::path::{Path, PathBuf};
use std::io::{Result, Write};
use std::fs::{File, create_dir_all};

pub trait Output {
    fn get_writer(&self, &Path) -> Result<Box<Write>>;
}

pub struct FsOutput {
    pub root: PathBuf,
}

impl Output for FsOutput {
    fn get_writer(&self, path: &Path) -> Result<Box<Write>> {
        assert!(path.is_relative());
        let file_path = self.root.join(&path);
        if let Some(parent) = file_path.parent() {
            create_dir_all(parent)?;
        }
        let file = File::create(file_path.as_path())?;
        Ok(Box::new(file))
    }
}
<|endoftext|>