<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::ptr;
use std::slice;
use std::ffi;

use htslib;

pub struct Record {
    pub inner: *mut htslib::vcf::bcf1_t,
    pub header: *mut htslib::vcf::bcf_hdr_t,
    buffer: *mut ::libc::c_void,
}

impl Record {
    pub fn new() -> Self {
        let inner = unsafe { htslib::vcf::bcf_init() };
        Record { inner: inner, header: ptr::null_mut(), buffer: ptr::null_mut() }
    }

    #[inline]
    fn inner(&self) -> htslib::vcf::bcf1_t {
        unsafe { *self.inner }
    }

    pub fn rid(&self) -> Option<u32> {
        match self.inner().rid {
            -1  => None,
            rid => Some(rid as u32)
        }
    }

    // 0-based position.
    pub fn pos(&self) -> u32 {
        self.inner().pos as u32
    }

    pub fn alleles(&self) -> Vec<&[u8]> {
        unsafe { htslib::vcf::bcf_unpack(self.inner, htslib::vcf::BCF_UN_STR) };
        let n = self.inner().n_allele as usize;
        let dec = self.inner().d;
        let alleles = unsafe { slice::from_raw_parts(dec.allele, n) };
        (0..n).map(|i| unsafe { ffi::CStr::from_ptr(alleles[i]).to_bytes() }).collect()
    }

    pub fn qual(&self) -> f32 {
        self.inner().qual
    }

    /// Get the value of the given info tag.
    pub fn info<'a>(&'a mut self, tag: &'a [u8]) -> Info {
        Info { record: self, tag: tag }
    }

    pub fn sample_count(&self) -> u32 {
        self.inner().n_fmt_n_sample & 0xffffff
    }

    /// Get the value of the given format tag for each sample.
    pub fn format<'a>(&'a mut self, tag: &'a [u8]) -> Format {
        Format::new(self, tag)
    }
}

impl Drop for Record {
    fn drop(&mut self) {
        if !self.buffer.is_null() {
            unsafe { ::libc::free(self.buffer) };
        }
        unsafe { htslib::vcf::bcf_destroy(self.inner) };
    }
}

pub struct Info<'a> {
    record: &'a mut Record,
    tag: &'a [u8],
}

impl<'a> Info<'a> {
    fn data(&mut self, data_type: i32) -> Result<(usize, i32), InfoError> {
        let mut n: i32 = 0;
        match unsafe {
            htslib::vcf::bcf_get_info_values(
                self.record.header,
                self.record.inner,
                ffi::CString::new(self.tag).unwrap().as_ptr() as *mut i8,
                &mut self.record.buffer,
                &mut n,
                data_type
            )
        } {
            -1 => Err(InfoError::UndefinedTag),
            -2 => Err(InfoError::UnexpectedType),
            -3 => Err(InfoError::MissingTag),
            ret  => Ok((n as usize, ret)),
        }
    }

    pub fn integer(&mut self) -> Result<&[i32], InfoError> {
        self.data(htslib::vcf::BCF_HT_INT).map(|(n, _)| {
            unsafe { slice::from_raw_parts(self.record.buffer as *mut i32, n) }
        })
    }

    pub fn float(&mut self) -> Result<&[f32], InfoError> {
        self.data(htslib::vcf::BCF_HT_REAL).map(|(n, _)| {
            unsafe { slice::from_raw_parts(self.record.buffer as *mut f32, n) }
        })
    }

    pub fn flag(&mut self) -> Result<bool, InfoError> {
        self.data(htslib::vcf::BCF_HT_FLAG).map(|(_, ret)| {
            ret == 1
        })
    }

    pub fn string(&mut self) -> Result<&[u8], InfoError> {
        self.data(htslib::vcf::BCF_HT_STR).map(|(_, ret)| {
            unsafe { slice::from_raw_parts(self.record.buffer as *mut u8, ret as usize) }
        })
    }
}

// TODO implement format.
pub struct Format<'a> {
    record: &'a mut Record,
    tag: &'a [u8],
    inner: *mut htslib::vcf::bcf_fmt_t,
}

impl<'a> Format<'a> {
    fn new(record: &'a mut Record, tag: &'a [u8]) -> Format<'a> {
        let inner = unsafe { htslib::vcf::bcf_get_fmt(
            record.header,
            record.inner,
            ffi::CString::new(tag).unwrap().as_ptr() as *mut i8
        ) };
        Format { record: record, tag: tag, inner: inner }
    }

    fn values_per_sample(&self) -> usize {
        unsafe { (*self.inner).n as usize }
    }

    fn data(&mut self, data_type: i32) -> Result<(usize, i32), InfoError> {
        let mut n: i32 = 0;
        match unsafe {
            htslib::vcf::bcf_get_format_values(
                self.record.header,
                self.record.inner,
                ffi::CString::new(self.tag).unwrap().as_ptr() as *mut i8,
                &mut self.record.buffer,
                &mut n,
                data_type
            )
        } {
            -1 => Err(InfoError::UndefinedTag),
            -2 => Err(InfoError::UnexpectedType),
            -3 => Err(InfoError::MissingTag),
            ret  => Ok((n as usize, ret)),
        }
    }

    pub fn integer(&mut self) -> Result<Vec<&[i32]>, InfoError> {
        self.data(htslib::vcf::BCF_HT_INT).map(|(n, _)| {
            unsafe {
                slice::from_raw_parts(self.record.buffer as *mut i32, n)
            }.chunks(self.values_per_sample()).collect()
        })
    }

    pub fn float(&mut self) -> Result<Vec<&[f32]>, InfoError> {
        self.data(htslib::vcf::BCF_HT_REAL).map(|(n, _)| {
            unsafe {
                slice::from_raw_parts(self.record.buffer as *mut f32, n)
            }.chunks(self.values_per_sample()).collect()
        })
    }
}

pub enum InfoError {
    UndefinedTag,
    UnexpectedType,
    MissingTag,
}
<commit_msg>Refactoring.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::ptr;
use std::slice;
use std::ffi;

use htslib;

pub struct Record {
    pub inner: *mut htslib::vcf::bcf1_t,
    pub header: *mut htslib::vcf::bcf_hdr_t,
    buffer: *mut ::libc::c_void,
}

impl Record {
    pub fn new() -> Self {
        let inner = unsafe { htslib::vcf::bcf_init() };
        Record { inner: inner, header: ptr::null_mut(), buffer: ptr::null_mut() }
    }

    #[inline]
    fn inner(&self) -> htslib::vcf::bcf1_t {
        unsafe { *self.inner }
    }

    pub fn rid(&self) -> Option<u32> {
        match self.inner().rid {
            -1  => None,
            rid => Some(rid as u32)
        }
    }

    // 0-based position.
    pub fn pos(&self) -> u32 {
        self.inner().pos as u32
    }

    pub fn alleles(&self) -> Vec<&[u8]> {
        unsafe { htslib::vcf::bcf_unpack(self.inner, htslib::vcf::BCF_UN_STR) };
        let n = self.inner().n_allele as usize;
        let dec = self.inner().d;
        let alleles = unsafe { slice::from_raw_parts(dec.allele, n) };
        (0..n).map(|i| unsafe { ffi::CStr::from_ptr(alleles[i]).to_bytes() }).collect()
    }

    pub fn qual(&self) -> f32 {
        self.inner().qual
    }

    /// Get the value of the given info tag.
    pub fn info<'a>(&'a mut self, tag: &'a [u8]) -> Info {
        Info { record: self, tag: tag }
    }

    pub fn sample_count(&self) -> u32 {
        self.inner().n_fmt_n_sample & 0xffffff
    }

    /// Get the value of the given format tag for each sample.
    pub fn format<'a>(&'a mut self, tag: &'a [u8]) -> Format {
        Format::new(self, tag)
    }
}

impl Drop for Record {
    fn drop(&mut self) {
        if !self.buffer.is_null() {
            unsafe { ::libc::free(self.buffer) };
        }
        unsafe { htslib::vcf::bcf_destroy(self.inner) };
    }
}

pub struct Info<'a> {
    record: &'a mut Record,
    tag: &'a [u8],
}

impl<'a> Info<'a> {
    fn data(&mut self, data_type: i32) -> Result<(usize, i32), TagError> {
        let mut n: i32 = 0;
        match unsafe {
            htslib::vcf::bcf_get_info_values(
                self.record.header,
                self.record.inner,
                ffi::CString::new(self.tag).unwrap().as_ptr() as *mut i8,
                &mut self.record.buffer,
                &mut n,
                data_type
            )
        } {
            -1 => Err(TagError::UndefinedTag),
            -2 => Err(TagError::UnexpectedType),
            -3 => Err(TagError::MissingTag),
            ret  => Ok((n as usize, ret)),
        }
    }

    pub fn integer(&mut self) -> Result<&[i32], TagError> {
        self.data(htslib::vcf::BCF_HT_INT).map(|(n, _)| {
            unsafe { slice::from_raw_parts(self.record.buffer as *mut i32, n) }
        })
    }

    pub fn float(&mut self) -> Result<&[f32], TagError> {
        self.data(htslib::vcf::BCF_HT_REAL).map(|(n, _)| {
            unsafe { slice::from_raw_parts(self.record.buffer as *mut f32, n) }
        })
    }

    pub fn flag(&mut self) -> Result<bool, TagError> {
        self.data(htslib::vcf::BCF_HT_FLAG).map(|(_, ret)| {
            ret == 1
        })
    }

    pub fn string(&mut self) -> Result<&[u8], TagError> {
        self.data(htslib::vcf::BCF_HT_STR).map(|(_, ret)| {
            unsafe { slice::from_raw_parts(self.record.buffer as *mut u8, ret as usize) }
        })
    }
}

// TODO implement format.
pub struct Format<'a> {
    record: &'a mut Record,
    tag: &'a [u8],
    inner: *mut htslib::vcf::bcf_fmt_t,
}

