<commit_before>extern mod extra;

use extra::json;
use extra::json::Json;
use extra::uuid::Uuid;
use std::rt::io::Decorator;
use std::rt::io::extensions::{WriterByteConversions, ReaderByteConversions};
use std::rt::io::mem::{MemWriter, BufReader};
use std::str;

pub type Oid = i32;

// Values from pg_type.h
static BOOLOID: Oid = 16;
static BYTEAOID: Oid = 17;
static CHAROID: Oid = 18;
static INT8OID: Oid = 20;
static INT2OID: Oid = 21;
static INT4OID: Oid = 23;
static TEXTOID: Oid = 25;
static JSONOID: Oid = 114;
static FLOAT4OID: Oid = 700;
static FLOAT8OID: Oid = 701;
static BPCHAROID: Oid = 1042;
static VARCHAROID: Oid = 1043;
static UUIDOID: Oid = 2950;

#[deriving(Eq)]
pub enum PostgresType {
    PgBool,
    PgByteA,
    PgChar,
    PgInt8,
    PgInt2,
    PgInt4,
    PgText,
    PgJson,
    PgFloat4,
    PgFloat8,
    PgCharN,
    PgVarchar,
    PgUuid,
    PgUnknownType(Oid)
}

impl PostgresType {
    pub fn from_oid(oid: Oid) -> PostgresType {
        match oid {
            BOOLOID => PgBool,
            BYTEAOID => PgByteA,
            CHAROID => PgChar,
            INT8OID => PgInt8,
            INT2OID => PgInt2,
            INT4OID => PgInt4,
            TEXTOID => PgText,
            JSONOID => PgJson,
            FLOAT4OID => PgFloat4,
            FLOAT8OID => PgFloat8,
            BPCHAROID => PgCharN,
            VARCHAROID => PgVarchar,
            UUIDOID => PgUuid,
            oid => PgUnknownType(oid)
        }
    }

    pub fn result_format(&self) -> Format {
        match *self {
            PgBool
            | PgByteA
            | PgInt8
            | PgInt2
            | PgInt4
            | PgFloat4
            | PgFloat8
            | PgUuid => Binary,
            _ => Text
        }
    }
}

pub enum Format {
    Text = 0,
    Binary = 1
}

macro_rules! check_types(
    ($($expected:pat)|+, $actual:ident) => (
        match $actual {
            $($expected)|+ => (),
            actual => fail2!("Invalid Postgres type {:?}", actual)
        }
    )
)

pub trait FromSql {
    fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Self;
}

macro_rules! from_map_impl(
    ($($expected:pat)|+, $t:ty, $blk:expr) => (
        impl FromSql for Option<$t> {
            fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<$t> {
                check_types!($($expected)|+, ty)
                raw.map($blk)
            }
        }
    )
)

macro_rules! from_conversions_impl(
    ($expected:pat, $t:ty, $f:ident) => (
        from_map_impl!($expected, $t, |buf| {
            let mut reader = BufReader::new(buf.as_slice());
            reader.$f()
        })
    )
)

macro_rules! from_option_impl(
    ($t:ty) => (
        impl FromSql for $t {
            fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> $t {
                // FIXME when you can specify Self types properly
                let ret: Option<$t> = FromSql::from_sql(ty, raw);
                ret.unwrap()
            }
        }
    )
)

from_map_impl!(PgBool, bool, |buf| { buf[0] != 0 })
from_option_impl!(bool)

from_conversions_impl!(PgChar, i8, read_i8_)
from_option_impl!(i8)
from_conversions_impl!(PgInt2, i16, read_be_i16_)
from_option_impl!(i16)
from_conversions_impl!(PgInt4, i32, read_be_i32_)
from_option_impl!(i32)
from_conversions_impl!(PgInt8, i64, read_be_i64_)
from_option_impl!(i64)
from_conversions_impl!(PgFloat4, f32, read_be_f32_)
from_option_impl!(f32)
from_conversions_impl!(PgFloat8, f64, read_be_f64_)
from_option_impl!(f64)

from_map_impl!(PgVarchar | PgText | PgCharN, ~str, |buf| {
    str::from_utf8(buf.as_slice())
})
from_option_impl!(~str)

impl FromSql for Option<~[u8]> {
    fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<~[u8]> {
        check_types!(PgByteA, ty)
        raw.clone()
    }
}
from_option_impl!(~[u8])

from_map_impl!(PgJson, Json, |buf| {
    json::from_str(str::from_utf8_slice(buf.as_slice())).unwrap()
})
from_option_impl!(Json)

from_map_impl!(PgUuid, Uuid, |buf| {
    Uuid::from_utf8(buf.as_slice()).unwrap()
})
from_option_impl!(Uuid)

pub trait ToSql {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>);
}

macro_rules! to_option_impl(
    ($($oid:ident)|+, $t:ty) => (
        impl ToSql for Option<$t> {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_types!($($oid)|+, ty)

                match *self {
                    None => (Text, None),
                    Some(ref val) => val.to_sql(ty)
                }
            }
        }
    );
    (self, $($oid:ident)|+, $t:ty) => (
        impl<'self> ToSql for Option<$t> {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_types!($($oid)|+, ty)

                match *self {
                    None => (Text, None),
                    Some(ref val) => val.to_sql(ty)
                }
            }
        }
    )
)

macro_rules! to_conversions_impl(
    ($($oid:ident)|+, $t:ty, $f:ident) => (
        impl ToSql for $t {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_types!($($oid)|+, ty)

                let mut writer = MemWriter::new();
                writer.$f(*self);
                (Binary, Some(writer.inner()))
            }
        }
    )
)

impl ToSql for bool {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgBool, ty)
        (Binary, Some(~[*self as u8]))
    }
}
to_option_impl!(PgBool, bool)

to_conversions_impl!(PgChar, i8, write_i8_)
to_option_impl!(PgChar, i8)
to_conversions_impl!(PgInt2, i16, write_be_i16_)
to_option_impl!(PgInt2, i16)
to_conversions_impl!(PgInt4, i32, write_be_i32_)
to_option_impl!(PgInt4, i32)
to_conversions_impl!(PgInt8, i64, write_be_i64_)
to_option_impl!(PgInt8, i64)
to_conversions_impl!(PgFloat4, f32, write_be_f32_)
to_option_impl!(PgFloat4, f32)
to_conversions_impl!(PgFloat8, f64, write_be_f64_)
to_option_impl!(PgFloat8, f64)

impl ToSql for ~str {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgVarchar | PgText | PgCharN, ty)
        (Text, Some(self.as_bytes().to_owned()))
    }
}

impl<'self> ToSql for &'self str {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgVarchar | PgText | PgCharN, ty)
        (Text, Some(self.as_bytes().to_owned()))
    }
}

to_option_impl!(PgVarchar | PgText | PgCharN, ~str)
to_option_impl!(self, PgVarchar | PgText | PgCharN, &'self str)

impl ToSql for ~[u8] {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgByteA, ty)
        (Binary, Some(self.to_owned()))
    }
}

impl<'self> ToSql for &'self [u8] {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgByteA, ty)
        (Binary, Some(self.to_owned()))
    }
}

to_option_impl!(PgByteA, ~[u8])
to_option_impl!(self, PgByteA, &'self [u8])

impl ToSql for Json {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgJson, ty)
        (Text, Some(self.to_str().into_bytes()))
    }
}

to_option_impl!(PgJson, Json)

impl ToSql for Uuid {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgUuid, ty)
        (Binary, Some(self.to_bytes().to_owned()))
    }
}

to_option_impl!(PgUuid, Uuid)
<commit_msg>Update to newest master<commit_after>extern mod extra;

use extra::json;
use extra::json::Json;
use extra::uuid::Uuid;
use std::rt::io::Decorator;
use std::rt::io::extensions::{WriterByteConversions, ReaderByteConversions};
use std::rt::io::mem::{MemWriter, BufReader};
use std::str;

pub type Oid = i32;

// Values from pg_type.h
static BOOLOID: Oid = 16;
static BYTEAOID: Oid = 17;
static CHAROID: Oid = 18;
static INT8OID: Oid = 20;
static INT2OID: Oid = 21;
static INT4OID: Oid = 23;
static TEXTOID: Oid = 25;
static JSONOID: Oid = 114;
static FLOAT4OID: Oid = 700;
static FLOAT8OID: Oid = 701;
static BPCHAROID: Oid = 1042;
static VARCHAROID: Oid = 1043;
static UUIDOID: Oid = 2950;

#[deriving(Eq)]
pub enum PostgresType {
    PgBool,
    PgByteA,
    PgChar,
    PgInt8,
    PgInt2,
    PgInt4,
    PgText,
    PgJson,
    PgFloat4,
    PgFloat8,
    PgCharN,
    PgVarchar,
    PgUuid,
    PgUnknownType(Oid)
}

