<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use libsodium_sys;
use secstr;
use argon2rs;

struct PublicKey(secstr::SecStr);
struct SecretKey(secstr::SecStr);

pub fn keyed_fingerprint(sk: &[u8],
                         msg: &[u8],
                         salt: &[u8; libsodium_sys::crypto_generichash_blake2b_SALTBYTES],
                         out: &mut [u8]) {
    let outlen = out.len();
    let personal: &[u8; libsodium_sys::crypto_generichash_blake2b_PERSONALBYTES] =
        b"hat-backup~~~~~a";

    let ret = unsafe {
        libsodium_sys::crypto_generichash_blake2b_salt_personal(out.as_mut_ptr(),
                                                                outlen,
                                                                msg.as_ptr(),
                                                                msg.len() as u64,
                                                                sk.as_ptr(),
                                                                sk.len(),
                                                                salt.as_ptr() as *const [u8; libsodium_sys::crypto_generichash_blake2b_SALTBYTES],
                                                                personal.as_ptr() as *const [u8; libsodium_sys::crypto_generichash_blake2b_PERSONALBYTES])
    };
    assert_eq!(ret, 0);
}

pub struct Keeper {
    universal_key: secstr::SecStr,
    fingerprint_key: Option<secstr::SecStr>,
    blob_authentication_key: Option<secstr::SecStr>,

    data_key_pk: Option<PublicKey>,
    data_key_sk: Option<SecretKey>,

    naming_key_pk: Option<PublicKey>,
    naming_key_sk: Option<SecretKey>,

    access_key_pk: Option<PublicKey>,
    access_key_sk: Option<SecretKey>,
}

impl Keeper {
    pub fn new(universal: &str) -> Keeper {
        let app: &str = "hat-backup:universal-key";
        let mut keeper = Keeper {
            universal_key: Keeper::strengthen(universal, app),
            fingerprint_key: None,
            blob_authentication_key: None,
            data_key_pk: None,
            data_key_sk: None,
            access_key_pk: None,
            access_key_sk: None,
            naming_key_pk: None,
            naming_key_sk: None,
        };
        keeper.init();
        keeper
    }

    #[cfg(test)]
    pub fn new_for_testing() -> Keeper {
        let mut keeper = Keeper {
            universal_key: secstr::SecStr::new(vec![0; 32]),
            fingerprint_key: None,
            blob_authentication_key: None,
            data_key_pk: None,
            data_key_sk: None,
            access_key_pk: None,
            access_key_sk: None,
            naming_key_pk: None,
            naming_key_sk: None,
        };
        keeper.init();
        keeper
    }

    fn init(&mut self) {
        // Generate key used for fingerprinting.
        self.fingerprint_key = Some(self.from_nonce("hat:FINGERPRINT-key".as_bytes(), 64));

        // Generate key for authenticating blob data.
        self.blob_authentication_key =
            Some(self.from_nonce("hat:BLOB-AUTHENTICATION-key".as_bytes(), 64));

        // Generate data key.
        // Required for reading blob data without a direct reference.
        let (pk, sk) = self.x25519_key_pair_from_nonce("hat:DATA-key-x25519".as_bytes());
        self.data_key_pk = Some(pk);
        self.data_key_sk = Some(sk);

        // Generate access key.
        // Required for reading any blob data (with direct reference or with data key).
        let (pk, sk) = self.x25519_key_pair_from_nonce("hat:ACCESS-key-x25519".as_bytes());
        self.access_key_pk = Some(pk);
        self.access_key_sk = Some(sk);

        // Generate naming key.
        // Required for reading blob names.
        let (pk, sk) = self.x25519_key_pair_from_nonce("hat:NAMING-key-x25519".as_bytes());
        self.naming_key_pk = Some(pk);
        self.naming_key_sk = Some(sk);
    }

    fn strengthen(phrase: &str, salt: &str) -> secstr::SecStr {
        let passes = 5;
        let threads = 2;
        let kib = 16 * 1024;

        let argon2 = argon2rs::Argon2::new(passes, threads, kib, argon2rs::Variant::Argon2d)
            .unwrap();

        let mut out = vec![0; 64];
        argon2.hash(&mut out[..], phrase.as_bytes(), salt.as_bytes(), &[], &[]);
        secstr::SecStr::new(out)
    }

    pub fn from_nonce(&self, nonce: &[u8], outlen: usize) -> secstr::SecStr {
        let mut out = secstr::SecStr::new(vec![0; outlen]);
        let salt: &[u8; 16] = b"nonce~~~nonce~~~";
        keyed_fingerprint(&self.universal_key.unsecure(),
                          &nonce[..],
                          salt,
                          out.unsecure_mut());
        out
    }

    fn x25519_key_pair_from_nonce(&self, nonce: &[u8]) -> (PublicKey, SecretKey) {
        let mut pk = secstr::SecStr::new(vec![0; 32]);
        let mut sk = secstr::SecStr::new(vec![0; 32]);

        let seed = self.from_nonce(nonce, 32);

        let ret = unsafe {
            libsodium_sys::crypto_box_seed_keypair(pk.unsecure_mut().as_mut_ptr() as *mut [u8; 32],
                                                   sk.unsecure_mut().as_mut_ptr() as *mut [u8; 32],
                                                   seed.unsecure().as_ptr() as *const [u8; 32])
        };
        assert_eq!(ret, 0);

        (PublicKey(pk), SecretKey(sk))
    }

    fn asymmetric_lock(pk: &PublicKey, msg: &[u8]) -> Vec<u8> {
        let mut out = vec![0; msg.len() + libsodium_sys::crypto_box_SEALBYTES];
        let ret = unsafe {
            libsodium_sys::crypto_box_seal(out.as_mut_ptr(),
                                           msg.as_ptr(),
                                           msg.len() as u64,
                                           pk.0.unsecure().as_ptr() as *const [u8; 32])
        };
        assert_eq!(0, ret);

        out
    }

    fn asymmetric_unlock(pk: &PublicKey, sk: &SecretKey, ciphertext: &[u8]) -> Vec<u8> {
        let mut out = vec![0; ciphertext.len() - libsodium_sys::crypto_box_SEALBYTES];
        let ret = unsafe {
            libsodium_sys::crypto_box_seal_open(out.as_mut_ptr(),
                                                ciphertext.as_ptr(),
                                                ciphertext.len() as u64,
                                                pk.0.unsecure().as_ptr() as *const [u8; 32],
                                                sk.0.unsecure().as_ptr() as *const [u8; 32])
        };
        assert_eq!(0, ret);

        out
    }

    pub fn data_lock(&self, msg: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_lock(self.data_key_pk.as_ref().expect("need data public key"),
                                msg)
    }