impl<'a> Format<'a> {
    fn new(record: &'a mut Record, tag: &'a [u8]) -> Format<'a> {
        let inner = unsafe { htslib::vcf::bcf_get_fmt(
            record.header,
            record.inner,
            ffi::CString::new(tag).unwrap().as_ptr() as *mut i8
        ) };
        Format { record: record, tag: tag, inner: inner }
    }

    fn values_per_sample(&self) -> usize {
        unsafe { (*self.inner).n as usize }
    }

    fn data(&mut self, data_type: i32) -> Result<(usize, i32), TagError> {
        let mut n: i32 = 0;
        match unsafe {
            htslib::vcf::bcf_get_format_values(
                self.record.header,
                self.record.inner,
                ffi::CString::new(self.tag).unwrap().as_ptr() as *mut i8,
                &mut self.record.buffer,
                &mut n,
                data_type
            )
        } {
            -1 => Err(TagError::UndefinedTag),
            -2 => Err(TagError::UnexpectedType),
            -3 => Err(TagError::MissingTag),
            ret  => Ok((n as usize, ret)),
        }
    }

    pub fn integer(&mut self) -> Result<Vec<&[i32]>, TagError> {
        self.data(htslib::vcf::BCF_HT_INT).map(|(n, _)| {
            unsafe {
                slice::from_raw_parts(self.record.buffer as *mut i32, n)
            }.chunks(self.values_per_sample()).collect()
        })
    }

    pub fn float(&mut self) -> Result<Vec<&[f32]>, TagError> {
        self.data(htslib::vcf::BCF_HT_REAL).map(|(n, _)| {
            unsafe {
                slice::from_raw_parts(self.record.buffer as *mut f32, n)
            }.chunks(self.values_per_sample()).collect()
        })
    }
}

pub enum TagError {
    UndefinedTag,
    UnexpectedType,
    MissingTag,
}
<|endoftext|>


<commit_before>use platform::io;

pub enum Color {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Pink = 5,
    Brown = 6,
    LightGray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    LightPink = 13,
    Yellow = 14,
    White = 15,
}

pub static ROWS: uint = 25;
pub static COLS: uint = 80;

#[no_split_stack]
pub fn putc(xpos: uint, ypos: uint, value: u8)
{
	if xpos >= COLS || ypos >= ROWS { return }
	unsafe
	{
		*((0xb8000 + ypos * COLS * 2 + xpos * 2) as *mut u8) = value;
	}
}

#[no_split_stack]
pub fn setfg(xpos: uint, ypos: uint, value: Color)
{
	if xpos >= COLS || ypos >= ROWS { return }
	unsafe
	{
		let ptr = (0xb8000 + ypos * COLS * 2 + xpos * 2 + 1) as *mut u8;
		*ptr = (*ptr & 0xF0) | (value as u8 & 0x0F);
	}
}

#[no_split_stack]
pub fn setbg(xpos: uint, ypos: uint, value: Color)
{
	if xpos >= COLS || ypos >= ROWS { return }
	unsafe
	{
		let ptr = (0xb8000 + ypos * COLS * 2 + xpos * 2 + 1) as *mut u8;
		*ptr = (*ptr & 0x0F) | ((value as u8 << 4) & 0xF0);
	}
}

#[no_split_stack]
pub fn move_cursor(xpos: uint, ypos: uint)
{
	if xpos >= COLS || ypos >= COLS { return };
	let pos = ypos * COLS + xpos;
	unsafe
	{
		io::outport(0x3D4, 14);
		io::outport(0x3D5, (pos >> 8) as u8);
		io::outport(0x3D4, 15);
		io::outport(0x3D5, pos as u8);
	}
}
<commit_msg>Background may use bit 4 for indicating to blink<commit_after>use platform::io;

pub enum Color {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Pink = 5,
    Brown = 6,
    LightGray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    LightPink = 13,
    Yellow = 14,
    White = 15,
}

pub static ROWS: uint = 25;
pub static COLS: uint = 80;

#[no_split_stack]
pub fn putc(xpos: uint, ypos: uint, value: u8)
{
	if xpos >= COLS || ypos >= ROWS { return }
	unsafe
	{
		*((0xb8000 + ypos * COLS * 2 + xpos * 2) as *mut u8) = value;
	}
}

#[no_split_stack]
pub fn setfg(xpos: uint, ypos: uint, value: Color)
{
	if xpos >= COLS || ypos >= ROWS { return }
	unsafe
	{
		let ptr = (0xb8000 + ypos * COLS * 2 + xpos * 2 + 1) as *mut u8;
		*ptr = (*ptr & 0xF0) | (value as u8 & 0x0F);
	}
}

#[no_split_stack]
pub fn setbg(xpos: uint, ypos: uint, value: Color)
{
	if xpos >= COLS || ypos >= ROWS { return }
	unsafe
	{
		let ptr = (0xb8000 + ypos * COLS * 2 + xpos * 2 + 1) as *mut u8;
		*ptr = (*ptr & 0x0F) | ((value as u8 << 4) & 0x70);
	}
}

#[no_split_stack]
pub fn move_cursor(xpos: uint, ypos: uint)
{
	if xpos >= COLS || ypos >= COLS { return };
	let pos = ypos * COLS + xpos;
	unsafe
	{
		io::outport(0x3D4, 14);
		io::outport(0x3D5, (pos >> 8) as u8);
		io::outport(0x3D4, 15);
		io::outport(0x3D5, pos as u8);
	}
}
<|endoftext|>


<commit_before>//! A buffer is a memory location accessible to the video card.
//!
//! The purpose of buffers is to serve as a space where the GPU can read from or write data to.
//! It can contain a list of vertices, indices, uniform data, etc.
//!
//! # Buffers management in glium
//!
//! There are three levels of abstraction in glium:
//!
//!  - An `Alloc` corresponds to an OpenGL buffer object and is unsafe to use.
//!    This type is not public.
//!  - A `Buffer` wraps around an `Alloc` and provides safety by handling the data type and fences.
//!  - The `VertexBuffer`, `IndexBuffer`, `UniformBuffer`, `PixelBuffer`, etc. types are
//!    abstractions over a `Buffer` indicating their specific purpose. They implement `Deref`
//!    for the `Buffer`. These types are in the `vertex`, `index`, etc. modules.
//!
//! # Unsized types
//!
//! In order to put some data in a buffer, it must implement the `Content` trait. This trait is
//! automatically implemented on all `Sized` types and on slices (like `[u8]`). This means that
//! you can create a `Buffer<Foo>` (if `Foo` is sized) or a `Buffer<[u8]>` for example without
//! worrying about it.
//!
//! However unsized structs don't automatically implement this trait and you must call the
//! `implement_buffer_content!` macro on them. You must then use the `empty_unsized` constructor.
//!
//! ```no_run
//! # #[macro_use] extern crate glium; fn main() {
//! # use std::mem;
//! # use glium::buffer::{BufferType, BufferMode};
//! # let display: glium::Display = unsafe { mem::uninitialized() };
//! struct Data {
//!     data: [f32],        // `[f32]` is unsized, therefore `Data` is unsized too
//! }
//!
//! implement_buffer_content!(Data);    // without this, you can't put `Data` in a glium buffer
//!
//! // creates a buffer of 64 bytes, which thus holds 8 f32s
//! let mut buffer = glium::buffer::Buffer::<Data>::empty_unsized(&display, BufferType::UniformBuffer,
//!                                                               64, BufferMode::Default).unwrap();
//!
//! // you can then write to it like you normally would
//! buffer.map().data[4] = 2.1;
//! # }
//! ```
//!
pub use self::view::{Buffer, BufferAny, BufferMutSlice};
pub use self::view::{BufferSlice, BufferAnySlice};
pub use self::alloc::{Mapping, WriteMapping, ReadMapping, ReadError, CopyError};
pub use self::alloc::{is_buffer_read_supported};
pub use self::fences::Inserter;

/// DEPRECATED. Only here for backward compatibility.
pub use self::view::Buffer as BufferView;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferSlice as BufferViewSlice;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferMutSlice as BufferViewMutSlice;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferAny as BufferViewAny;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferAnySlice as BufferViewAnySlice;

use gl;
use std::error::Error;
use std::fmt;
use std::mem;
use std::slice;

mod alloc;
mod fences;
mod view;

/// Trait for types of data that can be put inside buffers.
pub unsafe trait Content {
    /// A type that holds a sized version of the content.
    type Owned;

    /// Prepares an output buffer, then turns this buffer into an `Owned`.
    fn read<F, E>(size: usize, F) -> Result<Self::Owned, E>
                  where F: FnOnce(&mut Self) -> Result<(), E>;

    /// Returns the size of each element.
    fn get_elements_size() -> usize;

    /// Produces a pointer to the data.
    fn to_void_ptr(&self) -> *const ();

    /// Builds a pointer to this type from a raw pointer.
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut Self>;

    /// Returns true if the size is suitable to store a type like this.
    fn is_size_suitable(usize) -> bool;
}

unsafe impl<T> Content for T where T: Copy {
    type Owned = T;

    #[inline]
    fn read<F, E>(size: usize, f: F) -> Result<T, E> where F: FnOnce(&mut T) -> Result<(), E> {
        assert!(size == mem::size_of::<T>());
        #[allow(deprecated)]
        let mut value = unsafe { mem::uninitialized() };
        try!(f(&mut value));
        Ok(value)
    }

    #[inline]
    fn get_elements_size() -> usize {
        mem::size_of::<T>()
    }

    #[inline]
    fn to_void_ptr(&self) -> *const () {
        self as *const T as *const ()
    }

    #[inline]
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut T> {
        if size != mem::size_of::<T>() {
            return None;
        }

        Some(ptr as *mut T)
    }

    #[inline]
    fn is_size_suitable(size: usize) -> bool {
        size == mem::size_of::<T>()
    }
}

unsafe impl<T> Content for [T] where T: Copy {
    type Owned = Vec<T>;

    #[inline]
    fn read<F, E>(size: usize, f: F) -> Result<Vec<T>, E>
                  where F: FnOnce(&mut [T]) -> Result<(), E>
    {
        assert!(size % mem::size_of::<T>() == 0);
        let len = size / mem::size_of::<T>();
        let mut value = Vec::with_capacity(len);
        unsafe { value.set_len(len) };
        try!(f(&mut value));
        Ok(value)
    }

    #[inline]
    fn get_elements_size() -> usize {
        mem::size_of::<T>()
    }

    #[inline]
    fn to_void_ptr(&self) -> *const () {
        &self[0] as *const T as *const ()
    }

    #[inline]
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut [T]> {
        if size % mem::size_of::<T>() != 0 {
            return None;
        }

        let ptr = ptr as *mut T;
        let size = size / mem::size_of::<T>();
        Some(unsafe { slice::from_raw_parts_mut(&mut *ptr, size) as *mut [T] })
    }

    #[inline]
    fn is_size_suitable(size: usize) -> bool {
        size % mem::size_of::<T>() == 0
    }
}