impl PostgresType {
    pub fn from_oid(oid: Oid) -> PostgresType {
        match oid {
            BOOLOID => PgBool,
            BYTEAOID => PgByteA,
            CHAROID => PgChar,
            INT8OID => PgInt8,
            INT2OID => PgInt2,
            INT4OID => PgInt4,
            TEXTOID => PgText,
            JSONOID => PgJson,
            FLOAT4OID => PgFloat4,
            FLOAT8OID => PgFloat8,
            BPCHAROID => PgCharN,
            VARCHAROID => PgVarchar,
            UUIDOID => PgUuid,
            oid => PgUnknownType(oid)
        }
    }

    pub fn result_format(&self) -> Format {
        match *self {
            PgBool
            | PgByteA
            | PgInt8
            | PgInt2
            | PgInt4
            | PgFloat4
            | PgFloat8
            | PgUuid => Binary,
            _ => Text
        }
    }
}

pub enum Format {
    Text = 0,
    Binary = 1
}

macro_rules! check_types(
    ($($expected:pat)|+, $actual:ident) => (
        match $actual {
            $($expected)|+ => (),
            actual => fail2!("Invalid Postgres type {:?}", actual)
        }
    )
)

pub trait FromSql {
    fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Self;
}

macro_rules! from_map_impl(
    ($($expected:pat)|+, $t:ty, $blk:expr) => (
        impl FromSql for Option<$t> {
            fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<$t> {
                check_types!($($expected)|+, ty)
                raw.map($blk)
            }
        }
    )
)

macro_rules! from_conversions_impl(
    ($expected:pat, $t:ty, $f:ident) => (
        from_map_impl!($expected, $t, |buf| {
            let mut reader = BufReader::new(buf.as_slice());
            reader.$f()
        })
    )
)

macro_rules! from_option_impl(
    ($t:ty) => (
        impl FromSql for $t {
            fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> $t {
                // FIXME when you can specify Self types properly
                let ret: Option<$t> = FromSql::from_sql(ty, raw);
                ret.unwrap()
            }
        }
    )
)

from_map_impl!(PgBool, bool, |buf| { buf[0] != 0 })
from_option_impl!(bool)

from_conversions_impl!(PgChar, i8, read_i8_)
from_option_impl!(i8)
from_conversions_impl!(PgInt2, i16, read_be_i16_)
from_option_impl!(i16)
from_conversions_impl!(PgInt4, i32, read_be_i32_)
from_option_impl!(i32)
from_conversions_impl!(PgInt8, i64, read_be_i64_)
from_option_impl!(i64)
from_conversions_impl!(PgFloat4, f32, read_be_f32_)
from_option_impl!(f32)
from_conversions_impl!(PgFloat8, f64, read_be_f64_)
from_option_impl!(f64)

from_map_impl!(PgVarchar | PgText | PgCharN, ~str, |buf| {
    str::from_utf8(buf.as_slice())
})
from_option_impl!(~str)

impl FromSql for Option<~[u8]> {
    fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<~[u8]> {
        check_types!(PgByteA, ty)
        raw.clone()
    }
}
from_option_impl!(~[u8])

from_map_impl!(PgJson, Json, |buf| {
    json::from_str(str::from_utf8_slice(buf.as_slice())).unwrap()
})
from_option_impl!(Json)

from_map_impl!(PgUuid, Uuid, |buf| {
    Uuid::from_bytes(buf.as_slice()).unwrap()
})
from_option_impl!(Uuid)

pub trait ToSql {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>);
}

macro_rules! to_option_impl(
    ($($oid:ident)|+, $t:ty) => (
        impl ToSql for Option<$t> {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_types!($($oid)|+, ty)

                match *self {
                    None => (Text, None),
                    Some(ref val) => val.to_sql(ty)
                }
            }
        }
    );
    (self, $($oid:ident)|+, $t:ty) => (
        impl<'self> ToSql for Option<$t> {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_types!($($oid)|+, ty)

                match *self {
                    None => (Text, None),
                    Some(ref val) => val.to_sql(ty)
                }
            }
        }
    )
)

macro_rules! to_conversions_impl(
    ($($oid:ident)|+, $t:ty, $f:ident) => (
        impl ToSql for $t {
            fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
                check_types!($($oid)|+, ty)

                let mut writer = MemWriter::new();
                writer.$f(*self);
                (Binary, Some(writer.inner()))
            }
        }
    )
)

impl ToSql for bool {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgBool, ty)
        (Binary, Some(~[*self as u8]))
    }
}
to_option_impl!(PgBool, bool)

to_conversions_impl!(PgChar, i8, write_i8_)
to_option_impl!(PgChar, i8)
to_conversions_impl!(PgInt2, i16, write_be_i16_)
to_option_impl!(PgInt2, i16)
to_conversions_impl!(PgInt4, i32, write_be_i32_)
to_option_impl!(PgInt4, i32)
to_conversions_impl!(PgInt8, i64, write_be_i64_)
to_option_impl!(PgInt8, i64)
to_conversions_impl!(PgFloat4, f32, write_be_f32_)
to_option_impl!(PgFloat4, f32)
to_conversions_impl!(PgFloat8, f64, write_be_f64_)
to_option_impl!(PgFloat8, f64)

impl ToSql for ~str {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgVarchar | PgText | PgCharN, ty)
        (Text, Some(self.as_bytes().to_owned()))
    }
}

impl<'self> ToSql for &'self str {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgVarchar | PgText | PgCharN, ty)
        (Text, Some(self.as_bytes().to_owned()))
    }
}

to_option_impl!(PgVarchar | PgText | PgCharN, ~str)
to_option_impl!(self, PgVarchar | PgText | PgCharN, &'self str)

impl ToSql for ~[u8] {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgByteA, ty)
        (Binary, Some(self.to_owned()))
    }
}

impl<'self> ToSql for &'self [u8] {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgByteA, ty)
        (Binary, Some(self.to_owned()))
    }
}

to_option_impl!(PgByteA, ~[u8])
to_option_impl!(self, PgByteA, &'self [u8])

impl ToSql for Json {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgJson, ty)
        (Text, Some(self.to_str().into_bytes()))
    }
}

to_option_impl!(PgJson, Json)

impl ToSql for Uuid {
    fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
        check_types!(PgUuid, ty)
        (Binary, Some(self.to_bytes().to_owned()))
    }
}

to_option_impl!(PgUuid, Uuid)
<|endoftext|>


<commit_before>//!
//! Miscellaneous utility functions.
//!

use std::f64::consts::PI;
use std::num::{Float, Int};
use std::num::NumCast;

/// Convert turns to radians.
pub fn turns<F: Float>(t: F) -> F {
    NumCast::from(2.0 * PI).unwrap() / t
}

/// Convert degrees to radians.
pub fn degrees<F: Float>(d: F) -> F {
    d * NumCast::from(PI / 180.0).unwrap()
}

/// The modulo function.
#[inline]
pub fn modulo<I: Int>(a: I, b: I) -> I {
    match a % b {
        r if (r > Int::zero() && b < Int::zero())
          || (r < Int::zero() && b > Int::zero()) => (r + b),
        r                                         => r,
    }
}

/// Modulo float.
pub fn fmod(f: f32, n: i32) -> f32 {
    let i = f.floor() as i32;
    modulo(i, n) as f32 + f - i as f32
}

/// Return the max between to floats.
pub fn max(a: f32, b: f32) -> f32 {
    if a >= b { a } else { b }
}

/// Return the min between to floats.
pub fn min(a: f32, b: f32) -> f32 {
    if a <= b { a } else { b }
}

<commit_msg>Fixed cast type inference error<commit_after>//!
//! Miscellaneous utility functions.
//!

use std::f64::consts::PI;
use std::num::{Float, Int};
use std::num::cast;

/// Convert turns to radians.
pub fn turns<F: Float>(t: F) -> F {
    let f: F = cast(2.0 * PI).unwrap();
    f / t
}

/// Convert degrees to radians.
pub fn degrees<F: Float>(d: F) -> F {
    d * cast(PI / 180.0).unwrap()
}

/// The modulo function.
#[inline]
pub fn modulo<I: Int>(a: I, b: I) -> I {
    match a % b {
        r if (r > Int::zero() && b < Int::zero())
          || (r < Int::zero() && b > Int::zero()) => (r + b),
        r                                         => r,
    }
}

/// Modulo float.
pub fn fmod(f: f32, n: i32) -> f32 {
    let i = f.floor() as i32;
    modulo(i, n) as f32 + f - i as f32
}

/// Return the max between to floats.
pub fn max(a: f32, b: f32) -> f32 {
    if a >= b { a } else { b }
}

/// Return the min between to floats.
pub fn min(a: f32, b: f32) -> f32 {
    if a <= b { a } else { b }
}

<|endoftext|>


<commit_before>use super::*;
use std::mem;

#[inline]
pub unsafe fn base_to_impl<T>(this: &development::MemberBase) -> &T
    where T: controls::Member + Sized
{
    mem::transmute(this)
}
#[inline]
pub unsafe fn base_to_impl_mut<T>(this: &mut development::MemberBase) -> &mut T
    where T: controls::Member + Sized
{
    mem::transmute(this)
}