    pub fn data_unlock(&self, ciphertext: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_unlock(self.data_key_pk.as_ref().expect("need data public key"),
                                  self.data_key_sk
                                      .as_ref()
                                      .expect("need data private key"),
                                  ciphertext)
    }

    pub fn access_lock(&self, msg: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_lock(self.access_key_pk
                                    .as_ref()
                                    .expect("need access publick key"),
                                msg)
    }

    pub fn access_unlock(&self, ciphertext: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_unlock(self.access_key_pk
                                      .as_ref()
                                      .expect("need access public key"),
                                  self.access_key_sk
                                      .as_ref()
                                      .expect("need access private key"),
                                  ciphertext)
    }

    pub fn naming_lock(&self, msg: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_lock(self.naming_key_pk
                                    .as_ref()
                                    .expect("need naming public key"),
                                msg)
    }

    pub fn naming_unlock(&self, ciphertext: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_unlock(self.naming_key_pk
                                      .as_ref()
                                      .expect("need naming public key"),
                                  self.naming_key_sk
                                      .as_ref()
                                      .expect("need naming private key"),
                                  ciphertext)
    }

    pub fn fingerprint(&self, msg: &[u8], salt: &[u8; 16], out: &mut [u8]) {
        let key = self.fingerprint_key
            .as_ref()
            .expect("need fingerprint key");
        keyed_fingerprint(key.unsecure(), msg, salt, out);
    }

    pub fn blob_authentication(&self, blob: &[u8], out: &mut [u8]) {
        let key = self.blob_authentication_key
            .as_ref()
            .expect("need blob authentication key");
        let salt: &[u8; 16] = b"blob~~~~blob~~~~";
        keyed_fingerprint(key.unsecure(), blob, salt, &mut out[..])
    }

    pub fn symmetric_lock(msg: &[u8], data: &[u8], nonce: &[u8; 8]) -> (secstr::SecStr, Vec<u8>) {
        let sk_len = libsodium_sys::crypto_aead_chacha20poly1305_KEYBYTES;
        let mut sk = secstr::SecStr::new(vec![0u8; sk_len]);
        unsafe { libsodium_sys::randombytes_buf(sk.unsecure_mut().as_mut_ptr(), sk_len) }

        let mut out = vec![0u8; msg.len() + libsodium_sys::crypto_aead_chacha20poly1305_ABYTES];
        let mut out_len = 0;

        let ret = unsafe {
            libsodium_sys::crypto_aead_chacha20poly1305_encrypt(out.as_mut_ptr(),
                                                                &mut out_len,
                                                                msg.as_ptr(),
                                                                msg.len() as u64,
                                                                data.as_ptr(),
                                                                data.len() as u64,
                                                                &[0u8; 0],
                                                                nonce.as_ptr() as *const [u8; 8],
                                                                sk.unsecure().as_ptr() as
                                                                *const [u8; 32])
        };
        assert_eq!(0, ret);
        assert_eq!(out_len, out.len() as u64);

        (sk, out)
    }

    pub fn symmetric_unlock(sk: &secstr::SecStr,
                            ciphertext: &[u8],
                            data: &[u8],
                            nonce: &[u8; 8])
                            -> Vec<u8> {
        let mut out =
            vec![0u8; ciphertext.len() - libsodium_sys::crypto_aead_chacha20poly1305_ABYTES];
        let mut out_len = 0;

        let ret = unsafe {
            libsodium_sys::crypto_aead_chacha20poly1305_decrypt(out.as_mut_ptr(),
                                                                &mut out_len,
                                                                &mut [0u8; 0],
                                                                ciphertext.as_ptr(),
                                                                ciphertext.len() as u64,
                                                                data.as_ptr(),
                                                                data.len() as u64,
                                                                nonce.as_ptr() as *const [u8; 8],
                                                                sk.unsecure().as_ptr() as
                                                                *const [u8; 32])
        };
        assert_eq!(0, ret);
        assert_eq!(out_len, out.len() as u64);

        out
    }
}
<commit_msg>Minor: Fix too long line.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use libsodium_sys;
use secstr;
use argon2rs;

struct PublicKey(secstr::SecStr);
struct SecretKey(secstr::SecStr);

pub fn keyed_fingerprint(sk: &[u8],
                         msg: &[u8],
                         salt: &[u8; libsodium_sys::crypto_generichash_blake2b_SALTBYTES],
                         out: &mut [u8]) {
    use libsodium_sys::{crypto_generichash_blake2b_SALTBYTES,
                        crypto_generichash_blake2b_PERSONALBYTES};

    let outlen = out.len();
    let personal: &[u8; libsodium_sys::crypto_generichash_blake2b_PERSONALBYTES] =
        b"hat-backup~~~~~a";

    let ret = unsafe {
        libsodium_sys::crypto_generichash_blake2b_salt_personal(
            out.as_mut_ptr(),
            outlen,
            msg.as_ptr(),
            msg.len() as u64,
            sk.as_ptr(),
            sk.len(),
            salt.as_ptr() as *const [u8; crypto_generichash_blake2b_SALTBYTES],
            personal.as_ptr() as *const [u8; crypto_generichash_blake2b_PERSONALBYTES])
    };
    assert_eq!(ret, 0);
}

pub struct Keeper {
    universal_key: secstr::SecStr,
    fingerprint_key: Option<secstr::SecStr>,
    blob_authentication_key: Option<secstr::SecStr>,

    data_key_pk: Option<PublicKey>,
    data_key_sk: Option<SecretKey>,

    naming_key_pk: Option<PublicKey>,
    naming_key_sk: Option<SecretKey>,

    access_key_pk: Option<PublicKey>,
    access_key_sk: Option<SecretKey>,
}

impl Keeper {
    pub fn new(universal: &str) -> Keeper {
        let app: &str = "hat-backup:universal-key";
        let mut keeper = Keeper {
            universal_key: Keeper::strengthen(universal, app),
            fingerprint_key: None,
            blob_authentication_key: None,
            data_key_pk: None,
            data_key_sk: None,
            access_key_pk: None,
            access_key_sk: None,
            naming_key_pk: None,
            naming_key_sk: None,
        };
        keeper.init();
        keeper
    }

    #[cfg(test)]
    pub fn new_for_testing() -> Keeper {
        let mut keeper = Keeper {
            universal_key: secstr::SecStr::new(vec![0; 32]),
            fingerprint_key: None,
            blob_authentication_key: None,
            data_key_pk: None,
            data_key_sk: None,
            access_key_pk: None,
            access_key_sk: None,
            naming_key_pk: None,
            naming_key_sk: None,
        };
        keeper.init();
        keeper
    }