/// Error that can happen when creating a buffer.
#[derive(Debug, Copy, Clone)]
pub enum BufferCreationError {
    /// Not enough memory to create the buffer.
    OutOfMemory,

    /// This type of buffer is not supported.
    BufferTypeNotSupported,
}

impl fmt::Display for BufferCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.description())
    }
}

impl Error for BufferCreationError {
    fn description(&self) -> &str {
        match self {
            &BufferCreationError::OutOfMemory => "Not enough memory to create the buffer",
            &BufferCreationError::BufferTypeNotSupported => "This type of buffer is not supported",
        }
    }
}

/// How the buffer is created.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BufferMode {
    /// This is the default mode suitable for any usage. Will never be slow, will never be fast
    /// either.
    ///
    /// Other modes should always be preferred, but you can use this one if you don't know what
    /// will happen to the buffer.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` flag.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
    ///
    Default,

    /// The mode to use when you modify a buffer multiple times per frame. Similar to `Default` in
    /// that it is suitable for most usages.
    ///
    /// Use this if you do a quick succession of modify the buffer, draw, modify, draw, etc. This
    /// is something that you shouldn't do by the way.
    ///
    /// With this mode, the OpenGL driver automatically manages the buffer for us. It will try to
    /// find the most appropriate storage depending on how we use it. It is guaranteed to never be
    /// too slow, but it won't be too fast either.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` and
    /// `GL_CLIENT_STORAGE_BIT` flags.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
    ///
    Dynamic,

    /// Optimized for when you modify a buffer exactly once per frame. You can modify it more than
    /// once per frame, but if you modify it too often things will slow down.
    ///
    /// With this mode, glium automatically handles synchronization to prevent the buffer from
    /// being access by both the GPU and the CPU simultaneously. If you try to modify the buffer,
    /// the execution will block until the GPU has finished using it. For this reason, a quick
    /// succession of modifying and drawing using the same buffer will be very slow.
    ///
    /// When using persistent mapping, it is recommended to use triple buffering. This is done by
    /// creating a buffer that has three times the capacity that it would normally have. You modify
    /// and draw the first third, then modify and draw the second third, then the last part, then
    /// go back to the first third, etc.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with `GL_MAP_PERSISTENT_BIT`. Sync fences are automatically
    /// managed by glium.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
    ///
    Persistent,

    /// Optimized when you will never touch the content of the buffer.
    ///
    /// Immutable buffers should be created once and never touched again. Modifying their content
    /// is permitted, but is very slow.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` without any flag. Modifications are done by creating
    /// temporary buffers and making the GPU copy the data from the temporary buffer to the real
    /// one.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
    ///
    Immutable,
}

impl Default for BufferMode {
    fn default() -> BufferMode {
        BufferMode::Default
    }
}

/// Type of a buffer.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum BufferType {
    ArrayBuffer,
    PixelPackBuffer,
    PixelUnpackBuffer,
    UniformBuffer,
    CopyReadBuffer,
    CopyWriteBuffer,
    AtomicCounterBuffer,
    DispatchIndirectBuffer,
    DrawIndirectBuffer,
    QueryBuffer,
    ShaderStorageBuffer,
    TextureBuffer,
    TransformFeedbackBuffer,
    ElementArrayBuffer,
}

impl BufferType {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            BufferType::ArrayBuffer => gl::ARRAY_BUFFER,
            BufferType::PixelPackBuffer => gl::PIXEL_PACK_BUFFER,
            BufferType::PixelUnpackBuffer => gl::PIXEL_UNPACK_BUFFER,
            BufferType::UniformBuffer => gl::UNIFORM_BUFFER,
            BufferType::CopyReadBuffer => gl::COPY_READ_BUFFER,
            BufferType::CopyWriteBuffer => gl::COPY_WRITE_BUFFER,
            BufferType::AtomicCounterBuffer => gl::ATOMIC_COUNTER_BUFFER,
            BufferType::DispatchIndirectBuffer => gl::DISPATCH_INDIRECT_BUFFER,
            BufferType::DrawIndirectBuffer => gl::DRAW_INDIRECT_BUFFER,
            BufferType::QueryBuffer => gl::QUERY_BUFFER,
            BufferType::ShaderStorageBuffer => gl::SHADER_STORAGE_BUFFER,
            BufferType::TextureBuffer => gl::TEXTURE_BUFFER,
            BufferType::TransformFeedbackBuffer => gl::TRANSFORM_FEEDBACK_BUFFER,
            BufferType::ElementArrayBuffer => gl::ELEMENT_ARRAY_BUFFER,
        }
    }
}
<commit_msg>references to uninit are probably UB, we can use zeroed<commit_after>//! A buffer is a memory location accessible to the video card.
//!
//! The purpose of buffers is to serve as a space where the GPU can read from or write data to.
//! It can contain a list of vertices, indices, uniform data, etc.
//!
//! # Buffers management in glium
//!
//! There are three levels of abstraction in glium:
//!
//!  - An `Alloc` corresponds to an OpenGL buffer object and is unsafe to use.
//!    This type is not public.
//!  - A `Buffer` wraps around an `Alloc` and provides safety by handling the data type and fences.
//!  - The `VertexBuffer`, `IndexBuffer`, `UniformBuffer`, `PixelBuffer`, etc. types are
//!    abstractions over a `Buffer` indicating their specific purpose. They implement `Deref`
//!    for the `Buffer`. These types are in the `vertex`, `index`, etc. modules.
//!
//! # Unsized types
//!
//! In order to put some data in a buffer, it must implement the `Content` trait. This trait is
//! automatically implemented on all `Sized` types and on slices (like `[u8]`). This means that
//! you can create a `Buffer<Foo>` (if `Foo` is sized) or a `Buffer<[u8]>` for example without
//! worrying about it.
//!
//! However unsized structs don't automatically implement this trait and you must call the
//! `implement_buffer_content!` macro on them. You must then use the `empty_unsized` constructor.
//!
//! ```no_run
//! # #[macro_use] extern crate glium; fn main() {
//! # use std::mem;
//! # use glium::buffer::{BufferType, BufferMode};
//! # let display: glium::Display = unsafe { mem::uninitialized() };
//! struct Data {
//!     data: [f32],        // `[f32]` is unsized, therefore `Data` is unsized too
//! }
//!
//! implement_buffer_content!(Data);    // without this, you can't put `Data` in a glium buffer
//!
//! // creates a buffer of 64 bytes, which thus holds 8 f32s
//! let mut buffer = glium::buffer::Buffer::<Data>::empty_unsized(&display, BufferType::UniformBuffer,
//!                                                               64, BufferMode::Default).unwrap();
//!
//! // you can then write to it like you normally would
//! buffer.map().data[4] = 2.1;
//! # }
//! ```
//!
pub use self::view::{Buffer, BufferAny, BufferMutSlice};
pub use self::view::{BufferSlice, BufferAnySlice};
pub use self::alloc::{Mapping, WriteMapping, ReadMapping, ReadError, CopyError};
pub use self::alloc::{is_buffer_read_supported};
pub use self::fences::Inserter;

/// DEPRECATED. Only here for backward compatibility.
pub use self::view::Buffer as BufferView;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferSlice as BufferViewSlice;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferMutSlice as BufferViewMutSlice;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferAny as BufferViewAny;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferAnySlice as BufferViewAnySlice;

use gl;
use std::error::Error;
use std::fmt;
use std::mem;
use std::slice;

mod alloc;
mod fences;
mod view;

/// Trait for types of data that can be put inside buffers.
pub unsafe trait Content {
    /// A type that holds a sized version of the content.
    type Owned;

    /// Prepares an output buffer, then turns this buffer into an `Owned`.
    fn read<F, E>(size: usize, F) -> Result<Self::Owned, E>
                  where F: FnOnce(&mut Self) -> Result<(), E>;

    /// Returns the size of each element.
    fn get_elements_size() -> usize;

    /// Produces a pointer to the data.
    fn to_void_ptr(&self) -> *const ();

    /// Builds a pointer to this type from a raw pointer.
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut Self>;

    /// Returns true if the size is suitable to store a type like this.
    fn is_size_suitable(usize) -> bool;
}

unsafe impl<T> Content for T where T: Copy {
    type Owned = T;

    #[inline]
    fn read<F, E>(size: usize, f: F) -> Result<T, E> where F: FnOnce(&mut T) -> Result<(), E> {
        assert!(size == mem::size_of::<T>());
        // Note(Lokathor): This is brittle and dangerous if `T` isn't a type
        // that can be zeroed. However, it's a breaking change to adjust the API
        // here (eg: extra trait bound or something) so someone with more
        // authority than me needs to look at and fix this.
        let mut value = unsafe { mem::zeroed() };
        try!(f(&mut value));
        Ok(value)
    }

    #[inline]
    fn get_elements_size() -> usize {
        mem::size_of::<T>()
    }

    #[inline]
    fn to_void_ptr(&self) -> *const () {
        self as *const T as *const ()
    }

    #[inline]
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut T> {
        if size != mem::size_of::<T>() {
            return None;
        }

        Some(ptr as *mut T)
    }

    #[inline]
    fn is_size_suitable(size: usize) -> bool {
        size == mem::size_of::<T>()
    }
}

unsafe impl<T> Content for [T] where T: Copy {
    type Owned = Vec<T>;

    #[inline]
    fn read<F, E>(size: usize, f: F) -> Result<Vec<T>, E>
                  where F: FnOnce(&mut [T]) -> Result<(), E>
    {
        assert!(size % mem::size_of::<T>() == 0);
        let len = size / mem::size_of::<T>();
        let mut value = Vec::with_capacity(len);
        unsafe { value.set_len(len) };
        try!(f(&mut value));
        Ok(value)
    }

    #[inline]
    fn get_elements_size() -> usize {
        mem::size_of::<T>()
    }

    #[inline]
    fn to_void_ptr(&self) -> *const () {
        &self[0] as *const T as *const ()
    }

    #[inline]
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut [T]> {
        if size % mem::size_of::<T>() != 0 {
            return None;
        }

        let ptr = ptr as *mut T;
        let size = size / mem::size_of::<T>();
        Some(unsafe { slice::from_raw_parts_mut(&mut *ptr, size) as *mut [T] })
    }

    #[inline]
    fn is_size_suitable(size: usize) -> bool {
        size % mem::size_of::<T>() == 0
    }
}

/// Error that can happen when creating a buffer.
#[derive(Debug, Copy, Clone)]
pub enum BufferCreationError {
    /// Not enough memory to create the buffer.
    OutOfMemory,