#[inline]
pub fn member_control_base<T: development::ControlInner>(this: &development::Member<development::Control<T>>) -> &development::MemberControlBase {
	unsafe { mem::transmute(this) }
}
#[inline]
pub fn member_control_base_mut<T: development::ControlInner>(this: &mut development::Member<development::Control<T>>) -> &mut development::MemberControlBase {
	unsafe { mem::transmute(this) }
}

#[inline]
pub(crate) unsafe fn member_control_base_unchecked(this: &development::MemberBase) -> &development::MemberControlBase {
	mem::transmute(this)
}
#[inline]
pub(crate) unsafe fn member_control_base_mut_unchecked(this: &mut development::MemberBase) -> &mut development::MemberControlBase {
	mem::transmute(this)
}
<commit_msg>Uncover some util functions<commit_after>use super::*;
use std::mem;

#[inline]
pub unsafe fn base_to_impl<T>(this: &development::MemberBase) -> &T
    where T: controls::Member + Sized
{
    mem::transmute(this)
}
#[inline]
pub unsafe fn base_to_impl_mut<T>(this: &mut development::MemberBase) -> &mut T
    where T: controls::Member + Sized
{
    mem::transmute(this)
}

#[inline]
pub fn member_control_base<T: development::ControlInner>(this: &development::Member<development::Control<T>>) -> &development::MemberControlBase {
	unsafe { mem::transmute(this) }
}
#[inline]
pub fn member_control_base_mut<T: development::ControlInner>(this: &mut development::Member<development::Control<T>>) -> &mut development::MemberControlBase {
	unsafe { mem::transmute(this) }
}

#[inline]
pub unsafe fn member_control_base_unchecked(this: &development::MemberBase) -> &development::MemberControlBase {
	mem::transmute(this)
}
#[inline]
pub unsafe fn member_control_base_mut_unchecked(this: &mut development::MemberBase) -> &mut development::MemberControlBase {
	mem::transmute(this)
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! println_err(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

#[repr(C)]
pub enum GstFlowReturn {
    Ok = 0,
    NotLinked = -1,
    Flushing = -2,
    Eos = -3,
    NotNegotiated = -4,
    Error = -5,
}

#[repr(C)]
pub enum GBoolean {
    False = 0,
    True = 1,
}

impl GBoolean {
    pub fn from_bool(v: bool) -> GBoolean {
        match v {
            true => GBoolean::True,
            false => GBoolean::False,
        }
    }
}

<commit_msg>Ignore errors when printing to stderr<commit_after>#[macro_export]
macro_rules! println_err(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        // Ignore when writing fails
        match r {
            Ok(_) => (),
            Err(_) => ()
        };
    } }
);

#[repr(C)]
pub enum GstFlowReturn {
    Ok = 0,
    NotLinked = -1,
    Flushing = -2,
    Eos = -3,
    NotNegotiated = -4,
    Error = -5,
}

#[repr(C)]
pub enum GBoolean {
    False = 0,
    True = 1,
}

impl GBoolean {
    pub fn from_bool(v: bool) -> GBoolean {
        match v {
            true => GBoolean::True,
            false => GBoolean::False,
        }
    }
}

<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use super::address::SBAddress;
use super::data::SBData;
use super::error::SBError;
use super::frame::SBFrame;
use super::process::SBProcess;
use super::stream::SBStream;
use super::target::SBTarget;
use super::thread::SBThread;
use super::watchpoint::SBWatchpoint;
use super::lldb_addr_t;
use sys;

/// The value of a variable, register or expression.
pub struct SBValue {
    /// The underlying raw `SBValueRef`.
    pub raw: sys::SBValueRef,
}

impl SBValue {
    /// Construct a new `SBValue`.
    pub fn wrap(raw: sys::SBValueRef) -> SBValue {
        SBValue { raw: raw }
    }