    fn init(&mut self) {
        // Generate key used for fingerprinting.
        self.fingerprint_key = Some(self.from_nonce("hat:FINGERPRINT-key".as_bytes(), 64));

        // Generate key for authenticating blob data.
        self.blob_authentication_key =
            Some(self.from_nonce("hat:BLOB-AUTHENTICATION-key".as_bytes(), 64));

        // Generate data key.
        // Required for reading blob data without a direct reference.
        let (pk, sk) = self.x25519_key_pair_from_nonce("hat:DATA-key-x25519".as_bytes());
        self.data_key_pk = Some(pk);
        self.data_key_sk = Some(sk);

        // Generate access key.
        // Required for reading any blob data (with direct reference or with data key).
        let (pk, sk) = self.x25519_key_pair_from_nonce("hat:ACCESS-key-x25519".as_bytes());
        self.access_key_pk = Some(pk);
        self.access_key_sk = Some(sk);

        // Generate naming key.
        // Required for reading blob names.
        let (pk, sk) = self.x25519_key_pair_from_nonce("hat:NAMING-key-x25519".as_bytes());
        self.naming_key_pk = Some(pk);
        self.naming_key_sk = Some(sk);
    }

    fn strengthen(phrase: &str, salt: &str) -> secstr::SecStr {
        let passes = 5;
        let threads = 2;
        let kib = 16 * 1024;

        let argon2 = argon2rs::Argon2::new(passes, threads, kib, argon2rs::Variant::Argon2d)
            .unwrap();

        let mut out = vec![0; 64];
        argon2.hash(&mut out[..], phrase.as_bytes(), salt.as_bytes(), &[], &[]);
        secstr::SecStr::new(out)
    }

    pub fn from_nonce(&self, nonce: &[u8], outlen: usize) -> secstr::SecStr {
        let mut out = secstr::SecStr::new(vec![0; outlen]);
        let salt: &[u8; 16] = b"nonce~~~nonce~~~";
        keyed_fingerprint(&self.universal_key.unsecure(),
                          &nonce[..],
                          salt,
                          out.unsecure_mut());
        out
    }

    fn x25519_key_pair_from_nonce(&self, nonce: &[u8]) -> (PublicKey, SecretKey) {
        let mut pk = secstr::SecStr::new(vec![0; 32]);
        let mut sk = secstr::SecStr::new(vec![0; 32]);

        let seed = self.from_nonce(nonce, 32);

        let ret = unsafe {
            libsodium_sys::crypto_box_seed_keypair(pk.unsecure_mut().as_mut_ptr() as *mut [u8; 32],
                                                   sk.unsecure_mut().as_mut_ptr() as *mut [u8; 32],
                                                   seed.unsecure().as_ptr() as *const [u8; 32])
        };
        assert_eq!(ret, 0);

        (PublicKey(pk), SecretKey(sk))
    }

    fn asymmetric_lock(pk: &PublicKey, msg: &[u8]) -> Vec<u8> {
        let mut out = vec![0; msg.len() + libsodium_sys::crypto_box_SEALBYTES];
        let ret = unsafe {
            libsodium_sys::crypto_box_seal(out.as_mut_ptr(),
                                           msg.as_ptr(),
                                           msg.len() as u64,
                                           pk.0.unsecure().as_ptr() as *const [u8; 32])
        };
        assert_eq!(0, ret);

        out
    }

    fn asymmetric_unlock(pk: &PublicKey, sk: &SecretKey, ciphertext: &[u8]) -> Vec<u8> {
        let mut out = vec![0; ciphertext.len() - libsodium_sys::crypto_box_SEALBYTES];
        let ret = unsafe {
            libsodium_sys::crypto_box_seal_open(out.as_mut_ptr(),
                                                ciphertext.as_ptr(),
                                                ciphertext.len() as u64,
                                                pk.0.unsecure().as_ptr() as *const [u8; 32],
                                                sk.0.unsecure().as_ptr() as *const [u8; 32])
        };
        assert_eq!(0, ret);

        out
    }

    pub fn data_lock(&self, msg: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_lock(self.data_key_pk.as_ref().expect("need data public key"),
                                msg)
    }

    pub fn data_unlock(&self, ciphertext: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_unlock(self.data_key_pk.as_ref().expect("need data public key"),
                                  self.data_key_sk
                                      .as_ref()
                                      .expect("need data private key"),
                                  ciphertext)
    }

    pub fn access_lock(&self, msg: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_lock(self.access_key_pk
                                    .as_ref()
                                    .expect("need access publick key"),
                                msg)
    }

    pub fn access_unlock(&self, ciphertext: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_unlock(self.access_key_pk
                                      .as_ref()
                                      .expect("need access public key"),
                                  self.access_key_sk
                                      .as_ref()
                                      .expect("need access private key"),
                                  ciphertext)
    }

    pub fn naming_lock(&self, msg: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_lock(self.naming_key_pk
                                    .as_ref()
                                    .expect("need naming public key"),
                                msg)
    }

    pub fn naming_unlock(&self, ciphertext: &[u8]) -> Vec<u8> {
        Keeper::asymmetric_unlock(self.naming_key_pk
                                      .as_ref()
                                      .expect("need naming public key"),
                                  self.naming_key_sk
                                      .as_ref()
                                      .expect("need naming private key"),
                                  ciphertext)
    }

    pub fn fingerprint(&self, msg: &[u8], salt: &[u8; 16], out: &mut [u8]) {
        let key = self.fingerprint_key
            .as_ref()
            .expect("need fingerprint key");
        keyed_fingerprint(key.unsecure(), msg, salt, out);
    }

    pub fn blob_authentication(&self, blob: &[u8], out: &mut [u8]) {
        let key = self.blob_authentication_key
            .as_ref()
            .expect("need blob authentication key");
        let salt: &[u8; 16] = b"blob~~~~blob~~~~";
        keyed_fingerprint(key.unsecure(), blob, salt, &mut out[..])
    }

    pub fn symmetric_lock(msg: &[u8], data: &[u8], nonce: &[u8; 8]) -> (secstr::SecStr, Vec<u8>) {
        let sk_len = libsodium_sys::crypto_aead_chacha20poly1305_KEYBYTES;
        let mut sk = secstr::SecStr::new(vec![0u8; sk_len]);
        unsafe { libsodium_sys::randombytes_buf(sk.unsecure_mut().as_mut_ptr(), sk_len) }

        let mut out = vec![0u8; msg.len() + libsodium_sys::crypto_aead_chacha20poly1305_ABYTES];
        let mut out_len = 0;

        let ret = unsafe {
            libsodium_sys::crypto_aead_chacha20poly1305_encrypt(out.as_mut_ptr(),
                                                                &mut out_len,
                                                                msg.as_ptr(),
                                                                msg.len() as u64,
                                                                data.as_ptr(),
                                                                data.len() as u64,
                                                                &[0u8; 0],
                                                                nonce.as_ptr() as *const [u8; 8],
                                                                sk.unsecure().as_ptr() as
                                                                *const [u8; 32])
        };
        assert_eq!(0, ret);
        assert_eq!(out_len, out.len() as u64);

        (sk, out)
    }