    /// This type of buffer is not supported.
    BufferTypeNotSupported,
}

impl fmt::Display for BufferCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.description())
    }
}

impl Error for BufferCreationError {
    fn description(&self) -> &str {
        match self {
            &BufferCreationError::OutOfMemory => "Not enough memory to create the buffer",
            &BufferCreationError::BufferTypeNotSupported => "This type of buffer is not supported",
        }
    }
}

/// How the buffer is created.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BufferMode {
    /// This is the default mode suitable for any usage. Will never be slow, will never be fast
    /// either.
    ///
    /// Other modes should always be preferred, but you can use this one if you don't know what
    /// will happen to the buffer.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` flag.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
    ///
    Default,

    /// The mode to use when you modify a buffer multiple times per frame. Similar to `Default` in
    /// that it is suitable for most usages.
    ///
    /// Use this if you do a quick succession of modify the buffer, draw, modify, draw, etc. This
    /// is something that you shouldn't do by the way.
    ///
    /// With this mode, the OpenGL driver automatically manages the buffer for us. It will try to
    /// find the most appropriate storage depending on how we use it. It is guaranteed to never be
    /// too slow, but it won't be too fast either.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` and
    /// `GL_CLIENT_STORAGE_BIT` flags.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
    ///
    Dynamic,

    /// Optimized for when you modify a buffer exactly once per frame. You can modify it more than
    /// once per frame, but if you modify it too often things will slow down.
    ///
    /// With this mode, glium automatically handles synchronization to prevent the buffer from
    /// being access by both the GPU and the CPU simultaneously. If you try to modify the buffer,
    /// the execution will block until the GPU has finished using it. For this reason, a quick
    /// succession of modifying and drawing using the same buffer will be very slow.
    ///
    /// When using persistent mapping, it is recommended to use triple buffering. This is done by
    /// creating a buffer that has three times the capacity that it would normally have. You modify
    /// and draw the first third, then modify and draw the second third, then the last part, then
    /// go back to the first third, etc.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with `GL_MAP_PERSISTENT_BIT`. Sync fences are automatically
    /// managed by glium.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
    ///
    Persistent,

    /// Optimized when you will never touch the content of the buffer.
    ///
    /// Immutable buffers should be created once and never touched again. Modifying their content
    /// is permitted, but is very slow.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` without any flag. Modifications are done by creating
    /// temporary buffers and making the GPU copy the data from the temporary buffer to the real
    /// one.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
    ///
    Immutable,
}

impl Default for BufferMode {
    fn default() -> BufferMode {
        BufferMode::Default
    }
}

/// Type of a buffer.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum BufferType {
    ArrayBuffer,
    PixelPackBuffer,
    PixelUnpackBuffer,
    UniformBuffer,
    CopyReadBuffer,
    CopyWriteBuffer,
    AtomicCounterBuffer,
    DispatchIndirectBuffer,
    DrawIndirectBuffer,
    QueryBuffer,
    ShaderStorageBuffer,
    TextureBuffer,
    TransformFeedbackBuffer,
    ElementArrayBuffer,
}

impl BufferType {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            BufferType::ArrayBuffer => gl::ARRAY_BUFFER,
            BufferType::PixelPackBuffer => gl::PIXEL_PACK_BUFFER,
            BufferType::PixelUnpackBuffer => gl::PIXEL_UNPACK_BUFFER,
            BufferType::UniformBuffer => gl::UNIFORM_BUFFER,
            BufferType::CopyReadBuffer => gl::COPY_READ_BUFFER,
            BufferType::CopyWriteBuffer => gl::COPY_WRITE_BUFFER,
            BufferType::AtomicCounterBuffer => gl::ATOMIC_COUNTER_BUFFER,
            BufferType::DispatchIndirectBuffer => gl::DISPATCH_INDIRECT_BUFFER,
            BufferType::DrawIndirectBuffer => gl::DRAW_INDIRECT_BUFFER,
            BufferType::QueryBuffer => gl::QUERY_BUFFER,
            BufferType::ShaderStorageBuffer => gl::SHADER_STORAGE_BUFFER,
            BufferType::TextureBuffer => gl::TEXTURE_BUFFER,
            BufferType::TransformFeedbackBuffer => gl::TRANSFORM_FEEDBACK_BUFFER,
            BufferType::ElementArrayBuffer => gl::ELEMENT_ARRAY_BUFFER,
        }
    }
}
<|endoftext|>


<commit_before>use ::{JsonResponse, IoDirection, MethodRouter};
use ::ffi::ImageflowJsonResponse;
use flow::definitions::Graph;
use ::internal_prelude::works_everywhere::*;
use ::rustc_serialize::base64;
use ::rustc_serialize::base64::ToBase64;

pub struct ContextPtr {
    // TODO: Remove pub as soon as tests/visuals.rs doesn't need access
    // (i.e, unit test helpers are ported, or the helper becomes cfgtest on the struct itself)
    pub ptr: Option<*mut ::ffi::ImageflowContext>,
}

pub struct SelfDisposingContextPtr {
    ptr: ContextPtr,
}
impl SelfDisposingContextPtr {
    pub fn create() -> Result<SelfDisposingContextPtr> {
        let p = ContextPtr::create()?;
        Ok(SelfDisposingContextPtr { ptr: p })
    }
    pub fn inner(&self) -> &ContextPtr {
        &self.ptr
    }

    pub fn inner_mut(&mut self) -> &mut ContextPtr {
        &mut self.ptr
    }

    pub fn create_job(&self) -> Result<JobPtr> {
        unsafe {
            JobPtr::create(self.ptr.as_ptr()?)
        }
    }

    pub fn destroy_allowing_panics(mut self) -> () {
        self.ptr.destroy_allowing_panics()
    }
}
impl Drop for SelfDisposingContextPtr {
    fn drop(&mut self) {
        self.ptr.force_destroy();
    }
}

pub struct JobPtr {
    ptr: *mut ::ffi::ImageflowJob,
    c: *mut ::ffi::ImageflowContext,
}

impl JobPtr {
    pub fn context_ptr(&self) -> *mut ::ffi::ImageflowContext {
        self.c
    }
    pub fn as_ptr(&self) -> *mut ::ffi::ImageflowJob {
        self.ptr
    }

    pub fn from_ptr(context: *mut ::ffi::ImageflowContext,
                    job: *mut ::ffi::ImageflowJob)
                    -> Result<JobPtr> {
        if context.is_null() || job.is_null() {
            Err(FlowError::NullArgument)
        } else {
            Ok(JobPtr {
                ptr: job,
                c: context,
            })
        }
    }
    pub unsafe fn create(context: *mut ::ffi::ImageflowContext) -> Result<JobPtr> {
        if context.is_null() {
            return Err(FlowError::ContextInvalid);
        }

        let job = ::ffi::flow_job_create(context);
        if job.is_null() {
            Err(FlowError::Oom)
        } else {
            Ok(JobPtr {
                ptr: job,
                c: context,
            })
        }
    }
    pub unsafe fn add_io_ptr(&self,
                             io: *mut ::ffi::ImageflowJobIo,
                             io_id: i32,
                             direction: IoDirection)
                             -> Result<()> {
        let p = ::ffi::flow_job_add_io(self.context_ptr(), self.as_ptr(), io, io_id, direction);
        if !p {
            Err(self.ctx().get_error_copy().unwrap())
        } else {
            Ok(())
        }

    }