    /// Construct a new `Some(SBValue)` or `None`.
    pub fn maybe_wrap(raw: sys::SBValueRef) -> Option<SBValue> {
        if unsafe { sys::SBValueIsValid(raw) != 0 } {
            Some(SBValue { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBValue` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBValueIsValid(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn dereference(&self) -> Option<SBValue> {
        SBValue::maybe_wrap(unsafe { sys::SBValueDereference(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn address_of(&self) -> Option<SBValue> {
        SBValue::maybe_wrap(unsafe { sys::SBValueAddressOf(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn type_is_pointer_type(&self) -> bool {
        unsafe { sys::SBValueTypeIsPointerType(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn target(&self) -> SBTarget {
        SBTarget::wrap(unsafe { sys::SBValueGetTarget(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn process(&self) -> SBProcess {
        SBProcess::wrap(unsafe { sys::SBValueGetProcess(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn thread(&self) -> SBThread {
        SBThread::wrap(unsafe { sys::SBValueGetThread(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn frame(&self) -> SBFrame {
        SBFrame::wrap(unsafe { sys::SBValueGetFrame(self.raw) })
    }

    /// Find and watch a variable.
    pub fn watch(&self,
                 resolve_location: bool,
                 read: bool,
                 write: bool)
                 -> Result<SBWatchpoint, SBError> {
        let error = SBError::new();
        let wp = unsafe {
            sys::SBValueWatch(self.raw,
                              resolve_location as u8,
                              read as u8,
                              write as u8,
                              error.raw)
        };
        if error.is_success() {
            Ok(SBWatchpoint::wrap(wp))
        } else {
            Err(error)
        }
    }

    /// Find and watch the location pointed to by a variable.
    pub fn watch_pointee(&self,
                         resolve_location: bool,
                         read: bool,
                         write: bool)
                         -> Result<SBWatchpoint, SBError> {
        let error = SBError::new();
        let wp = unsafe {
            sys::SBValueWatchPointee(self.raw,
                                     resolve_location as u8,
                                     read as u8,
                                     write as u8,
                                     error.raw)
        };
        if error.is_success() {
            Ok(SBWatchpoint::wrap(wp))
        } else {
            Err(error)
        }
    }

    /// Get an `SBData` wrapping what this `SBValue` points to.
    ///
    /// This method will dereference the current `SBValue`, if its
    /// data type is a `T*` or `T[]`, and extract `item_count` elements
    /// of type `T` from it, copying their contents into an `SBData`.
    ///
    /// `item_idx` is the index of the first item to retrieve. For an array
    /// this is equivalent to `array[item_idx]`, for a pointer
    /// to `*(pointer + item_idx)`. In either case, the measurement
    /// unit for `item_idx` is the `sizeof(T)` rather than bytes.
    ///
    /// `item_count` is how many items should be copied into the output.
    /// By default only one item is copied, but more can be asked for.
    ///
    /// Returns `Some(SBData)` with the contents of the copied items, on success.
    /// `None` otherwise.
    pub fn pointee_data(&self, item_idx: u32, item_count: u32) -> Option<SBData> {
        SBData::maybe_wrap(unsafe { sys::SBValueGetPointeeData(self.raw, item_idx, item_count) })
    }

    /// Get an `SBData` wrapping the contents of this `SBValue`.
    ///
    /// This method will read the contents of this object in memory
    /// and copy them into an `SBData` for future use.
    ///
    /// Returns `Some(SBData)` with the contents of this `SBValue`, on success.
    /// `None` otherwise.
    pub fn data(&self) -> Option<SBData> {
        SBData::maybe_wrap(unsafe { sys::SBValueGetData(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn set_data(&self, data: &SBData) -> Result<(), SBError> {
        let error = SBError::new();
        if unsafe { sys::SBValueSetData(self.raw, data.raw, error.raw) != 0 } {
            Ok(())
        } else {
            Err(error)
        }
    }

    #[allow(missing_docs)]
    pub fn load_address(&self) -> Option<lldb_addr_t> {
        let load_address = unsafe { sys::SBValueGetLoadAddress(self.raw) };
        if load_address != u64::max_value() {
            Some(load_address)
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn address(&self) -> Option<SBAddress> {
        SBAddress::maybe_wrap(unsafe { sys::SBValueGetAddress(self.raw) })
    }
}

impl fmt::Debug for SBValue {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBValueGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBValue {{ {} }}", stream.data())
    }
}

impl Drop for SBValue {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBValue(self.raw) };
    }
}
<commit_msg>Improve SBValue bindings.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::CStr;
use std::fmt;
use super::address::SBAddress;
use super::data::SBData;
use super::error::SBError;
use super::frame::SBFrame;
use super::process::SBProcess;
use super::stream::SBStream;
use super::target::SBTarget;
use super::thread::SBThread;
use super::watchpoint::SBWatchpoint;
use super::{lldb_addr_t, lldb_user_id_t, Format};
use sys;

/// The value of a variable, register or expression.
pub struct SBValue {
    /// The underlying raw `SBValueRef`.
    pub raw: sys::SBValueRef,
}

impl SBValue {
    /// Construct a new `SBValue`.
    pub fn wrap(raw: sys::SBValueRef) -> SBValue {
        SBValue { raw: raw }
    }

    /// Construct a new `Some(SBValue)` or `None`.
    pub fn maybe_wrap(raw: sys::SBValueRef) -> Option<SBValue> {
        if unsafe { sys::SBValueIsValid(raw) != 0 } {
            Some(SBValue { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBValue` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBValueIsValid(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn clear(&self) {
        unsafe { sys::SBValueClear(self.raw) };
    }

    #[allow(missing_docs)]
    pub fn error(&self) -> Option<SBError> {
        SBError::maybe_wrap(unsafe { sys::SBValueGetError(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn id(&self) -> lldb_user_id_t {
        unsafe { sys::SBValueGetID(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn name(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBValueGetName(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    #[allow(missing_docs)]
    pub fn type_name(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBValueGetTypeName(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    #[allow(missing_docs)]
    pub fn display_type_name(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBValueGetDisplayTypeName(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    #[allow(missing_docs)]
    pub fn byte_size(&self) -> usize {
        unsafe { sys::SBValueGetByteSize(self.raw) as usize }
    }

    #[allow(missing_docs)]
    pub fn is_in_scope(&self) -> bool {
        unsafe { sys::SBValueIsInScope(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn format(&self) -> Format {
        unsafe { sys::SBValueGetFormat(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_format(&mut self, format: Format) {
        unsafe { sys::SBValueSetFormat(self.raw, format) }
    }

    #[allow(missing_docs)]
    pub fn value(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBValueGetValue(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    #[allow(missing_docs)]
    pub fn dereference(&self) -> Option<SBValue> {
        SBValue::maybe_wrap(unsafe { sys::SBValueDereference(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn address_of(&self) -> Option<SBValue> {
        SBValue::maybe_wrap(unsafe { sys::SBValueAddressOf(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn type_is_pointer_type(&self) -> bool {
        unsafe { sys::SBValueTypeIsPointerType(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn target(&self) -> SBTarget {
        SBTarget::wrap(unsafe { sys::SBValueGetTarget(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn process(&self) -> SBProcess {
        SBProcess::wrap(unsafe { sys::SBValueGetProcess(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn thread(&self) -> SBThread {
        SBThread::wrap(unsafe { sys::SBValueGetThread(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn frame(&self) -> SBFrame {
        SBFrame::wrap(unsafe { sys::SBValueGetFrame(self.raw) })
    }

    /// Find and watch a variable.
    pub fn watch(&self,
                 resolve_location: bool,
                 read: bool,
                 write: bool)
                 -> Result<SBWatchpoint, SBError> {
        let error = SBError::new();
        let wp = unsafe {
            sys::SBValueWatch(self.raw,
                              resolve_location as u8,
                              read as u8,
                              write as u8,
                              error.raw)
        };
        if error.is_success() {
            Ok(SBWatchpoint::wrap(wp))
        } else {
            Err(error)
        }
    }

    /// Find and watch the location pointed to by a variable.
    pub fn watch_pointee(&self,
                         resolve_location: bool,
                         read: bool,
                         write: bool)
                         -> Result<SBWatchpoint, SBError> {
        let error = SBError::new();
        let wp = unsafe {
            sys::SBValueWatchPointee(self.raw,
                                     resolve_location as u8,
                                     read as u8,
                                     write as u8,
                                     error.raw)
        };
        if error.is_success() {
            Ok(SBWatchpoint::wrap(wp))
        } else {
            Err(error)
        }
    }

    /// Get an `SBData` wrapping what this `SBValue` points to.
    ///
    /// This method will dereference the current `SBValue`, if its
    /// data type is a `T*` or `T[]`, and extract `item_count` elements
    /// of type `T` from it, copying their contents into an `SBData`.
    ///
    /// `item_idx` is the index of the first item to retrieve. For an array
    /// this is equivalent to `array[item_idx]`, for a pointer
    /// to `*(pointer + item_idx)`. In either case, the measurement
    /// unit for `item_idx` is the `sizeof(T)` rather than bytes.
    ///
    /// `item_count` is how many items should be copied into the output.
    /// By default only one item is copied, but more can be asked for.
    ///
    /// Returns `Some(SBData)` with the contents of the copied items, on success.
    /// `None` otherwise.
    pub fn pointee_data(&self, item_idx: u32, item_count: u32) -> Option<SBData> {
        SBData::maybe_wrap(unsafe { sys::SBValueGetPointeeData(self.raw, item_idx, item_count) })
    }

    /// Get an `SBData` wrapping the contents of this `SBValue`.
    ///
    /// This method will read the contents of this object in memory
    /// and copy them into an `SBData` for future use.
    ///
    /// Returns `Some(SBData)` with the contents of this `SBValue`, on success.
    /// `None` otherwise.
    pub fn data(&self) -> Option<SBData> {
        SBData::maybe_wrap(unsafe { sys::SBValueGetData(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn set_data(&self, data: &SBData) -> Result<(), SBError> {
        let error = SBError::new();
        if unsafe { sys::SBValueSetData(self.raw, data.raw, error.raw) != 0 } {
            Ok(())
        } else {
            Err(error)
        }
    }

    #[allow(missing_docs)]
    pub fn load_address(&self) -> Option<lldb_addr_t> {
        let load_address = unsafe { sys::SBValueGetLoadAddress(self.raw) };
        if load_address != u64::max_value() {
            Some(load_address)
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn address(&self) -> Option<SBAddress> {
        SBAddress::maybe_wrap(unsafe { sys::SBValueGetAddress(self.raw) })
    }
}

impl fmt::Debug for SBValue {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBValueGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBValue {{ {} }}", stream.data())
    }
}

impl Drop for SBValue {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBValue(self.raw) };
    }
}

#[cfg(feature = "graphql")]
graphql_object!(SBValue: super::debugger::SBDebugger | &self | {
    field is_valid() -> bool {
        self.is_valid()
    }

    // TODO(bm): This should be u64
    field id() -> i64 {
        self.id() as i64
    }

    field name() -> &str {
        self.name()
    }

    field type_name() -> &str {
        self.type_name()
    }

    field display_type_name() -> &str {
        self.display_type_name()
    }

    // TODO(bm): This should be usize.
    field byte_size() -> i64 {
        self.byte_size() as i64
    }

    field is_in_scope() -> bool {
        self.is_in_scope()
    }
});
<|endoftext|>


<commit_before>//! Structs for creating a new zip archive

use compression::CompressionMethod;
use types::{ZipFileData, System, DEFAULT_VERSION};
use spec;
use crc32;
use result::{ZipResult, ZipError};
use std::default::Default;
use std::io;
use std::io::prelude::*;
use std::mem;
use std::ascii::AsciiExt;
use time;
use flate2;
use flate2::FlateWriteExt;
use flate2::write::DeflateEncoder;
use podio::{WritePodExt, LittleEndian};
use msdos_time::TmMsDosExt;

#[cfg(feature = "bzip2")]
use bzip2;
#[cfg(feature = "bzip2")]
use bzip2::write::BzEncoder;

enum GenericZipWriter<W: Write + io::Seek>
{
    Closed,
    Storer(W),
    Deflater(DeflateEncoder<W>),
    #[cfg(feature = "bzip2")]
    Bzip2(BzEncoder<W>),
}

/// Generator for ZIP files.
///
/// ```
/// fn doit() -> zip::result::ZipResult<()>
/// {
///     use std::io::Write;
///
///     // For this example we write to a buffer, but normally you should use a File
///     let mut buf: &mut [u8] = &mut [0u8; 65536];
///     let mut w = std::io::Cursor::new(buf);
///     let mut zip = zip::ZipWriter::new(w);
///
///     try!(zip.start_file("hello_world.txt", zip::CompressionMethod::Stored));
///     try!(zip.write(b"Hello, World!"));
///
///     // Optionally finish the zip. (this is also done on drop)
///     try!(zip.finish());
///
///     Ok(())
/// }
///
/// println!("Result: {:?}", doit());
/// ```
pub struct ZipWriter<W: Write + io::Seek>
{
    inner: GenericZipWriter<W>,
    files: Vec<ZipFileData>,
    stats: ZipWriterStats,
}

#[derive(Default)]
struct ZipWriterStats
{
    crc32: u32,
    start: u64,
    bytes_written: u64,
}

impl<W: Write+io::Seek> Write for ZipWriter<W>
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize>
    {
        if self.files.len() == 0 { return Err(io::Error::new(io::ErrorKind::Other, "No file has been started")) }
        match self.inner.ref_mut()
        {
            Some(ref mut w) => {
                let write_result = w.write(buf);
                if let Ok(count) = write_result {
                    self.stats.update(&buf[0..count]);
                }
                write_result

            }
            None => Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed")),
        }
    }

    fn flush(&mut self) -> io::Result<()>
    {
        match self.inner.ref_mut()
        {
            Some(ref mut w) => w.flush(),
            None => Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed")),
        }
    }
}

impl ZipWriterStats
{
    fn update(&mut self, buf: &[u8])
    {
        self.crc32 = crc32::update(self.crc32, buf);
        self.bytes_written += buf.len() as u64;
    }
}

impl<W: Write+io::Seek> ZipWriter<W>
{
    /// Initializes the ZipWriter.
    ///
    /// Before writing to this object, the start_file command should be called.
    pub fn new(inner: W) -> ZipWriter<W>
    {
        ZipWriter
        {
            inner: GenericZipWriter::Storer(inner),
            files: Vec::new(),
            stats: Default::default(),
        }
    }

    /// Start a new file for with the requested compression method.
    pub fn start_file<S>(&mut self, name: S, compression: CompressionMethod) -> ZipResult<()>
        where S: Into<String>
    {
        try!(self.finish_file());

        {
            let writer = self.inner.get_plain();
            let header_start = try!(writer.seek(io::SeekFrom::Current(0)));

            let mut file = ZipFileData
            {
                system: System::Dos,
                version_made_by: DEFAULT_VERSION,
                encrypted: false,
                compression_method: compression,
                last_modified_time: time::now(),
                crc32: 0,
                compressed_size: 0,
                uncompressed_size: 0,
                file_name: name.into(),
                file_comment: String::new(),
                header_start: header_start,
                data_start: 0,
                external_attributes: 0,
            };
            try!(write_local_file_header(writer, &file));

            let header_end = try!(writer.seek(io::SeekFrom::Current(0)));
            self.stats.start = header_end;
            file.data_start = header_end;

            self.stats.bytes_written = 0;
            self.stats.crc32 = 0;

            self.files.push(file);
        }

        try!(self.inner.switch_to(compression));

        Ok(())
    }

    fn finish_file(&mut self) -> ZipResult<()>
    {
        try!(self.inner.switch_to(CompressionMethod::Stored));
        let writer = self.inner.get_plain();

        let file = match self.files.last_mut()
        {
            None => return Ok(()),
            Some(f) => f,
        };
        file.crc32 = self.stats.crc32;
        file.uncompressed_size = self.stats.bytes_written;
        file.compressed_size = try!(writer.seek(io::SeekFrom::Current(0))) - self.stats.start;

        try!(update_local_file_header(writer, file));
        try!(writer.seek(io::SeekFrom::End(0)));
        Ok(())
    }

    /// Finish the last file and write all other zip-structures
    ///
    /// This will return the writer, but one should normally not append any data to the end of the file.
    /// Note that the zipfile will also be finished on drop.
    pub fn finish(&mut self) -> ZipResult<W>
    {
        try!(self.finalize());
        let inner = mem::replace(&mut self.inner, GenericZipWriter::Closed);
        Ok(inner.unwrap())
    }

    fn finalize(&mut self) -> ZipResult<()>
    {
        try!(self.finish_file());

        {
            let writer = self.inner.get_plain();

            let central_start = try!(writer.seek(io::SeekFrom::Current(0)));
            for file in self.files.iter()
            {
                try!(write_central_directory_header(writer, file));
            }
            let central_size = try!(writer.seek(io::SeekFrom::Current(0))) - central_start;

            let footer = spec::CentralDirectoryEnd
            {
                disk_number: 0,
                disk_with_central_directory: 0,
                number_of_files_on_this_disk: self.files.len() as u16,
                number_of_files: self.files.len() as u16,
                central_directory_size: central_size as u32,
                central_directory_offset: central_start as u32,
                zip_file_comment: b"zip-rs".to_vec(),
            };

            try!(footer.write(writer));
        }

        Ok(())
    }
}

impl<W: Write+io::Seek> Drop for ZipWriter<W>
{
    fn drop(&mut self)
    {
        if !self.inner.is_closed()
        {
            if let Err(e) = self.finalize() {
                let _ = write!(&mut io::stderr(), "ZipWriter drop failed: {:?}", e);
            }
        }
    }
}

impl<W: Write+io::Seek> GenericZipWriter<W>
{
    fn switch_to(&mut self, compression: CompressionMethod) -> ZipResult<()>
    {
        match self.current_compression() {
            Some(method) if method == compression => return Ok(()),
            None => try!(Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed"))),
            _ => {},
        }

        let bare = match mem::replace(self, GenericZipWriter::Closed)
        {
            GenericZipWriter::Storer(w) => w,
            GenericZipWriter::Deflater(w) => try!(w.finish()),
            #[cfg(feature = "bzip2")]
            GenericZipWriter::Bzip2(w) => try!(w.finish()),
            GenericZipWriter::Closed => try!(Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed"))),
        };

        *self = match compression
        {
            CompressionMethod::Stored => GenericZipWriter::Storer(bare),
            CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::Compression::Default)),
            #[cfg(feature = "bzip2")]
            CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzEncoder::new(bare, bzip2::Compression::Default)),
            CompressionMethod::Unsupported(..) => return Err(ZipError::UnsupportedArchive("Unsupported compression")),
        };

        Ok(())
    }

    fn ref_mut(&mut self) -> Option<&mut Write> {
        match *self {
            GenericZipWriter::Storer(ref mut w) => Some(w as &mut Write),
            GenericZipWriter::Deflater(ref mut w) => Some(w as &mut Write),
            #[cfg(feature = "bzip2")]
            GenericZipWriter::Bzip2(ref mut w) => Some(w as &mut Write),
            GenericZipWriter::Closed => None,
        }
    }

    fn is_closed(&self) -> bool
    {
        match *self
        {
            GenericZipWriter::Closed => true,
            _ => false,
        }
    }

    fn get_plain(&mut self) -> &mut W
    {
        match *self
        {
            GenericZipWriter::Storer(ref mut w) => w,
            _ => panic!("Should have switched to stored beforehand"),
        }
    }

    fn current_compression(&self) -> Option<CompressionMethod> {
        match *self {
            GenericZipWriter::Storer(..) => Some(CompressionMethod::Stored),
            GenericZipWriter::Deflater(..) => Some(CompressionMethod::Deflated),
            #[cfg(feature = "bzip2")]
            GenericZipWriter::Bzip2(..) => Some(CompressionMethod::Bzip2),
            GenericZipWriter::Closed => None,
        }
    }

    fn unwrap(self) -> W
    {
        match self
        {
            GenericZipWriter::Storer(w) => w,
            _ => panic!("Should have switched to stored beforehand"),
        }
    }
}

fn write_local_file_header<T: Write>(writer: &mut T, file: &ZipFileData) -> ZipResult<()>
{
    try!(writer.write_u32::<LittleEndian>(spec::LOCAL_FILE_HEADER_SIGNATURE));
    let version_made_by = (file.system as u16) << 8 | (file.version_made_by as u16);
    try!(writer.write_u16::<LittleEndian>(version_made_by));
    let flag = if !file.file_name.is_ascii() { 1u16 << 11 } else { 0 };
    try!(writer.write_u16::<LittleEndian>(flag));
    try!(writer.write_u16::<LittleEndian>(file.compression_method.to_u16()));
    let msdos_datetime = try!(file.last_modified_time.to_msdos());
    try!(writer.write_u16::<LittleEndian>(msdos_datetime.timepart));
    try!(writer.write_u16::<LittleEndian>(msdos_datetime.datepart));
    try!(writer.write_u32::<LittleEndian>(file.crc32));
    try!(writer.write_u32::<LittleEndian>(file.compressed_size as u32));
    try!(writer.write_u32::<LittleEndian>(file.uncompressed_size as u32));
    try!(writer.write_u16::<LittleEndian>(file.file_name.as_bytes().len() as u16));
    let extra_field = try!(build_extra_field(file));
    try!(writer.write_u16::<LittleEndian>(extra_field.len() as u16));
    try!(writer.write_all(file.file_name.as_bytes()));
    try!(writer.write_all(&extra_field));

    Ok(())
}

fn update_local_file_header<T: Write+io::Seek>(writer: &mut T, file: &ZipFileData) -> ZipResult<()>
{
    static CRC32_OFFSET : u64 = 14;
    try!(writer.seek(io::SeekFrom::Start(file.header_start + CRC32_OFFSET)));
    try!(writer.write_u32::<LittleEndian>(file.crc32));
    try!(writer.write_u32::<LittleEndian>(file.compressed_size as u32));
    try!(writer.write_u32::<LittleEndian>(file.uncompressed_size as u32));
    Ok(())
}

fn write_central_directory_header<T: Write>(writer: &mut T, file: &ZipFileData) -> ZipResult<()>
{
    try!(writer.write_u32::<LittleEndian>(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE));
    try!(writer.write_u16::<LittleEndian>(0x14FF));
    try!(writer.write_u16::<LittleEndian>(20));
    let flag = if !file.file_name.is_ascii() { 1u16 << 11 } else { 0 };
    try!(writer.write_u16::<LittleEndian>(flag));
    try!(writer.write_u16::<LittleEndian>(file.compression_method.to_u16()));
    let msdos_datetime = try!(file.last_modified_time.to_msdos());
    try!(writer.write_u16::<LittleEndian>(msdos_datetime.timepart));
    try!(writer.write_u16::<LittleEndian>(msdos_datetime.datepart));
    try!(writer.write_u32::<LittleEndian>(file.crc32));
    try!(writer.write_u32::<LittleEndian>(file.compressed_size as u32));
    try!(writer.write_u32::<LittleEndian>(file.uncompressed_size as u32));
    try!(writer.write_u16::<LittleEndian>(file.file_name.as_bytes().len() as u16));
    let extra_field = try!(build_extra_field(file));
    try!(writer.write_u16::<LittleEndian>(extra_field.len() as u16));
    try!(writer.write_u16::<LittleEndian>(0));
    try!(writer.write_u16::<LittleEndian>(0));
    try!(writer.write_u16::<LittleEndian>(0));
    try!(writer.write_u32::<LittleEndian>(0));
    try!(writer.write_u32::<LittleEndian>(file.header_start as u32));
    try!(writer.write_all(file.file_name.as_bytes()));
    try!(writer.write_all(&extra_field));

    Ok(())
}

fn build_extra_field(_file: &ZipFileData) -> ZipResult<Vec<u8>>
{
    let writer = Vec::new();
    // Future work
    Ok(writer)
}
<commit_msg>Add comments to write.rs<commit_after>//! Structs for creating a new zip archive

use compression::CompressionMethod;
use types::{ZipFileData, System, DEFAULT_VERSION};
use spec;
use crc32;
use result::{ZipResult, ZipError};
use std::default::Default;
use std::io;
use std::io::prelude::*;
use std::mem;
use std::ascii::AsciiExt;
use time;
use flate2;
use flate2::FlateWriteExt;
use flate2::write::DeflateEncoder;
use podio::{WritePodExt, LittleEndian};
use msdos_time::TmMsDosExt;

#[cfg(feature = "bzip2")]
use bzip2;
#[cfg(feature = "bzip2")]
use bzip2::write::BzEncoder;

enum GenericZipWriter<W: Write + io::Seek>
{
    Closed,
    Storer(W),
    Deflater(DeflateEncoder<W>),
    #[cfg(feature = "bzip2")]
    Bzip2(BzEncoder<W>),
}

/// Generator for ZIP files.
///
/// ```
/// fn doit() -> zip::result::ZipResult<()>
/// {
///     use std::io::Write;
///
///     // For this example we write to a buffer, but normally you should use a File
///     let mut buf: &mut [u8] = &mut [0u8; 65536];
///     let mut w = std::io::Cursor::new(buf);
///     let mut zip = zip::ZipWriter::new(w);
///
///     try!(zip.start_file("hello_world.txt", zip::CompressionMethod::Stored));
///     try!(zip.write(b"Hello, World!"));
///
///     // Optionally finish the zip. (this is also done on drop)
///     try!(zip.finish());
///
///     Ok(())
/// }
///
/// println!("Result: {:?}", doit());
/// ```
pub struct ZipWriter<W: Write + io::Seek>
{
    inner: GenericZipWriter<W>,
    files: Vec<ZipFileData>,
    stats: ZipWriterStats,
}

#[derive(Default)]
struct ZipWriterStats
{
    crc32: u32,
    start: u64,
    bytes_written: u64,
}

impl<W: Write+io::Seek> Write for ZipWriter<W>
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize>
    {
        if self.files.len() == 0 { return Err(io::Error::new(io::ErrorKind::Other, "No file has been started")) }
        match self.inner.ref_mut()
        {
            Some(ref mut w) => {
                let write_result = w.write(buf);
                if let Ok(count) = write_result {
                    self.stats.update(&buf[0..count]);
                }
                write_result

            }
            None => Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed")),
        }
    }

    fn flush(&mut self) -> io::Result<()>
    {
        match self.inner.ref_mut()
        {
            Some(ref mut w) => w.flush(),
            None => Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed")),
        }
    }
}

impl ZipWriterStats
{
    fn update(&mut self, buf: &[u8])
    {
        self.crc32 = crc32::update(self.crc32, buf);
        self.bytes_written += buf.len() as u64;
    }
}

impl<W: Write+io::Seek> ZipWriter<W>
{
    /// Initializes the ZipWriter.
    ///
    /// Before writing to this object, the start_file command should be called.
    pub fn new(inner: W) -> ZipWriter<W>
    {
        ZipWriter
        {
            inner: GenericZipWriter::Storer(inner),
            files: Vec::new(),
            stats: Default::default(),
        }
    }

    /// Start a new file for with the requested compression method.
    pub fn start_file<S>(&mut self, name: S, compression: CompressionMethod) -> ZipResult<()>
        where S: Into<String>
    {
        try!(self.finish_file());

        {
            let writer = self.inner.get_plain();
            let header_start = try!(writer.seek(io::SeekFrom::Current(0)));

            let mut file = ZipFileData
            {
                system: System::Dos,
                version_made_by: DEFAULT_VERSION,
                encrypted: false,
                compression_method: compression,
                last_modified_time: time::now(),
                crc32: 0,
                compressed_size: 0,
                uncompressed_size: 0,
                file_name: name.into(),
                file_comment: String::new(),
                header_start: header_start,
                data_start: 0,
                external_attributes: 0,
            };
            try!(write_local_file_header(writer, &file));

            let header_end = try!(writer.seek(io::SeekFrom::Current(0)));
            self.stats.start = header_end;
            file.data_start = header_end;

            self.stats.bytes_written = 0;
            self.stats.crc32 = 0;

            self.files.push(file);
        }

        try!(self.inner.switch_to(compression));

        Ok(())
    }

    fn finish_file(&mut self) -> ZipResult<()>
    {
        try!(self.inner.switch_to(CompressionMethod::Stored));
        let writer = self.inner.get_plain();

        let file = match self.files.last_mut()
        {
            None => return Ok(()),
            Some(f) => f,
        };
        file.crc32 = self.stats.crc32;
        file.uncompressed_size = self.stats.bytes_written;
        file.compressed_size = try!(writer.seek(io::SeekFrom::Current(0))) - self.stats.start;

        try!(update_local_file_header(writer, file));
        try!(writer.seek(io::SeekFrom::End(0)));
        Ok(())
    }

    /// Finish the last file and write all other zip-structures
    ///
    /// This will return the writer, but one should normally not append any data to the end of the file.
    /// Note that the zipfile will also be finished on drop.
    pub fn finish(&mut self) -> ZipResult<W>
    {
        try!(self.finalize());
        let inner = mem::replace(&mut self.inner, GenericZipWriter::Closed);
        Ok(inner.unwrap())
    }

    fn finalize(&mut self) -> ZipResult<()>
    {
        try!(self.finish_file());

        {
            let writer = self.inner.get_plain();

            let central_start = try!(writer.seek(io::SeekFrom::Current(0)));
            for file in self.files.iter()
            {
                try!(write_central_directory_header(writer, file));
            }
            let central_size = try!(writer.seek(io::SeekFrom::Current(0))) - central_start;

            let footer = spec::CentralDirectoryEnd
            {
                disk_number: 0,
                disk_with_central_directory: 0,
                number_of_files_on_this_disk: self.files.len() as u16,
                number_of_files: self.files.len() as u16,
                central_directory_size: central_size as u32,
                central_directory_offset: central_start as u32,
                zip_file_comment: b"zip-rs".to_vec(),
            };

            try!(footer.write(writer));
        }

        Ok(())
    }
}

impl<W: Write+io::Seek> Drop for ZipWriter<W>
{
    fn drop(&mut self)
    {
        if !self.inner.is_closed()
        {
            if let Err(e) = self.finalize() {
                let _ = write!(&mut io::stderr(), "ZipWriter drop failed: {:?}", e);
            }
        }
    }
}

impl<W: Write+io::Seek> GenericZipWriter<W>
{
    fn switch_to(&mut self, compression: CompressionMethod) -> ZipResult<()>
    {
        match self.current_compression() {
            Some(method) if method == compression => return Ok(()),
            None => try!(Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed"))),
            _ => {},
        }

        let bare = match mem::replace(self, GenericZipWriter::Closed)
        {
            GenericZipWriter::Storer(w) => w,
            GenericZipWriter::Deflater(w) => try!(w.finish()),
            #[cfg(feature = "bzip2")]
            GenericZipWriter::Bzip2(w) => try!(w.finish()),
            GenericZipWriter::Closed => try!(Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed"))),
        };

        *self = match compression
        {
            CompressionMethod::Stored => GenericZipWriter::Storer(bare),
            CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::Compression::Default)),
            #[cfg(feature = "bzip2")]
            CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzEncoder::new(bare, bzip2::Compression::Default)),
            CompressionMethod::Unsupported(..) => return Err(ZipError::UnsupportedArchive("Unsupported compression")),
        };

        Ok(())
    }

    fn ref_mut(&mut self) -> Option<&mut Write> {
        match *self {
            GenericZipWriter::Storer(ref mut w) => Some(w as &mut Write),
            GenericZipWriter::Deflater(ref mut w) => Some(w as &mut Write),
            #[cfg(feature = "bzip2")]
            GenericZipWriter::Bzip2(ref mut w) => Some(w as &mut Write),
            GenericZipWriter::Closed => None,
        }
    }

    fn is_closed(&self) -> bool
    {
        match *self
        {
            GenericZipWriter::Closed => true,
            _ => false,
        }
    }

    fn get_plain(&mut self) -> &mut W
    {
        match *self
        {
            GenericZipWriter::Storer(ref mut w) => w,
            _ => panic!("Should have switched to stored beforehand"),
        }
    }

    fn current_compression(&self) -> Option<CompressionMethod> {
        match *self {
            GenericZipWriter::Storer(..) => Some(CompressionMethod::Stored),
            GenericZipWriter::Deflater(..) => Some(CompressionMethod::Deflated),
            #[cfg(feature = "bzip2")]
            GenericZipWriter::Bzip2(..) => Some(CompressionMethod::Bzip2),
            GenericZipWriter::Closed => None,
        }
    }

    fn unwrap(self) -> W
    {
        match self
        {
            GenericZipWriter::Storer(w) => w,
            _ => panic!("Should have switched to stored beforehand"),
        }
    }
}

fn write_local_file_header<T: Write>(writer: &mut T, file: &ZipFileData) -> ZipResult<()>
{
    // local file header signature
    try!(writer.write_u32::<LittleEndian>(spec::LOCAL_FILE_HEADER_SIGNATURE));
    // version needed to extract
    let version_made_by = (file.system as u16) << 8 | (file.version_made_by as u16);
    try!(writer.write_u16::<LittleEndian>(version_made_by));
    // general purpose bit flag
    let flag = if !file.file_name.is_ascii() { 1u16 << 11 } else { 0 };
    try!(writer.write_u16::<LittleEndian>(flag));
    // Compression method
    try!(writer.write_u16::<LittleEndian>(file.compression_method.to_u16()));
    // last mod file time and last mod file date
    let msdos_datetime = try!(file.last_modified_time.to_msdos());
    try!(writer.write_u16::<LittleEndian>(msdos_datetime.timepart));
    try!(writer.write_u16::<LittleEndian>(msdos_datetime.datepart));
    // crc-32
    try!(writer.write_u32::<LittleEndian>(file.crc32));
    // compressed size
    try!(writer.write_u32::<LittleEndian>(file.compressed_size as u32));
    // uncompressed size
    try!(writer.write_u32::<LittleEndian>(file.uncompressed_size as u32));
    // file name length
    try!(writer.write_u16::<LittleEndian>(file.file_name.as_bytes().len() as u16));
    // extra field length
    let extra_field = try!(build_extra_field(file));
    try!(writer.write_u16::<LittleEndian>(extra_field.len() as u16));
    // file name
    try!(writer.write_all(file.file_name.as_bytes()));
    // extra field
    try!(writer.write_all(&extra_field));

    Ok(())
}

fn update_local_file_header<T: Write+io::Seek>(writer: &mut T, file: &ZipFileData) -> ZipResult<()>
{
    static CRC32_OFFSET : u64 = 14;
    try!(writer.seek(io::SeekFrom::Start(file.header_start + CRC32_OFFSET)));
    try!(writer.write_u32::<LittleEndian>(file.crc32));
    try!(writer.write_u32::<LittleEndian>(file.compressed_size as u32));
    try!(writer.write_u32::<LittleEndian>(file.uncompressed_size as u32));
    Ok(())
}

fn write_central_directory_header<T: Write>(writer: &mut T, file: &ZipFileData) -> ZipResult<()>
{
    // central file header signature
    try!(writer.write_u32::<LittleEndian>(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE));
    // version made by
    try!(writer.write_u16::<LittleEndian>(0x14FF));
    // version needed to extract
    try!(writer.write_u16::<LittleEndian>(20));
    // general puprose bit flag
    let flag = if !file.file_name.is_ascii() { 1u16 << 11 } else { 0 };
    try!(writer.write_u16::<LittleEndian>(flag));
    // compression method
    try!(writer.write_u16::<LittleEndian>(file.compression_method.to_u16()));
    // last mod file time + date
    let msdos_datetime = try!(file.last_modified_time.to_msdos());
    try!(writer.write_u16::<LittleEndian>(msdos_datetime.timepart));
    try!(writer.write_u16::<LittleEndian>(msdos_datetime.datepart));
    // crc-32
    try!(writer.write_u32::<LittleEndian>(file.crc32));
    // compressed size
    try!(writer.write_u32::<LittleEndian>(file.compressed_size as u32));
    // uncompressed size
    try!(writer.write_u32::<LittleEndian>(file.uncompressed_size as u32));
    // file name length
    try!(writer.write_u16::<LittleEndian>(file.file_name.as_bytes().len() as u16));
    // extra field length
    let extra_field = try!(build_extra_field(file));
    try!(writer.write_u16::<LittleEndian>(extra_field.len() as u16));
    // file comment length
    try!(writer.write_u16::<LittleEndian>(0));
    // disk number start
    try!(writer.write_u16::<LittleEndian>(0));
    // internal file attribytes
    try!(writer.write_u16::<LittleEndian>(0));
    // external file attributes
    try!(writer.write_u32::<LittleEndian>(0));
    // relative offset of local header
    try!(writer.write_u32::<LittleEndian>(file.header_start as u32));
    // file name
    try!(writer.write_all(file.file_name.as_bytes()));
    // extra field
    try!(writer.write_all(&extra_field));
    // file comment
    // <none>

    Ok(())
}

fn build_extra_field(_file: &ZipFileData) -> ZipResult<Vec<u8>>
{
    let writer = Vec::new();
    // Future work
    Ok(writer)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! # Vertex sources definition
//!
//! When you create a graphics pipeline object, you need to pass an object which indicates the
//! layout of the vertex buffer(s) that will serve as input for the vertex shader. This is done
//! by passing an implementation of the `Definition` trait.
//!
//! The most common situation is a single vertex buffer and no instancing, in which case you can
//! pass a `SingleBufferDefinition` when you create the pipeline.
//!
//! # Implementing `Vertex`
//!
//! The implementations of the `Definition` trait that are provided by vulkano (like
//! `SingleBufferDefinition`) require you to use a buffer whose content is `[V]` where `V`
//! implements the `Vertex` trait.
//!
//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
//! macro.
//!
//! # Example
//!
//! ```no_run
//! # #[macro_use] extern crate vulkano
//! # fn main() {
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::device::Queue;
//! use vulkano::buffer::Buffer;
//! use vulkano::buffer::Usage as BufferUsage;
//! use vulkano::memory::HostVisible;
//! use vulkano::pipeline::vertex::;
//! # let device: Arc<Device> = unsafe { std::mem::uninitialized() };
//! # let queue: Arc<Queue> = unsafe { std::mem::uninitialized() };
//!
//! struct Vertex {
//!     position: [f32; 2]
//! }
//!
//! impl_vertex!(Vertex, position);
//!
//! let usage = BufferUsage {
//!     vertex_buffer: true,
//!     .. BufferUsage::none()
//! };
//!
//! let vertex_buffer = Buffer::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
//!                                                     .expect("failed to create buffer");
//!
//! // TODO: finish example
//! # }
//! ```
//!
use std::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;

use buffer::Buffer;
use buffer::TypedBuffer;
use format::Format;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. In other words a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<AttributeInfo>;
}

/// Information about a single attribute within a vertex.
pub struct AttributeInfo {
    /// Number of bytes between the start of a vertex and the location of attribute.
    pub offset: usize,
    /// Data type of the attribute.
    pub format: Format,
}

/// Trait for types that contain a definition of the vertex input used by a graphics pipeline.
pub unsafe trait Definition {
    /// Iterator used to enumerate the list of buffers.
    type InfoIter: ExactSizeIterator<Item = (usize, InputRate)>;

    /// Returns information about an attribute, and the index of the buffer (within the iterator
    /// returned by `buffers`) in which the attribute is found.
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)>;

    /// Produces an iterator that returns the stride (in bytes) and input rate of each buffer.
    fn buffers(&self) -> Self::InfoIter;
}

/// Extension for `Definition` trait. The `L` parameter is an acceptable vertex source for this
/// vertex definition.
pub unsafe trait Source<L>: Definition {
    /// Iterator used by `decode`.
    type Iter: ExactSizeIterator<Item = Arc<Buffer>>;

    /// Checks and returns the list of buffers, number of vertices and number of instances.
    fn decode(&self, L) -> (Self::Iter, usize, usize);
}

/// Implementation of `Definition` for a single vertex buffer.
pub struct SingleBufferDefinition<T>(pub PhantomData<T>);

impl<T> SingleBufferDefinition<T> {
    #[inline]
    pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}

unsafe impl<T> Definition for SingleBufferDefinition<T> where T: Vertex {
    type InfoIter = OptionIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        <T as Vertex>::attrib(name).map(|info| (0, info))
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        Some((mem::size_of::<T>(), InputRate::Vertex)).into_iter()
    }
}

unsafe impl<'a, B, V> Source<&'a Arc<B>> for SingleBufferDefinition<V>
    where B: TypedBuffer<Content = [V]> + 'static, V: Vertex + 'static
{
    type Iter = OptionIntoIter<Arc<Buffer>>;

    #[inline]
    fn decode(&self, source: &'a Arc<B>) -> (OptionIntoIter<Arc<Buffer>>, usize, usize) {
        let iter = Some(source.clone() as Arc<_>).into_iter();
        (iter, source.len(), 1)
    }
}

/// Unstable.
// TODO: shouldn't be just `Two` but `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> TwoBuffersDefinition<T, U> {
    #[inline]
    pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for TwoBuffersDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Vertex)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Bt, Bu> Source<(&'a Arc<Bt>, &'a Arc<Bu>)> for TwoBuffersDefinition<T, U>
    where T: Vertex + 'static, Bt: TypedBuffer<Content = [T]> + 'static, T: 'static,
          U: Vertex + 'static, Bu: TypedBuffer<Content = [U]> + 'static, T: 'static
{
    type Iter = VecIntoIter<Arc<Buffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Bt>, &'a Arc<Bu>))
              -> (VecIntoIter<Arc<Buffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

/// Unstable.
// TODO: bad way to do things
pub struct OneVertexOneInstanceDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> OneVertexOneInstanceDefinition<T, U> {
    #[inline]
    pub fn new() -> OneVertexOneInstanceDefinition<T, U> { OneVertexOneInstanceDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for OneVertexOneInstanceDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Instance)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Bt, Bu> Source<(&'a Arc<Bt>, &'a Arc<Bu>)> for OneVertexOneInstanceDefinition<T, U>
    where T: Vertex + 'static, Bt: TypedBuffer<Content = [T]> + 'static, T: 'static,
          U: Vertex + 'static, Bu: TypedBuffer<Content = [U]> + 'static, U: 'static
{
    type Iter = VecIntoIter<Arc<Buffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Bt>, &'a Arc<Bu>))
              -> (VecIntoIter<Arc<Buffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

/// Implements the `Vertex` trait on a struct.
// TODO: add example
#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::AttributeInfo> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::AttributeInfo {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Data>(_: &T) -> $crate::format::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

/// Trait for data types that can be used as vertex attributes. Used by the `impl_vertex!` macro.
pub unsafe trait Data {
    /// Returns the format of the attribute.
    fn format() -> Format;
}

unsafe impl Data for f32 {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for (f32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for (f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for u32 {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for [u32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for [u32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Uint
    }
}

unsafe impl Data for [u32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Uint
    }
}

unsafe impl Data for [u32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Uint
    }
}

unsafe impl Data for (u32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for (u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Uint
    }
}

unsafe impl Data for (u32, u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Uint
    }
}

unsafe impl Data for (u32, u32, u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Uint
    }
}
<commit_msg>Fix wrong instances number again<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! # Vertex sources definition
//!
//! When you create a graphics pipeline object, you need to pass an object which indicates the
//! layout of the vertex buffer(s) that will serve as input for the vertex shader. This is done
//! by passing an implementation of the `Definition` trait.
//!
//! The most common situation is a single vertex buffer and no instancing, in which case you can
//! pass a `SingleBufferDefinition` when you create the pipeline.
//!
//! # Implementing `Vertex`
//!
//! The implementations of the `Definition` trait that are provided by vulkano (like
//! `SingleBufferDefinition`) require you to use a buffer whose content is `[V]` where `V`
//! implements the `Vertex` trait.
//!
//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
//! macro.
//!
//! # Example
//!
//! ```no_run
//! # #[macro_use] extern crate vulkano
//! # fn main() {
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::device::Queue;
//! use vulkano::buffer::Buffer;
//! use vulkano::buffer::Usage as BufferUsage;
//! use vulkano::memory::HostVisible;
//! use vulkano::pipeline::vertex::;
//! # let device: Arc<Device> = unsafe { std::mem::uninitialized() };
//! # let queue: Arc<Queue> = unsafe { std::mem::uninitialized() };
//!
//! struct Vertex {
//!     position: [f32; 2]
//! }
//!
//! impl_vertex!(Vertex, position);
//!
//! let usage = BufferUsage {
//!     vertex_buffer: true,
//!     .. BufferUsage::none()
//! };
//!
//! let vertex_buffer = Buffer::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
//!                                                     .expect("failed to create buffer");
//!
//! // TODO: finish example
//! # }
//! ```
//!
use std::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;

use buffer::Buffer;
use buffer::TypedBuffer;
use format::Format;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. In other words a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<AttributeInfo>;
}

/// Information about a single attribute within a vertex.
pub struct AttributeInfo {
    /// Number of bytes between the start of a vertex and the location of attribute.
    pub offset: usize,
    /// Data type of the attribute.
    pub format: Format,
}

/// Trait for types that contain a definition of the vertex input used by a graphics pipeline.
pub unsafe trait Definition {
    /// Iterator used to enumerate the list of buffers.
    type InfoIter: ExactSizeIterator<Item = (usize, InputRate)>;

    /// Returns information about an attribute, and the index of the buffer (within the iterator
    /// returned by `buffers`) in which the attribute is found.
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)>;

    /// Produces an iterator that returns the stride (in bytes) and input rate of each buffer.
    fn buffers(&self) -> Self::InfoIter;
}

/// Extension for `Definition` trait. The `L` parameter is an acceptable vertex source for this
/// vertex definition.
pub unsafe trait Source<L>: Definition {
    /// Iterator used by `decode`.
    type Iter: ExactSizeIterator<Item = Arc<Buffer>>;

    /// Checks and returns the list of buffers, number of vertices and number of instances.
    fn decode(&self, L) -> (Self::Iter, usize, usize);
}

/// Implementation of `Definition` for a single vertex buffer.
pub struct SingleBufferDefinition<T>(pub PhantomData<T>);

impl<T> SingleBufferDefinition<T> {
    #[inline]
    pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}

unsafe impl<T> Definition for SingleBufferDefinition<T> where T: Vertex {
    type InfoIter = OptionIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        <T as Vertex>::attrib(name).map(|info| (0, info))
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        Some((mem::size_of::<T>(), InputRate::Vertex)).into_iter()
    }
}

unsafe impl<'a, B, V> Source<&'a Arc<B>> for SingleBufferDefinition<V>
    where B: TypedBuffer<Content = [V]> + 'static, V: Vertex + 'static
{
    type Iter = OptionIntoIter<Arc<Buffer>>;

    #[inline]
    fn decode(&self, source: &'a Arc<B>) -> (OptionIntoIter<Arc<Buffer>>, usize, usize) {
        let iter = Some(source.clone() as Arc<_>).into_iter();
        (iter, source.len(), 1)
    }
}

/// Unstable.
// TODO: shouldn't be just `Two` but `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> TwoBuffersDefinition<T, U> {
    #[inline]
    pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for TwoBuffersDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Vertex)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Bt, Bu> Source<(&'a Arc<Bt>, &'a Arc<Bu>)> for TwoBuffersDefinition<T, U>
    where T: Vertex + 'static, Bt: TypedBuffer<Content = [T]> + 'static, T: 'static,
          U: Vertex + 'static, Bu: TypedBuffer<Content = [U]> + 'static, T: 'static
{
    type Iter = VecIntoIter<Arc<Buffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Bt>, &'a Arc<Bu>))
              -> (VecIntoIter<Arc<Buffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

/// Unstable.
// TODO: bad way to do things
pub struct OneVertexOneInstanceDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> OneVertexOneInstanceDefinition<T, U> {
    #[inline]
    pub fn new() -> OneVertexOneInstanceDefinition<T, U> { OneVertexOneInstanceDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for OneVertexOneInstanceDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Instance)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Bt, Bu> Source<(&'a Arc<Bt>, &'a Arc<Bu>)> for OneVertexOneInstanceDefinition<T, U>
    where T: Vertex + 'static, Bt: TypedBuffer<Content = [T]> + 'static, T: 'static,
          U: Vertex + 'static, Bu: TypedBuffer<Content = [U]> + 'static, U: 'static
{
    type Iter = VecIntoIter<Arc<Buffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Bt>, &'a Arc<Bu>))
              -> (VecIntoIter<Arc<Buffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, source.0.len(), source.1.len())
    }
}

/// Implements the `Vertex` trait on a struct.
// TODO: add example
#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::AttributeInfo> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::AttributeInfo {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Data>(_: &T) -> $crate::format::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

/// Trait for data types that can be used as vertex attributes. Used by the `impl_vertex!` macro.
pub unsafe trait Data {
    /// Returns the format of the attribute.
    fn format() -> Format;
}

unsafe impl Data for f32 {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for (f32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for (f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for u32 {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for [u32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for [u32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Uint
    }
}

unsafe impl Data for [u32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Uint
    }
}

unsafe impl Data for [u32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Uint
    }
}

unsafe impl Data for (u32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for (u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Uint
    }
}

unsafe impl Data for (u32, u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Uint
    }
}

unsafe impl Data for (u32, u32, u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Uint
    }
}
<|endoftext|>