    pub fn symmetric_unlock(sk: &secstr::SecStr,
                            ciphertext: &[u8],
                            data: &[u8],
                            nonce: &[u8; 8])
                            -> Vec<u8> {
        let mut out =
            vec![0u8; ciphertext.len() - libsodium_sys::crypto_aead_chacha20poly1305_ABYTES];
        let mut out_len = 0;

        let ret = unsafe {
            libsodium_sys::crypto_aead_chacha20poly1305_decrypt(out.as_mut_ptr(),
                                                                &mut out_len,
                                                                &mut [0u8; 0],
                                                                ciphertext.as_ptr(),
                                                                ciphertext.len() as u64,
                                                                data.as_ptr(),
                                                                data.len() as u64,
                                                                nonce.as_ptr() as *const [u8; 8],
                                                                sk.unsecure().as_ptr() as
                                                                *const [u8; 32])
        };
        assert_eq!(0, ret);
        assert_eq!(out_len, out.len() as u64);

        out
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use types::GLError;

pub struct Framebuffer {
    gl_id: GLuint
}

impl Framebuffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_framebuffer(&self) -> Framebuffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenFramebuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Framebuffer {
                gl_id: id
            }
        }
    }
}

gl_enum! {
    pub gl_enum FramebufferAttachment {
        ColorAttachment0 as COLOR_ATTACHMENT0 = gl::COLOR_ATTACHMENT0,
        DepthAttachment as DEPTH_ATTACHMENT = gl::DEPTH_ATTACHMENT,
        StencilAttachment as STENCIL_ATTACHMENT = gl::STENCIL_ATTACHMENT
    }
}

pub struct FramebufferBinding<'a> {
    phantom: PhantomData<&'a mut Framebuffer>
}

impl<'a> FramebufferBinding<'a> {
    fn target(&self) -> GLenum {
        gl::FRAMEBUFFER
    }
}

pub struct FramebufferBinder;
impl FramebufferBinder {
    pub fn bind<'a>(&'a mut self, fbo: &mut Framebuffer)
        -> FramebufferBinding<'a>
    {
        let binding = FramebufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindFramebuffer(binding.target(), fbo.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<commit_msg>Add `FramebufferBinding.renderbuffer()` (to attach a renderbuffer)<commit_after>use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use renderbuffer::Renderbuffer;
use types::GLError;

pub struct Framebuffer {
    gl_id: GLuint
}

impl Framebuffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_framebuffer(&self) -> Framebuffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenFramebuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Framebuffer {
                gl_id: id
            }
        }
    }
}

gl_enum! {
    pub gl_enum FramebufferAttachment {
        ColorAttachment0 as COLOR_ATTACHMENT0 = gl::COLOR_ATTACHMENT0,
        DepthAttachment as DEPTH_ATTACHMENT = gl::DEPTH_ATTACHMENT,
        StencilAttachment as STENCIL_ATTACHMENT = gl::STENCIL_ATTACHMENT
    }
}

pub struct FramebufferBinding<'a> {
    phantom: PhantomData<&'a mut Framebuffer>
}

impl<'a> FramebufferBinding<'a> {
    fn target(&self) -> GLenum {
        gl::FRAMEBUFFER
    }