    pub fn add_input_bytes<'a>(&'a self, io_id: i32, bytes: &'a [u8]) -> Result<()> {
        unsafe {
            let p = ::ffi::flow_io_create_from_memory(self.context_ptr(),
                                                      ::ffi::IoMode::ReadSeekable,
                                                      bytes.as_ptr(),
                                                      bytes.len(),
                                                      self.context_ptr() as *const libc::c_void,
                                                      ptr::null());
            if p.is_null() {
                Err(self.ctx().get_error_copy().unwrap())
            } else {
                self.add_io_ptr(p, io_id, IoDirection::In)
            }
        }
    }

    pub fn add_output_buffer(&self, io_id: i32) -> Result<()> {
        unsafe {
            let p =
                ::ffi::flow_io_create_for_output_buffer(self.context_ptr(),
                                                        self.context_ptr() as *const libc::c_void);
            if p.is_null() {
                Err(self.ctx().get_error_copy().unwrap())
            } else {
                self.add_io_ptr(p, io_id, IoDirection::Out)
            }
        }
    }

    //    pub fn record_graphs(&self){
    //        let _ = unsafe { ::ffi::flow_job_configure_recording(self.context_ptr(),
    //                                                             self.as_ptr(),
    //                                                             true,
    //                                                             true,
    //                                                             true,
    //                                                             false,
    //                                                             false) };
    //    }
    pub fn configure_graph_recording(&self, recording: s::Build001GraphRecording) {
        let r = if std::env::var("CI").and_then(|s| Ok(s.to_uppercase())) ==
                   Ok("TRUE".to_owned()) {
            s::Build001GraphRecording::off()
        } else {
            recording
        };
        let _ = unsafe {
            ::ffi::flow_job_configure_recording(self.context_ptr(),
                                                self.as_ptr(),
                                                r.record_graph_versions
                                                    .unwrap_or(false),
                                                r.record_frame_images
                                                    .unwrap_or(false),
                                                r.render_last_graph
                                                    .unwrap_or(false),
                                                r.render_graph_versions
                                                    .unwrap_or(false),
                                                r.render_animated_graph
                                                    .unwrap_or(false))
        };
    }

    pub fn get_image_info(&self, io_id: i32) -> Result<s::ImageInfo> {
        unsafe {
            let mut info: ::ffi::DecoderInfo = ::ffi::DecoderInfo { ..Default::default() };

            if !::ffi::flow_job_get_decoder_info(self.context_ptr(),
                                                 self.as_ptr(),
                                                 io_id,
                                                 &mut info) {
                ContextPtr::from_ptr(self.context_ptr()).assert_ok(None);
            }
            Ok(s::ImageInfo {
                frame_decodes_into: s::PixelFormat::from(info.frame_decodes_into),
                image_height: info.image_height,
                image_width: info.image_width,
                frame_count: info.frame_count,
                current_frame_index: info.current_frame_index,
                preferred_extension: std::ffi::CStr::from_ptr(info.preferred_extension)
                    .to_owned()
                    .into_string()
                    .unwrap(),
                preferred_mime_type: std::ffi::CStr::from_ptr(info.preferred_mime_type)
                    .to_owned()
                    .into_string()
                    .unwrap(),
            })
        }

    }

    pub fn tell_decoder(&self, io_id: i32, tell: s::DecoderCommand) -> Result<()> {
        unsafe {
            match tell {
                s::DecoderCommand::JpegDownscaleHints(hints) => {
                    if !::ffi::flow_job_decoder_set_downscale_hints_by_placeholder_id(self.context_ptr(),
                                                                                self.as_ptr(), io_id,
                                                                                hints.width, hints.height,
                                                                                hints.width, hints.height,
                                                                                hints.scale_luma_spatially.unwrap_or(false),
                                                                                hints.gamma_correct_for_srgb_during_spatial_luma_scaling.unwrap_or(false)

                    ){
                        panic!("");
                    }
                }
            }
        }
        Ok(())

    }

    pub fn message(&mut self, method: &str, json: &[u8]) -> Result<JsonResponse> {

        ::job_methods::JOB_ROUTER.invoke(self, method, json)
    }

    pub fn io_get_output_buffer_copy(&mut self, io_id: i32) -> Result<Vec<u8>> {
        unsafe {
            let io_p = ::ffi::flow_job_get_io(self.c, self.ptr, io_id);
            if io_p.is_null() {
                Err(self.ctx().get_error_copy().unwrap())
            } else {
                let mut buf_start: *const u8 = ptr::null();
                let mut buf_len: usize = 0;
                let worked = ::ffi::flow_io_get_output_buffer(self.c,
                                                              io_p,
                                                              &mut buf_start as *mut *const u8,
                                                              &mut buf_len as *mut usize);
                if !worked {
                    Err(self.ctx().get_error_copy().unwrap())
                } else if buf_start.is_null() {
                    // Not sure how output buffer is null... no writes yet?
                    Err(FlowError::ErrNotImpl)
                } else {
                    Ok((std::slice::from_raw_parts(buf_start, buf_len)).to_vec())
                }
            }
        }
    }

    pub fn collect_encode_results(g: &Graph) -> Vec<s::EncodeResult>{
        let mut encodes = Vec::new();
        for node in g.raw_nodes() {
            if let ::flow::definitions::NodeResult::Encoded(ref r) = node.weight.result {
                encodes.push((*r).clone());
            }
        }
        encodes
    }
    pub fn collect_augmented_encode_results(&mut self, g: &Graph, io: &[s::IoObject]) -> Vec<s::EncodeResult>{
        JobPtr::collect_encode_results(g).into_iter().map(|r: s::EncodeResult|{
            if r.bytes == s::ResultBytes::Elsewhere {
                let obj: &s::IoObject = io.iter().find(|obj| obj.io_id == r.io_id).unwrap();//There's gotta be one
                let bytes = match obj.io {
                    s::IoEnum::Filename(ref str) => s::ResultBytes::PhysicalFile(str.to_owned()),
                    s::IoEnum::OutputBase64 => {
                        let vec = self.io_get_output_buffer_copy(r.io_id).unwrap();
                        s::ResultBytes::Base64(vec.as_slice().to_base64(base64::Config{char_set: base64::CharacterSet::Standard, line_length: None, newline: base64::Newline::LF, pad: true}))
                    },
                    _ => s::ResultBytes::Elsewhere
                };
                s::EncodeResult{
                    bytes: bytes,
                    .. r
                }
            }else{
                r
            }

        }).collect::<Vec<s::EncodeResult>>()
    }

    fn ctx(&self) -> ContextPtr {
        ContextPtr::from_ptr(self.context_ptr())
    }
}

impl ContextPtr {
    pub fn create_abi_json_response(&self,
                                    json_bytes: std::borrow::Cow<[u8]>,
                                    status_code: i64)
                                    -> *const ImageflowJsonResponse {
        unsafe {
            let sizeof_struct = std::mem::size_of::<ImageflowJsonResponse>();

            let pointer = ::ffi::flow_context_calloc(self.ptr.unwrap(),
                                                     1,
                                                     sizeof_struct + json_bytes.len(),
                                                     ptr::null(),
                                                     self.ptr.unwrap() as *mut libc::c_void,
                                                     ptr::null(),
                                                     0) as *mut u8;
            // Return null on OOM
            if pointer.is_null() {
                return ::std::ptr::null();
            }
            let pointer_to_final_buffer =
                pointer.offset(sizeof_struct as isize) as *mut libc::uint8_t;
            let imageflow_response = &mut (*(pointer as *mut ImageflowJsonResponse));
            imageflow_response.buffer_utf8_no_nulls = pointer_to_final_buffer;
            imageflow_response.buffer_size = json_bytes.len();
            imageflow_response.status_code = status_code;

            let mut out_json_bytes = std::slice::from_raw_parts_mut(pointer_to_final_buffer,
                                                                    json_bytes.len());

            out_json_bytes.clone_from_slice(&json_bytes);

            imageflow_response as *const ImageflowJsonResponse
        }
    }

    pub fn message(&mut self, method: &str, json: &[u8]) -> Result<JsonResponse> {

        ::context_methods::CONTEXT_ROUTER.invoke(self, method, json)
    }

    pub fn create() -> Result<ContextPtr> {
        unsafe {
            let ptr = ::ffi::flow_context_create();

            if ptr.is_null() {
                Err(FlowError::Oom)
            } else {
                Ok(ContextPtr { ptr: Some(ptr) })
            }
        }
    }

    fn force_destroy(&mut self) {
        unsafe {
            self.ptr = match self.ptr {
                Some(ptr) => {
                    ::ffi::flow_context_destroy(ptr);
                    None
                }
                _ => None,
            }
        }
    }

    fn destroy_allowing_panics(&mut self) {
        unsafe {
            self.ptr = match self.ptr {
                Some(ptr) => {
                    if !::ffi::flow_context_begin_terminate(ptr) {
                        panic!("Error during context shutdown{:?}",
                               self.get_error_copy().unwrap());
                    }
                    ::ffi::flow_context_destroy(ptr);
                    None
                }
                _ => None,
            }
        }
    }

    pub fn from_ptr(ptr: *mut ::ffi::ImageflowContext) -> ContextPtr {
        ContextPtr {
            ptr: if ptr.is_null() { None } else { Some(ptr) }
        }
    }
    pub fn as_ptr(&self) -> Result<*mut ::ffi::ImageflowContext> {
        match self.ptr {
            Some(p) if !p.is_null() => Ok(p),
            _ => Err(FlowError::ContextInvalid),
        }
    }

    unsafe fn get_flow_err(&self, c: *mut ::ffi::ImageflowContext) -> FlowErr {

        let code = ::ffi::flow_context_error_reason(c);
        let mut buf = vec![0u8; 2048];

        let chars_written =
            ::ffi::flow_context_error_and_stacktrace(c, buf.as_mut_ptr(), buf.len(), false);

        if chars_written < 0 {
            panic!("Error msg doesn't fit in 2kb");
        } else {
            buf.resize(chars_written as usize, 0u8);
        }

        FlowErr {
            code: code,
            message_and_stack: String::from_utf8(buf).unwrap(),
        }

    }
    pub unsafe fn err_maybe(&self) -> Result<()> {
        match self.get_error_copy() {
            Some(err) => Err(err),
            None => Ok(()),
        }
    }

    pub unsafe fn assert_ok(&self, g: Option<&Graph>) {
        if let Some(which_error) = self.get_error_copy() {
            match which_error {
                FlowError::Err(e) => {
                    println!("Error {} {}\n", e.code, e.message_and_stack);
                    if (e.code == 72 || e.code == 73) && g.is_some() {
                        //                                let _ = ::flow::graph::print_to_stdout(
                        //                                    self.ptr.unwrap(),
                        //                                    g.unwrap() as &flow::graph::Graph);
                    }

                    panic!();
                }
                FlowError::Oom => {
                    panic!("Out of memory.");
                }
                FlowError::ErrNotImpl => {
                    panic!("Error not implemented");
                }
                FlowError::ContextInvalid => {
                    panic!("Context pointer null");
                }
                FlowError::NullArgument => {
                    panic!("Context pointer null");
                }
                other => {
                    panic!("{:?}", other);
                }
            }
        }
    }

    fn get_error_copy(&self) -> Option<FlowError> {
        unsafe {
            match self.ptr {
                Some(ptr) if ::ffi::flow_context_has_error(ptr) => {
                    match ::ffi::flow_context_error_reason(ptr) {
                        0 => panic!("Inconsistent errors"),
                        10 => Some(FlowError::Oom),
                        _ => Some(FlowError::Err(self.get_flow_err(ptr))),
                    }
                }
                None => Some(FlowError::ContextInvalid),
                Some(_) => None,
            }
        }
    }
}

<commit_msg>refactor(core): remove JobPtr::from_ptr and correct &self mutability constraints<commit_after>use ::{JsonResponse, IoDirection, MethodRouter};
use ::ffi::ImageflowJsonResponse;
use flow::definitions::Graph;
use ::internal_prelude::works_everywhere::*;
use ::rustc_serialize::base64;
use ::rustc_serialize::base64::ToBase64;

pub struct ContextPtr {
    // TODO: Remove pub as soon as tests/visuals.rs doesn't need access
    // (i.e, unit test helpers are ported, or the helper becomes cfgtest on the struct itself)
    pub ptr: Option<*mut ::ffi::ImageflowContext>,
}

pub struct SelfDisposingContextPtr {
    ptr: ContextPtr,
}
impl SelfDisposingContextPtr {
    pub fn create() -> Result<SelfDisposingContextPtr> {
        let p = ContextPtr::create()?;
        Ok(SelfDisposingContextPtr { ptr: p })
    }
    pub fn inner(&self) -> &ContextPtr {
        &self.ptr
    }

    pub fn inner_mut(&mut self) -> &mut ContextPtr {
        &mut self.ptr
    }

    pub fn create_job(&self) -> Result<JobPtr> {
        unsafe {
            JobPtr::create(self.ptr.as_ptr()?)
        }
    }

    pub fn destroy_allowing_panics(mut self) -> () {
        self.ptr.destroy_allowing_panics()
    }
}
impl Drop for SelfDisposingContextPtr {
    fn drop(&mut self) {
        self.ptr.force_destroy();
    }
}

pub struct JobPtr {
    ptr: *mut ::ffi::ImageflowJob,
    c: *mut ::ffi::ImageflowContext,
}

impl JobPtr {
    pub fn context_ptr(&self) -> *mut ::ffi::ImageflowContext {
        self.c
    }
    pub fn as_ptr(&self) -> *mut ::ffi::ImageflowJob {
        self.ptr
    }

    pub unsafe fn create(context: *mut ::ffi::ImageflowContext) -> Result<JobPtr> {
        if context.is_null() {
            return Err(FlowError::ContextInvalid);
        }

        let job = ::ffi::flow_job_create(context);
        if job.is_null() {
            Err(FlowError::Oom)
        } else {
            Ok(JobPtr {
                ptr: job,
                c: context,
            })
        }
    }
    pub unsafe fn add_io_ptr(&mut self,
                             io: *mut ::ffi::ImageflowJobIo,
                             io_id: i32,
                             direction: IoDirection)
                             -> Result<()> {
        let p = ::ffi::flow_job_add_io(self.context_ptr(), self.as_ptr(), io, io_id, direction);
        if !p {
            Err(self.ctx().get_error_copy().unwrap())
        } else {
            Ok(())
        }

    }

    pub fn add_input_bytes<'a>(&'a mut self, io_id: i32, bytes: &'a [u8]) -> Result<()> {
        unsafe {
            let p = ::ffi::flow_io_create_from_memory(self.context_ptr(),
                                                      ::ffi::IoMode::ReadSeekable,
                                                      bytes.as_ptr(),
                                                      bytes.len(),
                                                      self.context_ptr() as *const libc::c_void,
                                                      ptr::null());
            if p.is_null() {
                Err(self.ctx().get_error_copy().unwrap())
            } else {
                self.add_io_ptr(p, io_id, IoDirection::In)
            }
        }
    }

    pub fn add_output_buffer(&mut self, io_id: i32) -> Result<()> {
        unsafe {
            let p =
                ::ffi::flow_io_create_for_output_buffer(self.context_ptr(),
                                                        self.context_ptr() as *const libc::c_void);
            if p.is_null() {
                Err(self.ctx().get_error_copy().unwrap())
            } else {
                self.add_io_ptr(p, io_id, IoDirection::Out)
            }
        }
    }

    //    pub fn record_graphs(&self){
    //        let _ = unsafe { ::ffi::flow_job_configure_recording(self.context_ptr(),
    //                                                             self.as_ptr(),
    //                                                             true,
    //                                                             true,
    //                                                             true,
    //                                                             false,
    //                                                             false) };
    //    }
    pub fn configure_graph_recording(&mut self, recording: s::Build001GraphRecording) {
        let r = if std::env::var("CI").and_then(|s| Ok(s.to_uppercase())) ==
                   Ok("TRUE".to_owned()) {
            s::Build001GraphRecording::off()
        } else {
            recording
        };
        let _ = unsafe {
            ::ffi::flow_job_configure_recording(self.context_ptr(),
                                                self.as_ptr(),
                                                r.record_graph_versions
                                                    .unwrap_or(false),
                                                r.record_frame_images
                                                    .unwrap_or(false),
                                                r.render_last_graph
                                                    .unwrap_or(false),
                                                r.render_graph_versions
                                                    .unwrap_or(false),
                                                r.render_animated_graph
                                                    .unwrap_or(false))
        };
    }

    pub fn get_image_info(&mut self, io_id: i32) -> Result<s::ImageInfo> {
        unsafe {
            let mut info: ::ffi::DecoderInfo = ::ffi::DecoderInfo { ..Default::default() };

            if !::ffi::flow_job_get_decoder_info(self.context_ptr(),
                                                 self.as_ptr(),
                                                 io_id,
                                                 &mut info) {
                ContextPtr::from_ptr(self.context_ptr()).assert_ok(None);
            }
            Ok(s::ImageInfo {
                frame_decodes_into: s::PixelFormat::from(info.frame_decodes_into),
                image_height: info.image_height,
                image_width: info.image_width,
                frame_count: info.frame_count,
                current_frame_index: info.current_frame_index,
                preferred_extension: std::ffi::CStr::from_ptr(info.preferred_extension)
                    .to_owned()
                    .into_string()
                    .unwrap(),
                preferred_mime_type: std::ffi::CStr::from_ptr(info.preferred_mime_type)
                    .to_owned()
                    .into_string()
                    .unwrap(),
            })
        }

    }

    pub fn tell_decoder(&mut self, io_id: i32, tell: s::DecoderCommand) -> Result<()> {
        unsafe {
            match tell {
                s::DecoderCommand::JpegDownscaleHints(hints) => {
                    if !::ffi::flow_job_decoder_set_downscale_hints_by_placeholder_id(self.context_ptr(),
                                                                                self.as_ptr(), io_id,
                                                                                hints.width, hints.height,
                                                                                hints.width, hints.height,
                                                                                hints.scale_luma_spatially.unwrap_or(false),
                                                                                hints.gamma_correct_for_srgb_during_spatial_luma_scaling.unwrap_or(false)

                    ){
                        panic!("");
                    }
                }
            }
        }
        Ok(())

    }

    pub fn message(&mut self, method: &str, json: &[u8]) -> Result<JsonResponse> {

        ::job_methods::JOB_ROUTER.invoke(self, method, json)
    }

    pub fn io_get_output_buffer_copy(&mut self, io_id: i32) -> Result<Vec<u8>> {
        unsafe {
            let io_p = ::ffi::flow_job_get_io(self.c, self.ptr, io_id);
            if io_p.is_null() {
                Err(self.ctx().get_error_copy().unwrap())
            } else {
                let mut buf_start: *const u8 = ptr::null();
                let mut buf_len: usize = 0;
                let worked = ::ffi::flow_io_get_output_buffer(self.c,
                                                              io_p,
                                                              &mut buf_start as *mut *const u8,
                                                              &mut buf_len as *mut usize);
                if !worked {
                    Err(self.ctx().get_error_copy().unwrap())
                } else if buf_start.is_null() {
                    // Not sure how output buffer is null... no writes yet?
                    Err(FlowError::ErrNotImpl)
                } else {
                    Ok((std::slice::from_raw_parts(buf_start, buf_len)).to_vec())
                }
            }
        }
    }

    pub fn collect_encode_results(g: &Graph) -> Vec<s::EncodeResult>{
        let mut encodes = Vec::new();
        for node in g.raw_nodes() {
            if let ::flow::definitions::NodeResult::Encoded(ref r) = node.weight.result {
                encodes.push((*r).clone());
            }
        }
        encodes
    }
    pub fn collect_augmented_encode_results(&mut self, g: &Graph, io: &[s::IoObject]) -> Vec<s::EncodeResult>{
        JobPtr::collect_encode_results(g).into_iter().map(|r: s::EncodeResult|{
            if r.bytes == s::ResultBytes::Elsewhere {
                let obj: &s::IoObject = io.iter().find(|obj| obj.io_id == r.io_id).unwrap();//There's gotta be one
                let bytes = match obj.io {
                    s::IoEnum::Filename(ref str) => s::ResultBytes::PhysicalFile(str.to_owned()),
                    s::IoEnum::OutputBase64 => {
                        let vec = self.io_get_output_buffer_copy(r.io_id).unwrap();
                        s::ResultBytes::Base64(vec.as_slice().to_base64(base64::Config{char_set: base64::CharacterSet::Standard, line_length: None, newline: base64::Newline::LF, pad: true}))
                    },
                    _ => s::ResultBytes::Elsewhere
                };
                s::EncodeResult{
                    bytes: bytes,
                    .. r
                }
            }else{
                r
            }

        }).collect::<Vec<s::EncodeResult>>()
    }

    fn ctx(&self) -> ContextPtr {
        ContextPtr::from_ptr(self.context_ptr())
    }
}

impl ContextPtr {
    pub fn create_abi_json_response(&mut self,
                                    json_bytes: std::borrow::Cow<[u8]>,
                                    status_code: i64)
                                    -> *const ImageflowJsonResponse {
        unsafe {
            let sizeof_struct = std::mem::size_of::<ImageflowJsonResponse>();

            let pointer = ::ffi::flow_context_calloc(self.ptr.unwrap(),
                                                     1,
                                                     sizeof_struct + json_bytes.len(),
                                                     ptr::null(),
                                                     self.ptr.unwrap() as *mut libc::c_void,
                                                     ptr::null(),
                                                     0) as *mut u8;
            // Return null on OOM
            if pointer.is_null() {
                return ::std::ptr::null();
            }
            let pointer_to_final_buffer =
                pointer.offset(sizeof_struct as isize) as *mut libc::uint8_t;
            let imageflow_response = &mut (*(pointer as *mut ImageflowJsonResponse));
            imageflow_response.buffer_utf8_no_nulls = pointer_to_final_buffer;
            imageflow_response.buffer_size = json_bytes.len();
            imageflow_response.status_code = status_code;

            let mut out_json_bytes = std::slice::from_raw_parts_mut(pointer_to_final_buffer,
                                                                    json_bytes.len());

            out_json_bytes.clone_from_slice(&json_bytes);

            imageflow_response as *const ImageflowJsonResponse
        }
    }

    pub fn message(&mut self, method: &str, json: &[u8]) -> Result<JsonResponse> {

        ::context_methods::CONTEXT_ROUTER.invoke(self, method, json)
    }

    pub fn create() -> Result<ContextPtr> {
        unsafe {
            let ptr = ::ffi::flow_context_create();

            if ptr.is_null() {
                Err(FlowError::Oom)
            } else {
                Ok(ContextPtr { ptr: Some(ptr) })
            }
        }
    }

    fn force_destroy(&mut self) {
        unsafe {
            self.ptr = match self.ptr {
                Some(ptr) => {
                    ::ffi::flow_context_destroy(ptr);
                    None
                }
                _ => None,
            }
        }
    }

    fn destroy_allowing_panics(&mut self) {
        unsafe {
            self.ptr = match self.ptr {
                Some(ptr) => {
                    if !::ffi::flow_context_begin_terminate(ptr) {
                        panic!("Error during context shutdown{:?}",
                               self.get_error_copy().unwrap());
                    }
                    ::ffi::flow_context_destroy(ptr);
                    None
                }
                _ => None,
            }
        }
    }

    pub fn from_ptr(ptr: *mut ::ffi::ImageflowContext) -> ContextPtr {
        ContextPtr {
            ptr: if ptr.is_null() { None } else { Some(ptr) }
        }
    }
    pub fn as_ptr(&self) -> Result<*mut ::ffi::ImageflowContext> {
        match self.ptr {
            Some(p) if !p.is_null() => Ok(p),
            _ => Err(FlowError::ContextInvalid),
        }
    }