    pub fn renderbuffer(&mut self,
                        attachment: FramebufferAttachment,
                        renderbuffer: &mut Renderbuffer)
    {
        unsafe {
            gl::FramebufferRenderbuffer(self.target(),
                                        attachment.gl_enum(),
                                        gl::RENDERBUFFER,
                                        renderbuffer.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`, `attachment` is not a valid attachment point, or `renderbuffer` is not `GL_RENDERBUFFER` and `renderbuffer` is not 0",
                GLError::InvalidOperation => "Framebuffer 0 is bound, or `renderbuffer` is neither 0 nor the name of an existing renderbuffer object",
                _ => "Unknown error"
            }
        }
    }
}

pub struct FramebufferBinder;
impl FramebufferBinder {
    pub fn bind<'a>(&'a mut self, fbo: &mut Framebuffer)
        -> FramebufferBinding<'a>
    {
        let binding = FramebufferBinding { phantom: PhantomData };
        unsafe {
            gl::BindFramebuffer(binding.target(), fbo.gl_id());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`target` is not `GL_FRAMEBUFFER`",
                _ => "Unknown error"
            }
        }
        binding
    }
}
<|endoftext|>


<commit_before>// A port of selecta's scoring algorithm parsing.
// selecta (c) 2014 John Hawthorn
// Licensed under the MIT license

use std::cmp::Ordering;
use super::eq;
use super::mat::Mat;
use super::bonus::compute_bonus;
use super::consts::*;

#[derive(Debug)]
pub struct Score {
    /// The computed score value
    pub value: f32,
}

impl Score {
    /// Creates a new Score with the provided value
    ///
    /// # Examples
    ///
    /// ```
    /// let score = rff::fuzzy::Score::new(1.0);
    /// assert_eq!(score.value, 1.0);
    /// ```
    pub fn new(value: f32) -> Score {
        Score { value: value }
    }

    /// Creates a new Score, with value derived from provided needle / haystack
    pub fn calculate(needle: &str, haystack: &str) -> Score {
        let len_n = needle.len();
        let len_h = haystack.len();

        if len_n == 0 { return Score::new(SCORE_MIN); }
        if len_n == len_h { return Score::new(SCORE_MAX); }

        let (m, _) = generate_score_matrices(needle, haystack);

        let score = m.get(len_n - 1, len_h - 1).unwrap_or(SCORE_MIN);
        Score::new(score)
    }
}

impl PartialOrd for Score {
    fn partial_cmp(&self, other: &Score) -> Option<Ordering> {
        self.value.partial_cmp(&other.value)
    }
}

impl PartialEq for Score {
    fn eq(&self, other: &Score) -> bool {
        self.value == other.value
    }
}

#[inline]
fn generate_score_matrices(needle: &str, haystack: &str) -> (Mat, Mat) {
    let len_n = needle.len();
    let len_h = haystack.len();

    let bonus = compute_bonus(haystack);

    let mut d = Mat::new(len_n, len_h);
    let mut m = Mat::new(len_n, len_h);

    for (i, n) in needle.chars().enumerate() {
        let mut prev_score = SCORE_MIN;
        let gap_score = if i == len_n - 1 { SCORE_GAP_TRAILING } else { SCORE_GAP_INNER };

        for (j, h) in haystack.chars().enumerate() {
            if eq(n, h) {
                let mut score = SCORE_MIN;

                let bonus_score = bonus[j];

                if i == 0 {
                    score = ((j as f32) * SCORE_GAP_LEADING) + bonus_score;
                } else if j > 0 {
                    let m = m.get(i - 1, j - 1).unwrap();
                    let d = d.get(i - 1, j - 1).unwrap();

                    score = (m + bonus_score).max(d + SCORE_MATCH_CONSECUTIVE);
                }

                prev_score = score.max(prev_score + gap_score);

                d.set(i, j, score).unwrap();
                m.set(i, j, prev_score).unwrap();
            } else {
                d.set(i, j, SCORE_MIN).unwrap();
                m.set(i, j, prev_score + gap_score).unwrap();
                prev_score += gap_score;
            }
        }
    }

    (m, d)
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    fn score(needle: &str, haystack: &str) -> Score {
        Score::calculate(needle, haystack)
    }

    #[test]
    fn test_eq() {
        let a = Score::new(1.0);
        let b = Score::new(1.0);
        assert_eq!(a, b);
    }

    #[test]
    fn test_cmp() {
        let a = Score::new(2.0);
        let b = Score::new(1.0);
        assert!(a > b);
        assert!(b < a);

        let b = Score::new(2.0);
        assert!(a == b);
    }

    #[test]
    fn relative_scores() {
        // App/Models/Order is better than App/MOdels/zRder
        assert!(score("amor", "app/models/order") > score("amor", "app/models/zrder"));

        // App/MOdels/foo is better than App/M/fOo
        assert!(score("amo", "app/m/foo") < score("amo", "app/models/foo"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // Prefer shorter scorees
        assert!(score("abce", "abcdef") > score("abce", "abc de"));

        // Prefer shorter candidates
        assert!(score("test", "tests") > score("test", "testing"));

        // Scores first letter highly
        assert!(score("test", "testing") > score("test", "/testing"));

        // Prefer shorter scorees
        assert!(score("abc", "    a b c ") > score("abc", " a  b  c "));
        assert!(score("abc", " a b c    ") > score("abc", " a  b  c "));
    }

    #[bench]
    fn bench_score(b: &mut Bencher) {
        b.iter(|| Score::calculate("amor", "app/models/order.rb"))
    }

    #[bench]
    fn bench_score_multiple(b: &mut Bencher) {
        b.iter(|| {
            Score::calculate("amor", "app/models/order.rb");
            Score::calculate("amor", "spec/models/order_spec.rb");
            Score::calculate("amor", "other_garbage.rb");
            Score::calculate("amor", "Gemfile");
            Score::calculate("amor", "node_modules/test/a/thing.js");
            Score::calculate("amor", "vendor/bundle/ruby/gem.rb")
        })
    }

}
<commit_msg>Add Score field to contain match positions<commit_after>// A port of selecta's scoring algorithm parsing.
// selecta (c) 2014 John Hawthorn
// Licensed under the MIT license

use std::cmp::Ordering;
use super::eq;
use super::mat::Mat;
use super::bonus::compute_bonus;
use super::consts::*;

#[derive(Debug)]
pub struct Score {
    /// The computed score value
    pub value: f32,

    /// Optional vector of match positions
    pub positions: Option<Vec<usize>>
}

impl Score {
    /// Creates a new Score with the provided value
    ///
    /// # Examples
    ///
    /// ```
    /// let score = rff::fuzzy::Score::new(1.0);
    /// assert_eq!(score.value, 1.0);
    /// ```
    pub fn new(value: f32) -> Score {
        Score { value: value, positions: None }
    }

    /// Creates a new Score with the provided value and match positions
    ///
    /// # Examples
    ///
    /// ```
    /// let score = rff::fuzzy::Score::with_positions(1.0, vec![1, 2, 3]);
    /// assert_eq!(score.value, 1.0);
    /// assert_eq!(score.positions, Some(vec![1, 2, 3]));
    /// ```
    pub fn with_positions(value: f32, positions: Vec<usize>) -> Score {
        Score { value: value, positions: Some(positions) }
    }

    /// Creates a new Score, with value derived from provided needle / haystack
    pub fn calculate(needle: &str, haystack: &str) -> Score {
        let len_n = needle.len();
        let len_h = haystack.len();

        if len_n == 0 { return Score::new(SCORE_MIN); }
        if len_n == len_h { return Score::new(SCORE_MAX); }

        let (m, _) = generate_score_matrices(needle, haystack);

        let score = m.get(len_n - 1, len_h - 1).unwrap_or(SCORE_MIN);
        Score::new(score)
    }
}

impl PartialOrd for Score {
    fn partial_cmp(&self, other: &Score) -> Option<Ordering> {
        self.value.partial_cmp(&other.value)
    }
}

impl PartialEq for Score {
    fn eq(&self, other: &Score) -> bool {
        self.value == other.value
    }
}

#[inline]
fn generate_score_matrices(needle: &str, haystack: &str) -> (Mat, Mat) {
    let len_n = needle.len();
    let len_h = haystack.len();

    let bonus = compute_bonus(haystack);

    let mut d = Mat::new(len_n, len_h);
    let mut m = Mat::new(len_n, len_h);

    for (i, n) in needle.chars().enumerate() {
        let mut prev_score = SCORE_MIN;
        let gap_score = if i == len_n - 1 { SCORE_GAP_TRAILING } else { SCORE_GAP_INNER };

        for (j, h) in haystack.chars().enumerate() {
            if eq(n, h) {
                let mut score = SCORE_MIN;

                let bonus_score = bonus[j];

                if i == 0 {
                    score = ((j as f32) * SCORE_GAP_LEADING) + bonus_score;
                } else if j > 0 {
                    let m = m.get(i - 1, j - 1).unwrap();
                    let d = d.get(i - 1, j - 1).unwrap();

                    score = (m + bonus_score).max(d + SCORE_MATCH_CONSECUTIVE);
                }

                prev_score = score.max(prev_score + gap_score);

                d.set(i, j, score).unwrap();
                m.set(i, j, prev_score).unwrap();
            } else {
                d.set(i, j, SCORE_MIN).unwrap();
                m.set(i, j, prev_score + gap_score).unwrap();
                prev_score += gap_score;
            }
        }
    }

    (m, d)
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    fn score(needle: &str, haystack: &str) -> Score {
        Score::calculate(needle, haystack)
    }

    #[test]
    fn test_eq() {
        let a = Score::new(1.0);
        let b = Score::new(1.0);
        assert_eq!(a, b);
    }

    #[test]
    fn test_cmp() {
        let a = Score::new(2.0);
        let b = Score::new(1.0);
        assert!(a > b);
        assert!(b < a);

        let b = Score::new(2.0);
        assert!(a == b);
    }

    #[test]
    fn relative_scores() {
        // App/Models/Order is better than App/MOdels/zRder
        assert!(score("amor", "app/models/order") > score("amor", "app/models/zrder"));

        // App/MOdels/foo is better than App/M/fOo
        assert!(score("amo", "app/m/foo") < score("amo", "app/models/foo"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // Prefer shorter scorees
        assert!(score("abce", "abcdef") > score("abce", "abc de"));

        // Prefer shorter candidates
        assert!(score("test", "tests") > score("test", "testing"));

        // Scores first letter highly
        assert!(score("test", "testing") > score("test", "/testing"));

        // Prefer shorter scorees
        assert!(score("abc", "    a b c ") > score("abc", " a  b  c "));
        assert!(score("abc", " a b c    ") > score("abc", " a  b  c "));
    }

    #[bench]
    fn bench_score(b: &mut Bencher) {
        b.iter(|| Score::calculate("amor", "app/models/order.rb"))
    }

    #[bench]
    fn bench_score_multiple(b: &mut Bencher) {
        b.iter(|| {
            Score::calculate("amor", "app/models/order.rb");
            Score::calculate("amor", "spec/models/order_spec.rb");
            Score::calculate("amor", "other_garbage.rb");
            Score::calculate("amor", "Gemfile");
            Score::calculate("amor", "node_modules/test/a/thing.js");
            Score::calculate("amor", "vendor/bundle/ruby/gem.rb")
        })
    }

}
<|endoftext|>


<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
in vec4 pos;
in vec4 color;

out vec4 v_color;

void main()
{
    v_color = color;
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
out vec4 out_color;
in vec4 v_color;

void main()
{
    out_color = v_color;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
in vec4 pos;
in vec4 color;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_v2TexCoord;
out vec4 v_color;

void main()
{
    v_v2TexCoord = uv;
    v_color = color;
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
out vec4 out_color;

uniform sampler2D s_texture;

in vec2 v_v2TexCoord;
in vec4 v_color;

void main()
{
    out_color = texture(s_texture, v_v2TexCoord) * v_color;
}
";

struct TriListXYRGBA {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        TriListXYRGBA {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        TriListXYRGBAUV {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        Gl {
            tri_list_xy_rgba: TriListXYRGBA::new(),
            tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
            current_program: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.tri_list_xy_rgba;
        gl::BindVertexArray(shader.vao);

        // xy makes two floats.
        let size_vertices: i32 = 2;

        unsafe {
            shader.pos.set(vertices);
            shader.color.set(colors);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.tri_list_xy_rgba_uv;
        gl::BindVertexArray(shader.vao);

        let size_vertices: i32 = 2;

        unsafe {
            shader.pos.set(vertices);
            shader.color.set(colors);
            shader.uv.set(texture_coords);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }
}

<commit_msg>Simplified shader parameter<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
in vec4 pos;
in vec4 color;

out vec4 v_color;

void main()
{
    v_color = color;
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
out vec4 out_color;
in vec4 v_color;

void main()
{
    out_color = v_color;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
in vec4 pos;
in vec4 color;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_uv;
out vec4 v_color;

void main()
{
    v_uv = uv;
    v_color = color;
    gl_Position = pos;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
out vec4 out_color;

uniform sampler2D s_texture;

in vec2 v_uv;
in vec4 v_color;

void main()
{
    out_color = texture(s_texture, v_uv) * v_color;
}
";

struct TriListXYRGBA {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        TriListXYRGBA {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        TriListXYRGBAUV {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        Gl {
            tri_list_xy_rgba: TriListXYRGBA::new(),
            tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
            current_program: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.tri_list_xy_rgba;
        gl::BindVertexArray(shader.vao);

        // xy makes two floats.
        let size_vertices: i32 = 2;

        unsafe {
            shader.pos.set(vertices);
            shader.color.set(colors);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.tri_list_xy_rgba_uv;
        gl::BindVertexArray(shader.vao);

        let size_vertices: i32 = 2;

        unsafe {
            shader.pos.set(vertices);
            shader.color.set(colors);
            shader.uv.set(texture_coords);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }
}

<|endoftext|>


<commit_before>use std::slice::raw;
use std::mem;

/// Given a type, produce a raw representation of it in the format of &[u8]. This allows us
/// to efficiently encode and decode messages without analyzing the type further like JSON.
///
/// 1) Convert `x` to a pointer of u8. This requires a double cast.
/// 2) Get the size of type `T`
/// 3) buf_as_slice will return a new raw Slice where the data is the pointer of u8s with
///    the size of type `T`.
/// 4) Transmute the raw slice &[T] to &[u8] in the closure.
pub fn as_byte_slice<'a, T>(x: &'a T) -> &'a [u8] {
    unsafe {
        raw::buf_as_slice(
            x as *_ as *u8,
            mem::size_of::<T>(),
            |v| mem::transmute(v)
        )
    }
}

/// We basically need to do the opposite from the as_byte_slice function.
///
/// * We have: &[u8]
/// * We need: T
///
/// 1) Convert x to &[T]
pub fn from_byte_slice<'a, T>(x: &'a [u8]) -> &'a T {
    unsafe {
        let slice: &[T] = mem::transmute(x);
        let ptr = slice.as_ptr() as *T;
        &*ptr
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn decode_int() {
        let i = 5;
        let bytes = as_byte_slice(&i);

        let dec = from_byte_slice(bytes);
        assert_eq!(i, *dec);
    }
}
<commit_msg>Decodes structs too<commit_after>use std::slice::raw;
use std::mem;

/// Given a type, produce a raw representation of it in the format of &[u8]. This allows us
/// to efficiently encode and decode messages without analyzing the type further like JSON.
///
/// 1) Convert `x` to a pointer of u8. This requires a double cast.
/// 2) Get the size of type `T`
/// 3) buf_as_slice will return a new raw Slice where the data is the pointer of u8s with
///    the size of type `T`.
/// 4) Transmute the raw slice &[T] to &[u8] in the closure.
pub fn as_byte_slice<'a, T>(x: &'a T) -> &'a [u8] {
    unsafe {
        raw::buf_as_slice(
            x as *_ as *u8,
            mem::size_of::<T>(),
            |v| mem::transmute(v)
        )
    }
}

/// We basically need to do the opposite from the as_byte_slice function.
///
/// * We have: &[u8]
/// * We need: T
///
/// 1) Convert x to &[T]
pub fn from_byte_slice<'a, T>(x: &'a [u8]) -> &'a T {
    unsafe {
        let slice: &[T] = mem::transmute(x);
        let ptr = slice.as_ptr() as *T;
        &*ptr
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn decode_int() {
        let i = 5;
        let bytes = as_byte_slice(&i);

        let dec = from_byte_slice(bytes);
        assert_eq!(i, *dec);
    }

    #[test]
    fn decode_struct() {
        #[deriving(PartialEq, Show)]
        struct Foo {
            i: int
        }

        let foo = Foo { i : 5 };

        let bytes = as_byte_slice(&foo);
        let dec   = from_byte_slice(bytes);
        assert_eq!(foo, *dec);
        assert_eq!(dec.i, 5);
    }
}
<|endoftext|>


<commit_before>/// Memory buffers for the benefit of `std::io::net` which has slow read/write.

use std::io::{IoResult, Stream};
use std::cmp::min;
use std::slice;
use std::num::ToStrRadix;

// 64KB chunks (moderately arbitrary)
static READ_BUF_SIZE: uint = 0x10000;
static WRITE_BUF_SIZE: uint = 0x10000;
// TODO: consider removing constants and giving a buffer size in the constructor

pub struct BufferedStream<T> {
    pub wrapped: T,
    pub read_buffer: Vec<u8>,
    // The current position in the buffer
    pub read_pos: uint,
    // The last valid position in the reader
    pub read_max: uint,
    pub write_buffer: Vec<u8>,
    pub write_len: uint,

    pub writing_chunked_body: bool,
}

impl<T: Stream> BufferedStream<T> {
    pub fn new(stream: T) -> BufferedStream<T> {
        let mut read_buffer = Vec::with_capacity(READ_BUF_SIZE);
        unsafe { read_buffer.set_len(READ_BUF_SIZE); }
        let mut write_buffer = Vec::with_capacity(WRITE_BUF_SIZE);
        unsafe { write_buffer.set_len(WRITE_BUF_SIZE); }
        BufferedStream {
            wrapped: stream,
            read_buffer: read_buffer,
            read_pos: 0u,
            read_max: 0u,
            write_buffer: write_buffer,
            write_len: 0u,
            writing_chunked_body: false,
        }
    }
}

impl<T: Reader> BufferedStream<T> {
    /// Poke a single byte back so it will be read next. For this to make sense, you must have just
    /// read that byte. If `self.pos` is 0 and `self.max` is not 0 (i.e. if the buffer is just
    /// filled
    /// Very great caution must be used in calling this as it will fail if `self.pos` is 0.
    pub fn poke_byte(&mut self, byte: u8) {
        match (self.read_pos, self.read_max) {
            (0, 0) => self.read_max = 1,
            (0, _) => fail!("poke called when buffer is full"),
            (_, _) => self.read_pos -= 1,
        }
        self.read_buffer.as_mut_slice()[self.read_pos] = byte;
    }

    #[inline]
    fn fill_buffer(&mut self) -> IoResult<()> {
        assert_eq!(self.read_pos, self.read_max);
        self.read_pos = 0;
        match self.wrapped.read(self.read_buffer.as_mut_slice()) {
            Ok(i) => {
                self.read_max = i;
                Ok(())
            },
            Err(err) => {
                self.read_max = 0;
                Err(err)
            },
        }
    }

    /// Slightly faster implementation of read_byte than that which is provided by ReaderUtil
    /// (which just uses `read()`)
    #[inline]
    pub fn read_byte(&mut self) -> IoResult<u8> {
        if self.read_pos == self.read_max {
            // Fill the buffer, giving up if we've run out of buffered content
            try!(self.fill_buffer());
        }
        self.read_pos += 1;
        Ok(self.read_buffer.as_slice()[self.read_pos - 1])
    }
}

impl<T: Writer> BufferedStream<T> {
    /// Finish off writing a response: this flushes the writer and in case of chunked
    /// Transfer-Encoding writes the ending zero-length chunk to indicate completion.
    ///
    /// At the time of calling this, headers MUST have been written, including the
    /// ending CRLF, or else an invalid HTTP response may be written.
    pub fn finish_response(&mut self) -> IoResult<()> {
        try!(self.flush());
        if self.writing_chunked_body {
            try!(self.wrapped.write(b"0\r\n\r\n"));
        }
        Ok(())
    }
}

impl<T: Reader> Reader for BufferedStream<T> {
    /// Read at most N bytes into `buf`, where N is the minimum of `buf.len()` and the buffer size.
    ///
    /// At present, this makes no attempt to fill its buffer proactively, instead waiting until you
    /// ask.
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        if self.read_pos == self.read_max {
            // Fill the buffer, giving up if we've run out of buffered content
            try!(self.fill_buffer());
        }
        let size = min(self.read_max - self.read_pos, buf.len());
        slice::bytes::copy_memory(buf, self.read_buffer.slice_from(self.read_pos).slice_to(size));
        self.read_pos += size;
        Ok(size)
    }
}

impl<T: Writer> Writer for BufferedStream<T> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        if buf.len() + self.write_len > self.write_buffer.len() {
            // This is the lazy approach which may involve multiple writes where it's really not
            // warranted. Maybe deal with that later.
            if self.writing_chunked_body {
                let s = format!("{}\r\n", (self.write_len + buf.len()).to_str_radix(16));
                try!(self.wrapped.write(s.as_bytes()));
            }
            if self.write_len > 0 {
                try!(self.wrapped.write(self.write_buffer.slice_to(self.write_len)));
                self.write_len = 0;
            }
            try!(self.wrapped.write(buf));
            self.write_len = 0;
            if self.writing_chunked_body {
                try!(self.wrapped.write(b"\r\n"));
            }
        } else {
            unsafe {
                let len = self.write_buffer.len();
                self.write_buffer.mut_slice(self.write_len, len).copy_memory(buf);
            }

            self.write_len += buf.len();
            if self.write_len == self.write_buffer.len() {
                if self.writing_chunked_body {
                    let s = format!("{}\r\n", self.write_len.to_str_radix(16));
                    try!(self.wrapped.write(s.as_bytes()));
                    try!(self.wrapped.write(self.write_buffer.as_slice()));
                    try!(self.wrapped.write(b"\r\n"));
                } else {
                    try!(self.wrapped.write(self.write_buffer.as_slice()));
                }
                self.write_len = 0;
            }
        }
        Ok(())
    }

    fn flush(&mut self) -> IoResult<()> {
        if self.write_len > 0 {
            if self.writing_chunked_body {
                let s = format!("{}\r\n", self.write_len.to_str_radix(16));
                try!(self.wrapped.write(s.as_bytes()));
            }
            try!(self.wrapped.write(self.write_buffer.slice_to(self.write_len)));
            if self.writing_chunked_body {
                try!(self.wrapped.write(b"\r\n"));
            }
            self.write_len = 0;
        }
        self.wrapped.flush()
    }
}
<commit_msg>(fix) Replace deprecated with radix.<commit_after>/// Memory buffers for the benefit of `std::io::net` which has slow read/write.

use std::io::{IoResult, Stream};
use std::cmp::min;
use std::slice;
use std::fmt::radix;

// 64KB chunks (moderately arbitrary)
static READ_BUF_SIZE: uint = 0x10000;
static WRITE_BUF_SIZE: uint = 0x10000;
// TODO: consider removing constants and giving a buffer size in the constructor

pub struct BufferedStream<T> {
    pub wrapped: T,
    pub read_buffer: Vec<u8>,
    // The current position in the buffer
    pub read_pos: uint,
    // The last valid position in the reader
    pub read_max: uint,
    pub write_buffer: Vec<u8>,
    pub write_len: uint,

    pub writing_chunked_body: bool,
}

impl<T: Stream> BufferedStream<T> {
    pub fn new(stream: T) -> BufferedStream<T> {
        let mut read_buffer = Vec::with_capacity(READ_BUF_SIZE);
        unsafe { read_buffer.set_len(READ_BUF_SIZE); }
        let mut write_buffer = Vec::with_capacity(WRITE_BUF_SIZE);
        unsafe { write_buffer.set_len(WRITE_BUF_SIZE); }
        BufferedStream {
            wrapped: stream,
            read_buffer: read_buffer,
            read_pos: 0u,
            read_max: 0u,
            write_buffer: write_buffer,
            write_len: 0u,
            writing_chunked_body: false,
        }
    }
}

impl<T: Reader> BufferedStream<T> {
    /// Poke a single byte back so it will be read next. For this to make sense, you must have just
    /// read that byte. If `self.pos` is 0 and `self.max` is not 0 (i.e. if the buffer is just
    /// filled
    /// Very great caution must be used in calling this as it will fail if `self.pos` is 0.
    pub fn poke_byte(&mut self, byte: u8) {
        match (self.read_pos, self.read_max) {
            (0, 0) => self.read_max = 1,
            (0, _) => fail!("poke called when buffer is full"),
            (_, _) => self.read_pos -= 1,
        }
        self.read_buffer.as_mut_slice()[self.read_pos] = byte;
    }

    #[inline]
    fn fill_buffer(&mut self) -> IoResult<()> {
        assert_eq!(self.read_pos, self.read_max);
        self.read_pos = 0;
        match self.wrapped.read(self.read_buffer.as_mut_slice()) {
            Ok(i) => {
                self.read_max = i;
                Ok(())
            },
            Err(err) => {
                self.read_max = 0;
                Err(err)
            },
        }
    }

    /// Slightly faster implementation of read_byte than that which is provided by ReaderUtil
    /// (which just uses `read()`)
    #[inline]
    pub fn read_byte(&mut self) -> IoResult<u8> {
        if self.read_pos == self.read_max {
            // Fill the buffer, giving up if we've run out of buffered content
            try!(self.fill_buffer());
        }
        self.read_pos += 1;
        Ok(self.read_buffer.as_slice()[self.read_pos - 1])
    }
}

impl<T: Writer> BufferedStream<T> {
    /// Finish off writing a response: this flushes the writer and in case of chunked
    /// Transfer-Encoding writes the ending zero-length chunk to indicate completion.
    ///
    /// At the time of calling this, headers MUST have been written, including the
    /// ending CRLF, or else an invalid HTTP response may be written.
    pub fn finish_response(&mut self) -> IoResult<()> {
        try!(self.flush());
        if self.writing_chunked_body {
            try!(self.wrapped.write(b"0\r\n\r\n"));
        }
        Ok(())
    }
}

impl<T: Reader> Reader for BufferedStream<T> {
    /// Read at most N bytes into `buf`, where N is the minimum of `buf.len()` and the buffer size.
    ///
    /// At present, this makes no attempt to fill its buffer proactively, instead waiting until you
    /// ask.
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        if self.read_pos == self.read_max {
            // Fill the buffer, giving up if we've run out of buffered content
            try!(self.fill_buffer());
        }
        let size = min(self.read_max - self.read_pos, buf.len());
        slice::bytes::copy_memory(buf, self.read_buffer.slice_from(self.read_pos).slice_to(size));
        self.read_pos += size;
        Ok(size)
    }
}

impl<T: Writer> Writer for BufferedStream<T> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        if buf.len() + self.write_len > self.write_buffer.len() {
            // This is the lazy approach which may involve multiple writes where it's really not
            // warranted. Maybe deal with that later.
            if self.writing_chunked_body {
                let s = format!("{}\r\n", (radix(self.write_len + buf.len(), 16)));
                try!(self.wrapped.write(s.as_bytes()));
            }
            if self.write_len > 0 {
                try!(self.wrapped.write(self.write_buffer.slice_to(self.write_len)));
                self.write_len = 0;
            }
            try!(self.wrapped.write(buf));
            self.write_len = 0;
            if self.writing_chunked_body {
                try!(self.wrapped.write(b"\r\n"));
            }
        } else {
            unsafe {
                let len = self.write_buffer.len();
                self.write_buffer.mut_slice(self.write_len, len).copy_memory(buf);
            }

            self.write_len += buf.len();
            if self.write_len == self.write_buffer.len() {
                if self.writing_chunked_body {
                    let s = format!("{}\r\n", radix(self.write_len, 16));
                    try!(self.wrapped.write(s.as_bytes()));
                    try!(self.wrapped.write(self.write_buffer.as_slice()));
                    try!(self.wrapped.write(b"\r\n"));
                } else {
                    try!(self.wrapped.write(self.write_buffer.as_slice()));
                }
                self.write_len = 0;
            }
        }
        Ok(())
    }

    fn flush(&mut self) -> IoResult<()> {
        if self.write_len > 0 {
            if self.writing_chunked_body {
                let s = format!("{}\r\n", radix(self.write_len, 16));
                try!(self.wrapped.write(s.as_bytes()));
            }
            try!(self.wrapped.write(self.write_buffer.slice_to(self.write_len)));
            if self.writing_chunked_body {
                try!(self.wrapped.write(b"\r\n"));
            }
            self.write_len = 0;
        }
        self.wrapped.flush()
    }
}
<|endoftext|>