    unsafe fn get_flow_err(&self, c: *mut ::ffi::ImageflowContext) -> FlowErr {

        let code = ::ffi::flow_context_error_reason(c);
        let mut buf = vec![0u8; 2048];

        let chars_written =
            ::ffi::flow_context_error_and_stacktrace(c, buf.as_mut_ptr(), buf.len(), false);

        if chars_written < 0 {
            panic!("Error msg doesn't fit in 2kb");
        } else {
            buf.resize(chars_written as usize, 0u8);
        }

        FlowErr {
            code: code,
            message_and_stack: String::from_utf8(buf).unwrap(),
        }

    }
    pub unsafe fn err_maybe(&self) -> Result<()> {
        match self.get_error_copy() {
            Some(err) => Err(err),
            None => Ok(()),
        }
    }

    pub unsafe fn assert_ok(&self, g: Option<&Graph>) {
        if let Some(which_error) = self.get_error_copy() {
            match which_error {
                FlowError::Err(e) => {
                    println!("Error {} {}\n", e.code, e.message_and_stack);
                    if (e.code == 72 || e.code == 73) && g.is_some() {
                        //                                let _ = ::flow::graph::print_to_stdout(
                        //                                    self.ptr.unwrap(),
                        //                                    g.unwrap() as &flow::graph::Graph);
                    }

                    panic!();
                }
                FlowError::Oom => {
                    panic!("Out of memory.");
                }
                FlowError::ErrNotImpl => {
                    panic!("Error not implemented");
                }
                FlowError::ContextInvalid => {
                    panic!("Context pointer null");
                }
                FlowError::NullArgument => {
                    panic!("Context pointer null");
                }
                other => {
                    panic!("{:?}", other);
                }
            }
        }
    }

    fn get_error_copy(&self) -> Option<FlowError> {
        unsafe {
            match self.ptr {
                Some(ptr) if ::ffi::flow_context_has_error(ptr) => {
                    match ::ffi::flow_context_error_reason(ptr) {
                        0 => panic!("Inconsistent errors"),
                        10 => Some(FlowError::Oom),
                        _ => Some(FlowError::Err(self.get_flow_err(ptr))),
                    }
                }
                None => Some(FlowError::ContextInvalid),
                Some(_) => None,
            }
        }
    }
}

<|endoftext|>


<commit_before>//! Utility macros.

// Helper struct used to trigger const eval errors when the const generic immediate value `IMM` is
// out of `[MIN-MAX]` range.
pub(crate) struct ValidateConstImm<const IMM: i32, const MIN: i32, const MAX: i32>;
impl<const IMM: i32, const MIN: i32, const MAX: i32> ValidateConstImm<IMM, MIN, MAX> {
    pub(crate) const VALID: () = {
        assert!(IMM >= MIN && IMM <= MAX, "IMM value not in expected range");
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm1 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm2 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 2) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm3 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 3) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm4 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 4) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm5 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 5) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm6 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 6) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm8 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 8) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm16 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 16) - 1 }>::VALID;
    };
}

#[allow(unused)]
macro_rules! static_assert {
    ($imm:ident : $ty:ty where $e:expr) => {{
        struct Validate<const $imm: $ty>();
        impl<const $imm: $ty> Validate<$imm> {
            const VALID: () = {
                assert!($e, concat!("Assertion failed: ", stringify!($e)));
            };
        }
        let _ = Validate::<$imm>::VALID;
    }};
}

#[allow(unused)]
macro_rules! types {
    ($(
        $(#[$doc:meta])*
        pub struct $name:ident($($fields:tt)*);
    )*) => ($(
        $(#[$doc])*
        #[derive(Copy, Clone, Debug)]
        #[allow(non_camel_case_types)]
        #[repr(simd)]
        #[allow(clippy::missing_inline_in_public_items)]
        pub struct $name($($fields)*);
    )*)
}

#[allow(unused)]
macro_rules! simd_shuffle2 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 2] = $idx;
        }

        simd_shuffle2($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 2] = $idx;
        simd_shuffle2($x, $y, IDX)
    }};
}

#[allow(unused_macros)]
macro_rules! simd_shuffle4 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 4] = $idx;
        }

        simd_shuffle4($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 4] = $idx;
        simd_shuffle4($x, $y, IDX)
    }};
}

#[allow(unused_macros)]
macro_rules! simd_shuffle8 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 8] = $idx;
        }

        simd_shuffle8($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 8] = $idx;
        simd_shuffle8($x, $y, IDX)
    }};
}

#[allow(unused_macros)]
macro_rules! simd_shuffle16 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 16] = $idx;
        }

        simd_shuffle16($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 16] = $idx;
        simd_shuffle16($x, $y, IDX)
    }};
}

#[allow(unused_macros)]
macro_rules! simd_shuffle32 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+> $(,)? $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 32] = $idx;
        }

        simd_shuffle32($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 32] = $idx;
        simd_shuffle32($x, $y, IDX)
    }};
}

#[allow(unused_macros)]
macro_rules! simd_shuffle64 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 64] = $idx;
        }

        simd_shuffle64($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 64] = $idx;
        simd_shuffle64($x, $y, IDX)
    }};
}
<commit_msg>Allow unused macro arms for simd_shuffle16 too<commit_after>//! Utility macros.

// Helper struct used to trigger const eval errors when the const generic immediate value `IMM` is
// out of `[MIN-MAX]` range.
pub(crate) struct ValidateConstImm<const IMM: i32, const MIN: i32, const MAX: i32>;
impl<const IMM: i32, const MIN: i32, const MAX: i32> ValidateConstImm<IMM, MIN, MAX> {
    pub(crate) const VALID: () = {
        assert!(IMM >= MIN && IMM <= MAX, "IMM value not in expected range");
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm1 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm2 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 2) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm3 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 3) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm4 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 4) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm5 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 5) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm6 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 6) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm8 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 8) - 1 }>::VALID;
    };
}

#[allow(unused_macros)]
macro_rules! static_assert_imm16 {
    ($imm:ident) => {
        let _ = $crate::core_arch::macros::ValidateConstImm::<$imm, 0, { (1 << 16) - 1 }>::VALID;
    };
}

#[allow(unused)]
macro_rules! static_assert {
    ($imm:ident : $ty:ty where $e:expr) => {{
        struct Validate<const $imm: $ty>();
        impl<const $imm: $ty> Validate<$imm> {
            const VALID: () = {
                assert!($e, concat!("Assertion failed: ", stringify!($e)));
            };
        }
        let _ = Validate::<$imm>::VALID;
    }};
}

#[allow(unused)]
macro_rules! types {
    ($(
        $(#[$doc:meta])*
        pub struct $name:ident($($fields:tt)*);
    )*) => ($(
        $(#[$doc])*
        #[derive(Copy, Clone, Debug)]
        #[allow(non_camel_case_types)]
        #[repr(simd)]
        #[allow(clippy::missing_inline_in_public_items)]
        pub struct $name($($fields)*);
    )*)
}

#[allow(unused)]
macro_rules! simd_shuffle2 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 2] = $idx;
        }

        simd_shuffle2($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 2] = $idx;
        simd_shuffle2($x, $y, IDX)
    }};
}

#[allow(unused_macros)]
macro_rules! simd_shuffle4 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 4] = $idx;
        }

        simd_shuffle4($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 4] = $idx;
        simd_shuffle4($x, $y, IDX)
    }};
}

#[allow(unused_macros)]
macro_rules! simd_shuffle8 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 8] = $idx;
        }

        simd_shuffle8($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 8] = $idx;
        simd_shuffle8($x, $y, IDX)
    }};
}

#[allow(unused)]
macro_rules! simd_shuffle16 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 16] = $idx;
        }

        simd_shuffle16($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 16] = $idx;
        simd_shuffle16($x, $y, IDX)
    }};
}

#[allow(unused_macros)]
macro_rules! simd_shuffle32 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+> $(,)? $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 32] = $idx;
        }

        simd_shuffle32($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 32] = $idx;
        simd_shuffle32($x, $y, IDX)
    }};
}

#[allow(unused_macros)]
macro_rules! simd_shuffle64 {
    ($x:expr, $y:expr, <$(const $imm:ident : $ty:ty),+ $(,)?> $idx:expr $(,)?) => {{
        struct ConstParam<$(const $imm: $ty),+>;
        impl<$(const $imm: $ty),+> ConstParam<$($imm),+> {
            const IDX: [u32; 64] = $idx;
        }

        simd_shuffle64($x, $y, ConstParam::<$($imm),+>::IDX)
    }};
    ($x:expr, $y:expr, $idx:expr $(,)?) => {{
        const IDX: [u32; 64] = $idx;
        simd_shuffle64($x, $y, IDX)
    }};
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;

use capnp_rpc::{RpcSystem, twoparty, rpc_twoparty_capnp};
use pubsub_capnp::{publisher, subscriber, subscription};

use capnp::capability::Promise;
use capnp::Error;

use futures::{Future, Stream};

use tokio_core::reactor;
use tokio_core::io::Io;

struct SubscriberHandle {
    client: subscriber::Client<::capnp::text::Owned>,
    requests_in_flight: i32,
}

struct SubscriberMap {
    subscribers: HashMap<u64, SubscriberHandle>,
}

impl SubscriberMap {
    fn new() -> SubscriberMap {
        SubscriberMap { subscribers: HashMap::new() }
    }
}

struct SubscriptionImpl {
    id: u64,
    subscribers: Rc<RefCell<SubscriberMap>>,
}

impl SubscriptionImpl {
    fn new(id: u64, subscribers: Rc<RefCell<SubscriberMap>>) -> SubscriptionImpl {
        SubscriptionImpl { id: id, subscribers: subscribers }
    }
}

impl Drop for SubscriptionImpl {
    fn drop(&mut self) {
        println!("subscription dropped");
        self.subscribers.borrow_mut().subscribers.remove(&self.id);
    }
}

impl subscription::Server for SubscriptionImpl {}

struct PublisherImpl {
    next_id: u64,
    subscribers: Rc<RefCell<SubscriberMap>>,
}

impl PublisherImpl {
    pub fn new() -> (PublisherImpl, Rc<RefCell<SubscriberMap>>) {
        let subscribers = Rc::new(RefCell::new(SubscriberMap::new()));
        (PublisherImpl { next_id: 0, subscribers: subscribers.clone() },
         subscribers.clone())
    }
}

impl publisher::Server<::capnp::text::Owned> for PublisherImpl {
    fn subscribe(&mut self,
                 params: publisher::SubscribeParams<::capnp::text::Owned>,
                 mut results: publisher::SubscribeResults<::capnp::text::Owned>,)
                 -> Promise<(), ::capnp::Error>
    {
        println!("subscribe");
        self.subscribers.borrow_mut().subscribers.insert(
            self.next_id,
            SubscriberHandle {
                client: pry!(pry!(params.get()).get_subscriber()),
                requests_in_flight: 0,
            }
        );

        results.get().set_subscription(
            subscription::ToClient::new(SubscriptionImpl::new(self.next_id, self.subscribers.clone()))
                .from_server::<::capnp_rpc::Server>());

        self.next_id += 1;
        Promise::ok(())
    }
}

/*
fn send_to_subscribers(subscribers: Rc<RefCell<SubscriberMap>>,
                       task_set: Rc<RefCell<TaskSet<(), ::capnp::Error>>>)
                       -> Promise<(), ::capnp::Error>
{
    timer.after_delay(::std::time::Duration::new(1, 0)).lift().then(move |()| {
        {
            let subscribers1 = subscribers.clone();
            let subs = &mut subscribers.borrow_mut().subscribers;
            for (&idx, mut subscriber) in subs.iter_mut() {
                if subscriber.requests_in_flight < 5 {
                    subscriber.requests_in_flight += 1;
                    let mut request = subscriber.client.push_message_request();
                    pry!(request.get().set_message(
                        &format!("system time is: {:?}", ::std::time::SystemTime::now())[..]));

                    let subscribers2 = subscribers1.clone();
                    task_set.borrow_mut().add(request.send().promise.map_else(move |r| {
                        match r {
                            Ok(_) => {
                                subscribers2.borrow_mut().subscribers.get_mut(&idx).map(|ref mut s| {
                                    s.requests_in_flight -= 1;
                                });
                            }
                            Err(e) => {
                                println!("Got error: {:?}. Dropping subscriber.", e);
                                subscribers2.borrow_mut().subscribers.remove(&idx);
                            }
                        }
                        Ok(())
                    }));
                }
            }
        }
        send_to_subscribers(subscribers, timer, task_set)
    })
}
*/

pub fn main() {
    use std::net::ToSocketAddrs;
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} server HOST:PORT", args[0]);
        return;
    }

    let mut core = reactor::Core::new().unwrap();
    let handle = core.handle();

    let addr = args[2].to_socket_addrs().unwrap().next().expect("could not parse address");
    let socket = ::tokio_core::net::TcpListener::bind(&addr, &handle).unwrap();

    let (publisher_impl, subscribers) = PublisherImpl::new();

    let publisher = publisher::ToClient::new(publisher_impl).from_server::<::capnp_rpc::Server>();

    let handle1 = handle.clone();
    let done = socket.incoming().for_each(move |(socket, _addr)| {
        let (reader, writer) = socket.split();
        let handle = handle1.clone();

        let mut network =
            twoparty::VatNetwork::new(reader, writer, &handle,
                                      rpc_twoparty_capnp::Side::Server, Default::default());
        let disconnect_promise = network.on_disconnect();

        let rpc_system = RpcSystem::new(Box::new(network), Some(publisher.clone().client), handle.clone());

        handle.spawn(disconnect_promise.and_then(move |()| { drop(rpc_system); Ok(()) }).map_err(|_| ()));

        Ok(())
    }).map_err(|e| e.into());

    let infinite = ::futures::stream::iter(::std::iter::repeat(()).map(Ok::<(), Error>));
    let send_to_subscribers = infinite.fold((handle, subscribers), move |(handle, subscribers), ()| -> Promise<(::tokio_core::reactor::Handle, Rc<RefCell<SubscriberMap>>), Error> {
        {
            let subscribers1 = subscribers.clone();
            let subs = &mut subscribers.borrow_mut().subscribers;
            for (&idx, mut subscriber) in subs.iter_mut() {
                if subscriber.requests_in_flight < 5 {
                    subscriber.requests_in_flight += 1;
                    let mut request = subscriber.client.push_message_request();
                    pry!(request.get().set_message(
                        &format!("system time is: {:?}", ::std::time::SystemTime::now())[..]));

                    let subscribers2 = subscribers1.clone();
                    handle.spawn(request.send().promise.then(move |r| {
                        match r {
                            Ok(_) => {
                                subscribers2.borrow_mut().subscribers.get_mut(&idx).map(|ref mut s| {
                                    s.requests_in_flight -= 1;
                                });
                            }
                            Err(e) => {
                                println!("Got error: {:?}. Dropping subscriber.", e);
                                subscribers2.borrow_mut().subscribers.remove(&idx);
                            }
                        }
                        Ok::<(), Error>(())
                    }).map_err(|_| unreachable!()));
                }
            }
        }

        let timeout = pry!(::tokio_core::reactor::Timeout::new(::std::time::Duration::from_secs(1), &handle));
        let timeout = timeout.and_then(move |()| Ok((handle, subscribers))).map_err(|e| e.into());
        Promise::from_future(timeout)
    });

    core.run(send_to_subscribers.join(done)).unwrap();
}
<commit_msg>delete dead code<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;

use capnp_rpc::{RpcSystem, twoparty, rpc_twoparty_capnp};
use pubsub_capnp::{publisher, subscriber, subscription};

use capnp::capability::Promise;
use capnp::Error;

use futures::{Future, Stream};

use tokio_core::reactor;
use tokio_core::io::Io;

struct SubscriberHandle {
    client: subscriber::Client<::capnp::text::Owned>,
    requests_in_flight: i32,
}

struct SubscriberMap {
    subscribers: HashMap<u64, SubscriberHandle>,
}

impl SubscriberMap {
    fn new() -> SubscriberMap {
        SubscriberMap { subscribers: HashMap::new() }
    }
}

struct SubscriptionImpl {
    id: u64,
    subscribers: Rc<RefCell<SubscriberMap>>,
}

impl SubscriptionImpl {
    fn new(id: u64, subscribers: Rc<RefCell<SubscriberMap>>) -> SubscriptionImpl {
        SubscriptionImpl { id: id, subscribers: subscribers }
    }
}

impl Drop for SubscriptionImpl {
    fn drop(&mut self) {
        println!("subscription dropped");
        self.subscribers.borrow_mut().subscribers.remove(&self.id);
    }
}

impl subscription::Server for SubscriptionImpl {}

struct PublisherImpl {
    next_id: u64,
    subscribers: Rc<RefCell<SubscriberMap>>,
}

impl PublisherImpl {
    pub fn new() -> (PublisherImpl, Rc<RefCell<SubscriberMap>>) {
        let subscribers = Rc::new(RefCell::new(SubscriberMap::new()));
        (PublisherImpl { next_id: 0, subscribers: subscribers.clone() },
         subscribers.clone())
    }
}

impl publisher::Server<::capnp::text::Owned> for PublisherImpl {
    fn subscribe(&mut self,
                 params: publisher::SubscribeParams<::capnp::text::Owned>,
                 mut results: publisher::SubscribeResults<::capnp::text::Owned>,)
                 -> Promise<(), ::capnp::Error>
    {
        println!("subscribe");
        self.subscribers.borrow_mut().subscribers.insert(
            self.next_id,
            SubscriberHandle {
                client: pry!(pry!(params.get()).get_subscriber()),
                requests_in_flight: 0,
            }
        );

        results.get().set_subscription(
            subscription::ToClient::new(SubscriptionImpl::new(self.next_id, self.subscribers.clone()))
                .from_server::<::capnp_rpc::Server>());

        self.next_id += 1;
        Promise::ok(())
    }
}
pub fn main() {
    use std::net::ToSocketAddrs;
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} server HOST:PORT", args[0]);
        return;
    }

    let mut core = reactor::Core::new().unwrap();
    let handle = core.handle();

    let addr = args[2].to_socket_addrs().unwrap().next().expect("could not parse address");
    let socket = ::tokio_core::net::TcpListener::bind(&addr, &handle).unwrap();

    let (publisher_impl, subscribers) = PublisherImpl::new();

    let publisher = publisher::ToClient::new(publisher_impl).from_server::<::capnp_rpc::Server>();

    let handle1 = handle.clone();
    let done = socket.incoming().for_each(move |(socket, _addr)| {
        let (reader, writer) = socket.split();
        let handle = handle1.clone();

        let mut network =
            twoparty::VatNetwork::new(reader, writer, &handle,
                                      rpc_twoparty_capnp::Side::Server, Default::default());
        let disconnect_promise = network.on_disconnect();

        let rpc_system = RpcSystem::new(Box::new(network), Some(publisher.clone().client), handle.clone());

        handle.spawn(disconnect_promise.and_then(move |()| { drop(rpc_system); Ok(()) }).map_err(|_| ()));

        Ok(())
    }).map_err(|e| e.into());

    let infinite = ::futures::stream::iter(::std::iter::repeat(()).map(Ok::<(), Error>));
    let send_to_subscribers = infinite.fold((handle, subscribers), move |(handle, subscribers), ()| -> Promise<(::tokio_core::reactor::Handle, Rc<RefCell<SubscriberMap>>), Error> {
        {
            let subscribers1 = subscribers.clone();
            let subs = &mut subscribers.borrow_mut().subscribers;
            for (&idx, mut subscriber) in subs.iter_mut() {
                if subscriber.requests_in_flight < 5 {
                    subscriber.requests_in_flight += 1;
                    let mut request = subscriber.client.push_message_request();
                    pry!(request.get().set_message(
                        &format!("system time is: {:?}", ::std::time::SystemTime::now())[..]));

                    let subscribers2 = subscribers1.clone();
                    handle.spawn(request.send().promise.then(move |r| {
                        match r {
                            Ok(_) => {
                                subscribers2.borrow_mut().subscribers.get_mut(&idx).map(|ref mut s| {
                                    s.requests_in_flight -= 1;
                                });
                            }
                            Err(e) => {
                                println!("Got error: {:?}. Dropping subscriber.", e);
                                subscribers2.borrow_mut().subscribers.remove(&idx);
                            }
                        }
                        Ok::<(), Error>(())
                    }).map_err(|_| unreachable!()));
                }
            }
        }

        let timeout = pry!(::tokio_core::reactor::Timeout::new(::std::time::Duration::from_secs(1), &handle));
        let timeout = timeout.and_then(move |()| Ok((handle, subscribers))).map_err(|e| e.into());
        Promise::from_future(timeout)
    });

    core.run(send_to_subscribers.join(done)).unwrap();
}
<|endoftext|>