<commit_before>use std::collections::HashMap;
use std::str::FromStr;

use hyper::Uri;

use client::{self, ApiClient};

static DATASTORE_ROOT: &str = "https://datastore.googleapis.com/v1";

pub struct DatastoreService {}
pub type Hub<'a> = client::Hub<'a, DatastoreService>;

pub type ValueMap = HashMap<String, Value>;

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct BeginTransactionRequest {}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct BeginTransactionResponse {
    pub transaction: String,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CommitRequest {
    pub transaction: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub mode: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub mutations: Option<Vec<Mutation>>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CommitResponse {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub mutation_results: Option<Vec<MutationResult>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub index_updates: Option<i32>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
struct RunQueryRequest {
    partition_id: PartitionId,
    read_options: ReadOptions,

    #[serde(skip_serializing_if = "Option::is_none")]
    gql_query: Option<GqlQuery>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
struct GqlQuery {
    query_string: String,
    allow_literals: bool,
    named_bindings: HashMap<String, GqlQueryParameter>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
struct GqlQueryParameter {
    value: Value,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct RunQueryResponse {
    pub batch: QueryResultBatch,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct QueryResultBatch {
    pub entity_results: Option<Vec<EntityResult>>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Mutation {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub insert: Option<Entity>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub upsert: Option<Entity>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub update: Option<Entity>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub base_version: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub delete: Option<Key>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct MutationResult {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub conflict_detected: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub key: Option<Key>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct LookupRequest {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub keys: Option<Vec<Key>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub read_options: Option<ReadOptions>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct LookupResponse {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub found: Option<Vec<EntityResult>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub missing: Option<Vec<EntityResult>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub deferred: Option<Vec<Key>>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ReadOptions {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub transaction: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub read_consistency: Option<String>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct EntityResult {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cursor: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub entity: Option<Entity>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Entity {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub properties: Option<HashMap<String, Value>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub key: Option<Key>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Key {
    pub path: Vec<PathElement>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub partition_id: Option<PartitionId>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PathElement {
    pub kind: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PartitionId {
    pub project_id: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub namespace_id: Option<String>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Value {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub entity_value: Option<Entity>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub timestamp_value: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub string_value: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub double_value: Option<f64>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub meaning: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub exclude_from_indexes: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub blob_value: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub key_value: Option<Key>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub boolean_value: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub integer_value: Option<i64>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub null_value: Option<String>,

    //#[serde(rename="geoPointValue")]
    //#[serde(skip_serializing_if = "Option::is_none")]
    //pub geo_point_value: Option<LatLng>,

    //#[serde(rename="arrayValue")]
    //#[serde(skip_serializing_if = "Option::is_none")]
    //pub array_value: Option<ArrayValue>,
}

impl<'a> Hub<'a> {
    pub fn insert_entity_auto_id(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        props: ValueMap,
    ) -> client::Result<String> {
        let key = self.mk_key(kind, Some(ns), ancestors, None, None);
        let res = self.insert(key, props)?;
        let mut results = res.mutation_results.expect("mutations to be valid");

        let mut key = results.remove(0).key.expect("key to be valid");
        Ok(key.path.pop().expect("path to be non-empty").id.expect(
            "id to be valid",
        ))
    }

    pub fn insert_entity_by_name(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        name: &str,
        props: ValueMap,
    ) -> client::Result<()> {
        let key = self.mk_key(kind, Some(ns), ancestors, Some(name), None);
        self.insert(key, props)?;
        Ok(())
    }

    fn insert(&self, key: Key, props: ValueMap) -> client::Result<CommitResponse> {
        let entity = Entity {
            key: Some(key),
            properties: Some(props),
        };

        let insert = Mutation {
            insert: Some(entity),
            ..Default::default()
        };

        let req = CommitRequest {
            mutations: Some(vec![insert]),
            ..Default::default()
        };

        let txn_id = self.begin_transaction()?;
        self.commit(&txn_id, req)
    }

    pub fn lookup_by_id(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        id: &str,
    ) -> client::Result<Option<ValueMap>> {
        let key = self.mk_key(kind, Some(ns), ancestors, None, Some(id));
        self.lookup_one(key)
    }

    pub fn lookup_by_name(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        name: &str,
    ) -> client::Result<Option<ValueMap>> {
        let key = self.mk_key(kind, Some(ns), ancestors, Some(name), None);
        self.lookup_one(key)
    }

    pub fn gql<B>(&self, ns: &str, q: &str, bindings: B) -> client::Result<RunQueryResponse>
    where
        B: IntoIterator<Item = (String, Value)>,
    {
        let query = GqlQuery {
            query_string: q.to_string(),
            allow_literals: false,
            named_bindings: bindings
                .into_iter()
                .map(|(k, v)| (k, GqlQueryParameter { value: v }))
                .collect(),
        };

        let req = RunQueryRequest {
            partition_id: PartitionId {
                project_id: self.project_id().to_string(),
                namespace_id: Some(ns.to_string()),
            },
            read_options: ReadOptions { ..Default::default() },
            gql_query: Some(query),
        };

        let uri = self.mk_uri("runQuery");
        self.post::<_, RunQueryResponse>(&uri, req, &[])
    }

    // Lookup a key using default read options:
    // https://cloud.google.com/datastore/docs/reference/rest/v1/ReadOptions
    fn lookup_one(&self, key: Key) -> client::Result<Option<ValueMap>> {
        let req = LookupRequest {
            keys: Some(vec![key]),
            read_options: None,
        };

        let uri = self.mk_uri("lookup");
        let res = self.post::<_, LookupResponse>(&uri, req, &[])?;

        Ok(
            res.found
                .and_then(|mut f| if f.len() != 1 {
                    None
                } else {
                    f.remove(0).entity
                })
                .and_then(|e| e.properties),
        )
    }

    pub fn update_by_id(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        id: &str,
        props: ValueMap,
    ) -> client::Result<()> {
        let key = self.mk_key(kind, Some(ns), ancestors, None, Some(id));

        let entity = Entity {
            key: Some(key),
            properties: Some(props),
        };

        let update = Mutation {
            update: Some(entity),
            ..Default::default()
        };

        let req = CommitRequest {
            mutations: Some(vec![update]),
            ..Default::default()
        };

        let txn_id = self.begin_transaction()?;
        self.commit(&txn_id, req)?;

        Ok(())
    }

    pub fn delete_by_id(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        id: &str,
    ) -> client::Result<()> {
        let key = self.mk_key(kind, Some(ns), ancestors, None, Some(id));

        let delete = Mutation {
            delete: Some(key),
            ..Default::default()
        };

        let req = CommitRequest {
            mutations: Some(vec![delete]),
            ..Default::default()
        };

        let txn_id = self.begin_transaction()?;
        self.commit(&txn_id, req)?;

        Ok(())
    }

    fn begin_transaction(&self) -> client::Result<String> {
        let uri = self.mk_uri("beginTransaction");
        let req = BeginTransactionRequest::default();
        self.post::<_, BeginTransactionResponse>(&uri, req, &[])
            .map(|r| r.transaction)
    }

    fn commit(&self, txn_id: &str, mut req: CommitRequest) -> client::Result<CommitResponse> {
        req.transaction = txn_id.to_string();
        let uri = self.mk_uri("commit");
        self.post(&uri, req, &[])
    }

    fn mk_uri(&self, action: &str) -> Uri {
        let path = format!(
            "{}/projects/{}:{}",
            DATASTORE_ROOT,
            self.project_id(),
            action
        );
        Uri::from_str(&path).expect("uri to be valid")
    }

    fn mk_key(
        &self,
        kind: &str,
        ns: Option<&str>,
        mut path: Vec<PathElement>,
        name: Option<&str>,
        id: Option<&str>,
    ) -> Key {
        let partition_id = PartitionId {
            project_id: self.project_id().to_string(),
            namespace_id: ns.map(|ns| ns.to_string()),
        };

        path.push(PathElement {
            kind: kind.to_string(),
            name: name.map(|name| name.to_string()),
            id: id.map(|id| id.to_string()),
        });

        Key {
            path: path,
            partition_id: Some(partition_id),
        }
    }
}
<commit_msg>rework datastore apis a bit<commit_after>use std::collections::HashMap;
use std::str::FromStr;

use hyper::Uri;

use client::{self, ApiClient};

static DATASTORE_ROOT: &str = "https://datastore.googleapis.com/v1";

pub struct DatastoreService {}
pub type Hub<'a> = client::Hub<'a, DatastoreService>;

pub type ValueMap = HashMap<String, Value>;

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct BeginTransactionRequest {}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct BeginTransactionResponse {
    pub transaction: String,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CommitRequest {
    pub transaction: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub mode: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub mutations: Option<Vec<Mutation>>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CommitResponse {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub mutation_results: Option<Vec<MutationResult>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub index_updates: Option<i32>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
struct RunQueryRequest {
    partition_id: PartitionId,
    read_options: ReadOptions,

    #[serde(skip_serializing_if = "Option::is_none")]
    gql_query: Option<GqlQuery>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
struct GqlQuery {
    query_string: String,
    allow_literals: bool,
    named_bindings: HashMap<String, GqlQueryParameter>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
struct GqlQueryParameter {
    value: Value,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct RunQueryResponse {
    pub batch: QueryResultBatch,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct QueryResultBatch {
    pub entity_results: Option<Vec<EntityResult>>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Mutation {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub insert: Option<Entity>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub upsert: Option<Entity>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub update: Option<Entity>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub base_version: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub delete: Option<Key>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct MutationResult {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub conflict_detected: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub key: Option<Key>,
}

#[derive(Serialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct LookupRequest {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub keys: Option<Vec<Key>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub read_options: Option<ReadOptions>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct LookupResponse {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub found: Option<Vec<EntityResult>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub missing: Option<Vec<EntityResult>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub deferred: Option<Vec<Key>>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ReadOptions {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub transaction: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub read_consistency: Option<String>,
}

#[derive(Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct EntityResult {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cursor: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub entity: Option<Entity>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Entity {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub properties: Option<HashMap<String, Value>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub key: Option<Key>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Key {
    pub path: Vec<PathElement>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub partition_id: Option<PartitionId>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PathElement {
    pub kind: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PartitionId {
    pub project_id: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub namespace_id: Option<String>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Value {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub entity_value: Option<Entity>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub timestamp_value: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub string_value: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub double_value: Option<f64>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub meaning: Option<i32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub exclude_from_indexes: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub blob_value: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub key_value: Option<Key>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub boolean_value: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub integer_value: Option<i64>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub null_value: Option<String>,

    //#[serde(rename="geoPointValue")]
    //#[serde(skip_serializing_if = "Option::is_none")]
    //pub geo_point_value: Option<LatLng>,

    //#[serde(rename="arrayValue")]
    //#[serde(skip_serializing_if = "Option::is_none")]
    //pub array_value: Option<ArrayValue>,
}

impl<'a> Hub<'a> {
    //
    // api-level operations

    pub fn begin_transaction(&self) -> client::Result<String> {
        let uri = self.mk_uri("beginTransaction");
        let req = BeginTransactionRequest::default();
        self.post::<_, BeginTransactionResponse>(&uri, req, &[])
            .map(|r| r.transaction)
    }

    pub fn commit(&self, req: CommitRequest) -> client::Result<CommitResponse> {
        debug_assert!(!req.transaction.is_empty());
        let uri = self.mk_uri("commit");
        self.post(&uri, req, &[])
    }

    //
    // high-level operations

    pub fn insert_entity_auto_id(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        props: ValueMap,
    ) -> client::Result<String> {
        let key = self.mk_key(kind, Some(ns), ancestors, None, None);
        let res = self.insert(key, props)?;
        let mut results = res.mutation_results.expect("mutations to be valid");

        let mut key = results.remove(0).key.expect("key to be valid");
        Ok(key.path.pop().expect("path to be non-empty").id.expect(
            "id to be valid",
        ))
    }

    pub fn insert_entity_by_name(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        name: &str,
        props: ValueMap,
    ) -> client::Result<()> {
        let key = self.mk_key(kind, Some(ns), ancestors, Some(name), None);
        self.insert(key, props)?;
        Ok(())
    }

    fn insert(&self, key: Key, props: ValueMap) -> client::Result<CommitResponse> {
        let entity = Entity {
            key: Some(key),
            properties: Some(props),
        };

        let insert = Mutation {
            insert: Some(entity),
            ..Default::default()
        };

        let req = CommitRequest {
            transaction: self.begin_transaction()?,
            mutations: Some(vec![insert]),
            ..Default::default()
        };

        self.commit(req)
    }

    pub fn lookup_by_id(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        id: &str,
    ) -> client::Result<Option<ValueMap>> {
        let key = self.mk_key(kind, Some(ns), ancestors, None, Some(id));
        self.lookup_one(key)
    }

    pub fn lookup_by_name(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        name: &str,
    ) -> client::Result<Option<ValueMap>> {
        let key = self.mk_key(kind, Some(ns), ancestors, Some(name), None);
        self.lookup_one(key)
    }

    pub fn gql<B>(&self, ns: &str, q: &str, bindings: B) -> client::Result<RunQueryResponse>
    where
        B: IntoIterator<Item = (String, Value)>,
    {
        let query = GqlQuery {
            query_string: q.to_string(),
            allow_literals: false,
            named_bindings: bindings
                .into_iter()
                .map(|(k, v)| (k, GqlQueryParameter { value: v }))
                .collect(),
        };

        let req = RunQueryRequest {
            partition_id: PartitionId {
                project_id: self.project_id().to_string(),
                namespace_id: Some(ns.to_string()),
            },
            read_options: ReadOptions { ..Default::default() },
            gql_query: Some(query),
        };

        let uri = self.mk_uri("runQuery");
        self.post::<_, RunQueryResponse>(&uri, req, &[])
    }

    // Lookup a key using default read options:
    // https://cloud.google.com/datastore/docs/reference/rest/v1/ReadOptions
    fn lookup_one(&self, key: Key) -> client::Result<Option<ValueMap>> {
        let req = LookupRequest {
            keys: Some(vec![key]),
            read_options: None,
        };

        let uri = self.mk_uri("lookup");
        let res = self.post::<_, LookupResponse>(&uri, req, &[])?;

        Ok(
            res.found
                .and_then(|mut f| if f.len() != 1 {
                    None
                } else {
                    f.remove(0).entity
                })
                .and_then(|e| e.properties),
        )
    }

    pub fn update_by_id(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        id: &str,
        props: ValueMap,
    ) -> client::Result<()> {
        let key = self.mk_key(kind, Some(ns), ancestors, None, Some(id));

        let entity = Entity {
            key: Some(key),
            properties: Some(props),
        };

        let update = Mutation {
            update: Some(entity),
            ..Default::default()
        };

        let req = CommitRequest {
            transaction: self.begin_transaction()?,
            mutations: Some(vec![update]),
            ..Default::default()
        };

        self.commit(req).map(|_| ())
    }

    pub fn delete_by_id(
        &self,
        kind: &str,
        ns: &str,
        ancestors: Vec<PathElement>,
        id: &str,
    ) -> client::Result<()> {
        let key = self.mk_key(kind, Some(ns), ancestors, None, Some(id));

        let delete = Mutation {
            delete: Some(key),
            ..Default::default()
        };

        let req = CommitRequest {
            transaction: self.begin_transaction()?,
            mutations: Some(vec![delete]),
            ..Default::default()
        };

        self.commit(req).map(|_| ())
    }

    fn mk_uri(&self, action: &str) -> Uri {
        let path = format!(
            "{}/projects/{}:{}",
            DATASTORE_ROOT,
            self.project_id(),
            action
        );
        Uri::from_str(&path).expect("uri to be valid")
    }

    fn mk_key(
        &self,
        kind: &str,
        ns: Option<&str>,
        mut path: Vec<PathElement>,
        name: Option<&str>,
        id: Option<&str>,
    ) -> Key {
        let partition_id = PartitionId {
            project_id: self.project_id().to_string(),
            namespace_id: ns.map(|ns| ns.to_string()),
        };

        path.push(PathElement {
            kind: kind.to_string(),
            name: name.map(|name| name.to_string()),
            id: id.map(|id| id.to_string()),
        });

        Key {
            path: path,
            partition_id: Some(partition_id),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2019 Fabian Schuiki

//! A mapping from node IDs to AST nodes.

use ast;
use common::NodeId;
use std::cell::RefCell;
use std::collections::HashMap;

#[derive(Default)]
pub struct AstMap<'ast> {
    map: RefCell<HashMap<NodeId, AstNode<'ast>>>,
}

impl<'ast> AstMap<'ast> {
    /// Insert an AST node into the map.
    pub fn set(&self, id: NodeId, node: impl Into<AstNode<'ast>>) {
        let node = node.into();
        if self.map.borrow_mut().insert(id, node).is_some() {
            panic!("An AST node with ID {} already exists in the map", id);
        }
    }

    /// Retrieve an AST node from the map.
    pub fn get(&self, id: NodeId) -> Option<AstNode<'ast>> {
        self.map.borrow().get(&id).cloned()
    }
}

pub enum AstNode<'ast> {
    Module(&'ast ast::ModDecl),
}
<commit_msg>svlog: impl HasSpan/HasDesc for AstNode<commit_after>// Copyright (c) 2016-2019 Fabian Schuiki

//! A mapping from node IDs to AST nodes.

use ast;
use common::source::Span;
use common::util::{HasDesc, HasSpan};
use common::NodeId;
use std::cell::RefCell;
use std::collections::HashMap;

#[derive(Default)]
pub struct AstMap<'ast> {
    map: RefCell<HashMap<NodeId, AstNode<'ast>>>,
}

impl<'ast> AstMap<'ast> {
    /// Insert an AST node into the map.
    pub fn set(&self, id: NodeId, node: impl Into<AstNode<'ast>>) {
        let node = node.into();
        if self.map.borrow_mut().insert(id, node).is_some() {
            panic!("An AST node with ID {} already exists in the map", id);
        }
    }

    /// Retrieve an AST node from the map.
    pub fn get(&self, id: NodeId) -> Option<AstNode<'ast>> {
        self.map.borrow().get(&id).cloned()
    }
}

/// A reference to an AST node.
///
/// This enum essentially provides a wrapper around typed references to AST
/// nodes. It allows code to obtain a generic reference to an AST node and then
/// match on the actual type that was provided.
#[derive(Clone, Copy, Debug)]
pub enum AstNode<'ast> {
    Module(&'ast ast::ModDecl),
}

impl<'ast> HasSpan for AstNode<'ast> {
    fn span(&self) -> Span {
        match *self {
            AstNode::Module(m) => m.span(),
        }
    }

    fn human_span(&self) -> Span {
        match *self {
            AstNode::Module(m) => m.human_span(),
        }
    }
}

impl<'ast> HasDesc for AstNode<'ast> {
    fn desc(&self) -> &'static str {
        match *self {
            AstNode::Module(m) => m.desc(),
        }
    }

    fn desc_full(&self) -> String {
        match *self {
            AstNode::Module(m) => m.desc_full(),
        }
    }
}
<|endoftext|>


<commit_before>use gl::types::*;
use id_allocator::IdAllocator;
use nalgebra::{normalize, cross};
use nalgebra::{Pnt3, Vec3};
use ncollide::bounding_volume::{AABB, AABB3};
use noise::source::Perlin;
use noise::model::Plane;
use state::EntityId;
use std::cmp::partial_max;
use std::collections::hash_map::HashMap;
use std::num::Float;
use stopwatch::TimerSet;
use terrain::{AMPLITUDE, TerrainType};

pub const BLOCK_WIDTH: i32 = 4;
// Number of samples in a single dimension per block.
pub const SAMPLES_PER_BLOCK: uint = 16;
pub const SAMPLE_WIDTH: f32 = BLOCK_WIDTH as f32 / SAMPLES_PER_BLOCK as f32;

#[deriving(Show, PartialEq, Eq, Hash, Copy, Clone)]
pub struct BlockPosition(Pnt3<i32>);

impl BlockPosition {
  #[inline(always)]
  pub fn new(x: i32, y: i32, z: i32) -> BlockPosition {
    BlockPosition(Pnt3::new(x, y, z))
  }

  #[inline(always)]
  pub fn as_pnt<'a>(&'a self) -> &'a Pnt3<i32> {
    let BlockPosition(ref pnt) = *self;
    pnt
  }

  #[inline(always)]
  pub fn as_mut_pnt3<'a>(&'a mut self) -> &'a mut Pnt3<i32> {
    let BlockPosition(ref mut pnt) = *self;
    pnt
  }

  pub fn from_world_position(world_position: &Pnt3<f32>) -> BlockPosition {
    macro_rules! convert_coordinate(
      ($x: expr) => ({
        let x = $x.floor() as i32;
        let x =
          if x < 0 {
            x - (BLOCK_WIDTH - 1)
          } else {
            x
          };
        x / BLOCK_WIDTH
      })
    );
    BlockPosition(
      Pnt3::new(
        convert_coordinate!(world_position.x),
        convert_coordinate!(world_position.y),
        convert_coordinate!(world_position.z),
      )
    )
  }

  pub fn to_world_position(&self) -> Pnt3<f32> {
    Pnt3::new(
      (self.as_pnt().x * BLOCK_WIDTH) as f32,
      (self.as_pnt().y * BLOCK_WIDTH) as f32,
      (self.as_pnt().z * BLOCK_WIDTH) as f32,
    )
  }
}

impl Add<Vec3<i32>, BlockPosition> for BlockPosition {
  fn add(mut self, rhs: Vec3<i32>) -> Self {
    self.as_mut_pnt3().x += rhs.x;
    self.as_mut_pnt3().y += rhs.y;
    self.as_mut_pnt3().z += rhs.z;
    self
  }
}

/// Ductyped heightmap methods.
trait HeightMapExt {
  /// The coordinate of the tile at a given x/z.
  fn point_at(&self, x: f32, z: f32) -> Pnt3<f32>;
  /// The lighting normal of the tile at a given x/z.
  fn normal_at(&self, x: f32, z: f32) -> Vec3<f32>;
}

impl<'a> HeightMapExt for Plane<'a, Perlin> {
  fn point_at(&self, x: f32, z: f32) -> Pnt3<f32> {
    let y = AMPLITUDE * (self.get(x, z) + 1.0) / 2.0;
    Pnt3::new(x, y, z)
  }

  fn normal_at(&self, x: f32, z: f32) -> Vec3<f32> {
    const DELTA: f32 = 0.2;
    let dx = self.point_at(x + DELTA, z).to_vec() - self.point_at(x - DELTA, z).to_vec();
    let dz = self.point_at(x, z + DELTA).to_vec() - self.point_at(x, z - DELTA).to_vec();
    normalize(&cross(&dx, &dz))
  }
}

pub struct TerrainBlock {
  // These Vecs must all be ordered the same way.

  // vertex coordinates flattened into separate GLfloats (x, y, z order)
  pub vertex_coordinates: Vec<GLfloat>,
  // per-vertex normal vectors flattened into separate GLfloats (x, y, z order)
  pub normals: Vec<GLfloat>,
  // per-triangle terrain types
  pub typs: Vec<GLuint>,

  // per-triangle entity IDs
  pub ids: Vec<EntityId>,
  // per-triangle bounding boxes
  pub bounds: HashMap<EntityId, AABB3<GLfloat>>,
}

impl TerrainBlock {
  pub fn empty() -> TerrainBlock {
    TerrainBlock {
      vertex_coordinates: Vec::new(),
      normals: Vec::new(),
      typs: Vec::new(),
      ids: Vec::new(),
      bounds: HashMap::new(),
    }
  }

  pub fn generate(
    timers: &TimerSet,
    id_allocator: &mut IdAllocator<EntityId>,
    heightmap: &Perlin,
    position: &BlockPosition,
  ) -> TerrainBlock {
    timers.time("update.generate_block", || {
      let mut block = TerrainBlock::empty();
      let heightmap = Plane::new(heightmap);

      let x = (position.as_pnt().x * BLOCK_WIDTH) as f32;
      let y = (position.as_pnt().y * BLOCK_WIDTH) as f32;
      let z = (position.as_pnt().z * BLOCK_WIDTH) as f32;

      for dx in range(0, SAMPLES_PER_BLOCK) {
        let x = x + dx as f32 * SAMPLE_WIDTH;
        for dz in range(0, SAMPLES_PER_BLOCK) {
          let z = z + dz as f32 * SAMPLE_WIDTH;
          let position = Pnt3::new(x, y, z);
          TerrainBlock::add_tile(
            timers,
            &heightmap,
            id_allocator,
            &mut block,
            &position,
          );
        }
      }

      block
    })
  }

  fn add_tile<'a>(
    timers: &TimerSet,
    hm: &Plane<'a, Perlin>,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
    position: &Pnt3<f32>,
  ) {
    let half_width = SAMPLE_WIDTH / 2.0;
    let center = hm.point_at(position.x + half_width, position.z + half_width);

    if position.y < center.y && center.y <= position.y + BLOCK_WIDTH as f32 {
      timers.time("update.generate_block.add_tile", || {
        let center_normal = hm.normal_at(position.x + half_width, position.z + half_width);

        let x2 = position.x + SAMPLE_WIDTH;
        let z2 = position.z + SAMPLE_WIDTH;

        let ps: [Pnt3<f32>, ..4] =
          [ hm.point_at(position.x, position.z)
          , hm.point_at(position.x, z2)
          , hm.point_at(x2, z2)
          , hm.point_at(x2, position.z)
          ];

        let ns: [Vec3<f32>, ..4] =
          [ hm.normal_at(position.x, position.z)
          , hm.normal_at(position.x, x2)
          , hm.normal_at(x2, z2)
          , hm.normal_at(x2, position.z)
          ];

        let center_lower_than = ps.iter().filter(|v| center.y < v.y).count();

        let terrain_type =
          if center_lower_than >= 3 {
            TerrainType::Dirt
          } else {
            TerrainType::Grass
          };

        macro_rules! place_terrain(
          ($v1: expr,
           $v2: expr,
           $n1: expr,
           $n2: expr,
           $minx: expr,
           $minz: expr,
           $maxx: expr,
           $maxz: expr
          ) => ({
            let maxy = partial_max($v1.y, $v2.y);
            let maxy = maxy.and_then(|m| partial_max(m, center.y));
            let maxy = maxy.unwrap();

            let id = id_allocator.allocate();
            block.vertex_coordinates.push_all(&[
              $v1.x, $v1.y, $v1.z,
              $v2.x, $v2.y, $v2.z,
              center.x, center.y, center.z,
            ]);
            block.normals.push_all(&[
              $n1.x, $n1.y, $n1.z,
              $n2.x, $n2.y, $n2.z,
              center_normal.x, center_normal.y, center_normal.z,
            ]);
            block.typs.push(terrain_type as GLuint);
            block.ids.push(id);
            block.bounds.insert(
              id,
              AABB::new(
                Pnt3::new($minx, $v1.y, $minz),
                Pnt3::new($maxx, maxy, $maxz),
              ),
            );
          });
        );

        let centr = center; // makes alignment nice
        place_terrain!(&ps[0], &ps[1], &ns[0], &ns[1], ps[0].x, ps[0].z, centr.x, ps[1].z);
        place_terrain!(&ps[1], &ps[2], &ns[1], &ns[2], ps[1].x, centr.z, ps[2].x, ps[2].z);
        place_terrain!(&ps[2], &ps[3], &ns[2], &ns[3], centr.x, centr.z, ps[2].x, ps[2].z);
        place_terrain!(&ps[3], &ps[0], &ns[3], &ns[0], ps[0].x, ps[0].z, ps[3].x, centr.z);
      })
    }
  }
}
<commit_msg>speed demon<commit_after>use gl::types::*;
use id_allocator::IdAllocator;
use nalgebra::{normalize, cross};
use nalgebra::{Pnt3, Vec3};
use ncollide::bounding_volume::{AABB, AABB3};
use noise::source::Perlin;
use noise::model::Plane;
use state::EntityId;
use std::cmp::partial_max;
use std::collections::hash_map::HashMap;
use std::num::Float;
use stopwatch::TimerSet;
use terrain::{AMPLITUDE, TerrainType};

pub const BLOCK_WIDTH: i32 = 4;
// Number of samples in a single dimension per block.
pub const SAMPLES_PER_BLOCK: uint = 16;
pub const SAMPLE_WIDTH: f32 = BLOCK_WIDTH as f32 / SAMPLES_PER_BLOCK as f32;

#[deriving(Show, PartialEq, Eq, Hash, Copy, Clone)]
pub struct BlockPosition(Pnt3<i32>);

impl BlockPosition {
  #[inline(always)]
  pub fn new(x: i32, y: i32, z: i32) -> BlockPosition {
    BlockPosition(Pnt3::new(x, y, z))
  }

  #[inline(always)]
  pub fn as_pnt<'a>(&'a self) -> &'a Pnt3<i32> {
    let BlockPosition(ref pnt) = *self;
    pnt
  }

  #[inline(always)]
  pub fn as_mut_pnt3<'a>(&'a mut self) -> &'a mut Pnt3<i32> {
    let BlockPosition(ref mut pnt) = *self;
    pnt
  }

  pub fn from_world_position(world_position: &Pnt3<f32>) -> BlockPosition {
    macro_rules! convert_coordinate(
      ($x: expr) => ({
        let x = $x.floor() as i32;
        let x =
          if x < 0 {
            x - (BLOCK_WIDTH - 1)
          } else {
            x
          };
        x / BLOCK_WIDTH
      })
    );
    BlockPosition(
      Pnt3::new(
        convert_coordinate!(world_position.x),
        convert_coordinate!(world_position.y),
        convert_coordinate!(world_position.z),
      )
    )
  }

  pub fn to_world_position(&self) -> Pnt3<f32> {
    Pnt3::new(
      (self.as_pnt().x * BLOCK_WIDTH) as f32,
      (self.as_pnt().y * BLOCK_WIDTH) as f32,
      (self.as_pnt().z * BLOCK_WIDTH) as f32,
    )
  }
}

impl Add<Vec3<i32>, BlockPosition> for BlockPosition {
  fn add(mut self, rhs: Vec3<i32>) -> Self {
    self.as_mut_pnt3().x += rhs.x;
    self.as_mut_pnt3().y += rhs.y;
    self.as_mut_pnt3().z += rhs.z;
    self
  }
}

/// Ductyped heightmap methods.
trait HeightMapExt {
  /// The coordinate of the tile at a given x/z.
  fn point_at(&self, x: f32, z: f32) -> Pnt3<f32>;
  /// The lighting normal of the tile at a given x/z.
  fn normal_at(&self, x: f32, z: f32) -> Vec3<f32>;
}

impl<'a> HeightMapExt for Plane<'a, Perlin> {
  fn point_at(&self, x: f32, z: f32) -> Pnt3<f32> {
    let y = AMPLITUDE * (self.get(x, z) + 1.0) / 2.0;
    Pnt3::new(x, y, z)
  }

  fn normal_at(&self, x: f32, z: f32) -> Vec3<f32> {
    const DELTA: f32 = 0.2;
    let dx = self.point_at(x + DELTA, z).to_vec() - self.point_at(x - DELTA, z).to_vec();
    let dz = self.point_at(x, z + DELTA).to_vec() - self.point_at(x, z - DELTA).to_vec();
    normalize(&cross(&dx, &dz))
  }
}

pub struct TerrainBlock {
  // These Vecs must all be ordered the same way.

  // vertex coordinates flattened into separate GLfloats (x, y, z order)
  pub vertex_coordinates: Vec<GLfloat>,
  // per-vertex normal vectors flattened into separate GLfloats (x, y, z order)
  pub normals: Vec<GLfloat>,
  // per-triangle terrain types
  pub typs: Vec<GLuint>,

  // per-triangle entity IDs
  pub ids: Vec<EntityId>,
  // per-triangle bounding boxes
  pub bounds: HashMap<EntityId, AABB3<GLfloat>>,
}

impl TerrainBlock {
  pub fn empty() -> TerrainBlock {
    TerrainBlock {
      vertex_coordinates: Vec::new(),
      normals: Vec::new(),
      typs: Vec::new(),
      ids: Vec::new(),
      bounds: HashMap::new(),
    }
  }

  pub fn generate(
    timers: &TimerSet,
    id_allocator: &mut IdAllocator<EntityId>,
    heightmap: &Perlin,
    position: &BlockPosition,
  ) -> TerrainBlock {
    timers.time("update.generate_block", || {
      let mut block = TerrainBlock::empty();
      let heightmap = Plane::new(heightmap);

      let x = (position.as_pnt().x * BLOCK_WIDTH) as f32;
      let y = (position.as_pnt().y * BLOCK_WIDTH) as f32;
      let z = (position.as_pnt().z * BLOCK_WIDTH) as f32;

      for dx in range(0, SAMPLES_PER_BLOCK) {
        let x = x + dx as f32 * SAMPLE_WIDTH;
        for dz in range(0, SAMPLES_PER_BLOCK) {
          let z = z + dz as f32 * SAMPLE_WIDTH;
          let position = Pnt3::new(x, y, z);
          TerrainBlock::add_tile(
            timers,
            &heightmap,
            id_allocator,
            &mut block,
            &position,
          );
        }
      }

      block
    })
  }

  fn add_tile<'a>(
    timers: &TimerSet,
    hm: &Plane<'a, Perlin>,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
    position: &Pnt3<f32>,
  ) {
    let half_width = SAMPLE_WIDTH / 2.0;
    let center = hm.point_at(position.x + half_width, position.z + half_width);

    if position.y >= center.y || center.y > position.y + BLOCK_WIDTH as f32 {
      return;
    }

    timers.time("update.generate_block.add_tile", || {
      let center_normal = hm.normal_at(position.x + half_width, position.z + half_width);

      let x2 = position.x + SAMPLE_WIDTH;
      let z2 = position.z + SAMPLE_WIDTH;

      let ps: [Pnt3<f32>, ..4] =
        [ hm.point_at(position.x, position.z)
        , hm.point_at(position.x, z2)
        , hm.point_at(x2, z2)
        , hm.point_at(x2, position.z)
        ];

      let ns: [Vec3<f32>, ..4] =
        [ hm.normal_at(position.x, position.z)
        , hm.normal_at(position.x, x2)
        , hm.normal_at(x2, z2)
        , hm.normal_at(x2, position.z)
        ];

      let center_lower_than = ps.iter().filter(|v| center.y < v.y).count();

      let terrain_type =
        if center_lower_than >= 3 {
          TerrainType::Dirt
        } else {
          TerrainType::Grass
        };

      macro_rules! place_terrain(
        ($v1: expr,
         $v2: expr,
         $n1: expr,
         $n2: expr,
         $minx: expr,
         $minz: expr,
         $maxx: expr,
         $maxz: expr
        ) => ({
          let maxy = partial_max($v1.y, $v2.y);
          let maxy = maxy.and_then(|m| partial_max(m, center.y));
          let maxy = maxy.unwrap();

          let id = id_allocator.allocate();
          block.vertex_coordinates.push_all(&[
            $v1.x, $v1.y, $v1.z,
            $v2.x, $v2.y, $v2.z,
            center.x, center.y, center.z,
          ]);
          block.normals.push_all(&[
            $n1.x, $n1.y, $n1.z,
            $n2.x, $n2.y, $n2.z,
            center_normal.x, center_normal.y, center_normal.z,
          ]);
          block.typs.push(terrain_type as GLuint);
          block.ids.push(id);
          block.bounds.insert(
            id,
            AABB::new(
              Pnt3::new($minx, $v1.y, $minz),
              Pnt3::new($maxx, maxy, $maxz),
            ),
          );
        });
      );

      let placements = 4;
      block.vertex_coordinates.reserve(placements*9);
      block.normals.reserve(placements*9);
      block.typs.reserve(placements);
      block.ids.reserve(placements);
      block.bounds.reserve(placements);

      let centr = center; // makes alignment nice
      place_terrain!(&ps[0], &ps[1], &ns[0], &ns[1], ps[0].x, ps[0].z, centr.x, ps[1].z);
      place_terrain!(&ps[1], &ps[2], &ns[1], &ns[2], ps[1].x, centr.z, ps[2].x, ps[2].z);
      place_terrain!(&ps[2], &ps[3], &ns[2], &ns[3], centr.x, centr.z, ps[2].x, ps[2].z);
      place_terrain!(&ps[3], &ps[0], &ns[3], &ns[0], ps[0].x, ps[0].z, ps[3].x, centr.z);
    })
  }
}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library 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. This file may not be copied, modified, or distributed
// except according to those terms.

use serde_json;
use std;
use std::collections::HashMap;
use v2::json::*;

pub use self::error::Error;

/// Trait for validating glTF JSON data against the 2.0 specification.
pub trait Validate {
    /// Validates the data against the glTF 2.0 specification.
    fn validate<F>(&self, root: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error);
}

/// Contains `Error` and other related data structures.
pub mod error {
    use serde_json;
    use std;
    use super::JsonPath;

    /// Error encountered when validating glTF 2.0 JSON data.
    #[derive(Clone, Debug)]
    pub struct Error {
        /// JSON source path of the offending data.
        path: JsonPath,

        /// Error kind.
        kind: Kind,
    }

    /// Specifies what kind of error occured during validation.
    #[derive(Clone, Debug)]
    pub enum Kind {
        /// An index was found to be out of bounds.
        IndexOutOfBounds,

        /// An invalid enumeration constant was identified.
        InvalidEnum(serde_json::Value),

        /// An invalid value was identified.
        InvalidValue(serde_json::Value),

        /// Some required data has been omitted.
        MissingData(String),
    }

    impl Error {
        /// Returns an `IndexOutOfBounds` error.
        pub fn index_out_of_bounds(path: JsonPath) -> Error {
            Error {
                kind: Kind::IndexOutOfBounds,
                path: path,
            }
        }

        /// Returns an `InvalidEnum` error.
        pub fn invalid_enum<V>(path: JsonPath, value: V) -> Error
            where V: Into<serde_json::Value>
        {
            Error {
                kind: Kind::InvalidEnum(value.into()),
                path: path,
            }
        }

        /// Returns an `InvalidValue` error.
        pub fn invalid_value<V>(path: JsonPath, value: V) -> Error
            where V: Into<serde_json::Value>
        {
            Error {
                kind: Kind::InvalidValue(value.into()),
                path: path,
            }
        }

        /// Returns an `MissingData` error.
        pub fn missing_data(path: JsonPath, reason: String) -> Error {
            Error {
                kind: Kind::MissingData(reason),
                path: path,
            }
        }
    }

    impl std::error::Error for Error {
        fn description(&self) -> &str {
            match &self.kind {
                &Kind::IndexOutOfBounds => "Index out of bounds",
                &Kind::InvalidEnum(_) => "Invalid enumeration constant",
                &Kind::InvalidValue(_) => "Invalid value",
                &Kind::MissingData(_) => "Missing data",
            }
        }
    }

    impl std::fmt::Display for Error {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            use std::error::Error;
            match &self.kind {
                &Kind::IndexOutOfBounds => {
                    write!(f, "{} ({})", self.path, self.description())
                },
                &Kind::InvalidEnum(ref value) => {
                    write!(f, "{}: {} ({})", self.path, value, self.description())
                },
                &Kind::InvalidValue(ref value) => {
                    write!(f, "{}: {} ({})", self.path, value, self.description())
                },
                &Kind::MissingData(ref reason) => {
                    write!(f, "{}: {} ({})", self.path, self.description(), reason)
                },
            }
        }
    }
}

/// An immutable JSON source path.
#[derive(Clone, Debug)]
pub struct JsonPath(String);

impl JsonPath {
    /// Creates an empty JSON source path.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// # use gltf::v2::validation::JsonPath;
    /// let path = JsonPath::new();
    /// assert_eq!("", path.as_str());
    /// ```
    pub fn new() -> Self {
        JsonPath(String::new())
    }

    /// Returns a new path ending with the given field.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// # use gltf::v2::validation::JsonPath;
    /// let path = JsonPath::new().field("foo");
    /// assert_eq!("foo", path.as_str());
    /// assert_eq!("foo.bar", path.field("bar").as_str());
    /// ```
    pub fn field(&self, name: &str) -> Self {
        if self.0.is_empty() {
            JsonPath(name.to_string())
        } else {
            JsonPath(format!("{}.{}", self.0, name))
        }
    }

    /// Returns a new path ending with the given array index.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// # use gltf::v2::validation::JsonPath;
    /// let path = JsonPath::new().field("foo");
    /// assert_eq!("foo[123]", path.index(123).as_str());
    /// ```
    pub fn index(&self, index: usize) -> Self {
        JsonPath(format!("{}[{}]", self.0, index))
    }

    /// Returns a new path ending with the given object key.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// # use gltf::v2::validation::JsonPath;
    /// let path = JsonPath::new().field("foo");
    /// assert_eq!("foo[\"bar\"]", path.key("bar").as_str());
    /// ```
    pub fn key(&self, key: &str) -> Self {
        JsonPath(format!("{}[\"{}\"]", self.0, key))
    }

    /// Returns a view into the internal representation.
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl std::fmt::Display for JsonPath {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl<T: Validate> Validate for HashMap<String, T> {
    fn validate<F>(&self, root: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error)
    {
        for (key, value) in self.iter() {
            value.validate(root, path.key(key), report);
        }
    }
}

impl<T: Validate> Validate for Option<T> {
    fn validate<F>(&self, root: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error)
    {
        if let Some(value) = self.as_ref() {
            value.validate(root, path, report);
        }
    }
}

impl<T: Validate> Validate for Vec<T> {
    fn validate<F>(&self, root: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error)
    {
        for (index, value) in self.iter().enumerate() {
            value.validate(root, path.index(index), report);
        }
    }
}

impl Validate for bool {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for u32 {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for i32 {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for f32 {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for [f32; 3] {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for [f32; 4] {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for [f32; 16] {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for () {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for String {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for serde_json::Value {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

<commit_msg>Fixed typo<commit_after>
// Copyright 2017 The gltf Library 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. This file may not be copied, modified, or distributed
// except according to those terms.

use serde_json;
use std;
use std::collections::HashMap;
use v2::json::*;

pub use self::error::Error;

/// Trait for validating glTF JSON data against the 2.0 specification.
pub trait Validate {
    /// Validates the data against the glTF 2.0 specification.
    fn validate<F>(&self, root: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error);
}

/// Contains `Error` and other related data structures.
pub mod error {
    use serde_json;
    use std;
    use super::JsonPath;

    /// Error encountered when validating glTF 2.0 JSON data.
    #[derive(Clone, Debug)]
    pub struct Error {
        /// JSON source path of the offending data.
        path: JsonPath,

        /// Error kind.
        kind: Kind,
    }

    /// Specifies what kind of error occured during validation.
    #[derive(Clone, Debug)]
    pub enum Kind {
        /// An index was found to be out of bounds.
        IndexOutOfBounds,

        /// An invalid enumeration constant was identified.
        InvalidEnum(serde_json::Value),

        /// An invalid value was identified.
        InvalidValue(serde_json::Value),

        /// Some required data has been omitted.
        MissingData(String),
    }

    impl Error {
        /// Returns an `IndexOutOfBounds` error.
        pub fn index_out_of_bounds(path: JsonPath) -> Error {
            Error {
                kind: Kind::IndexOutOfBounds,
                path: path,
            }
        }

        /// Returns an `InvalidEnum` error.
        pub fn invalid_enum<V>(path: JsonPath, value: V) -> Error
            where V: Into<serde_json::Value>
        {
            Error {
                kind: Kind::InvalidEnum(value.into()),
                path: path,
            }
        }

        /// Returns an `InvalidValue` error.
        pub fn invalid_value<V>(path: JsonPath, value: V) -> Error
            where V: Into<serde_json::Value>
        {
            Error {
                kind: Kind::InvalidValue(value.into()),
                path: path,
            }
        }

        /// Returns a `MissingData` error.
        pub fn missing_data(path: JsonPath, reason: String) -> Error {
            Error {
                kind: Kind::MissingData(reason),
                path: path,
            }
        }
    }

    impl std::error::Error for Error {
        fn description(&self) -> &str {
            match &self.kind {
                &Kind::IndexOutOfBounds => "Index out of bounds",
                &Kind::InvalidEnum(_) => "Invalid enumeration constant",
                &Kind::InvalidValue(_) => "Invalid value",
                &Kind::MissingData(_) => "Missing data",
            }
        }
    }

    impl std::fmt::Display for Error {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            use std::error::Error;
            match &self.kind {
                &Kind::IndexOutOfBounds => {
                    write!(f, "{} ({})", self.path, self.description())
                },
                &Kind::InvalidEnum(ref value) => {
                    write!(f, "{}: {} ({})", self.path, value, self.description())
                },
                &Kind::InvalidValue(ref value) => {
                    write!(f, "{}: {} ({})", self.path, value, self.description())
                },
                &Kind::MissingData(ref reason) => {
                    write!(f, "{}: {} ({})", self.path, self.description(), reason)
                },
            }
        }
    }
}

/// An immutable JSON source path.
#[derive(Clone, Debug)]
pub struct JsonPath(String);

impl JsonPath {
    /// Creates an empty JSON source path.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// # use gltf::v2::validation::JsonPath;
    /// let path = JsonPath::new();
    /// assert_eq!("", path.as_str());
    /// ```
    pub fn new() -> Self {
        JsonPath(String::new())
    }

    /// Returns a new path ending with the given field.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// # use gltf::v2::validation::JsonPath;
    /// let path = JsonPath::new().field("foo");
    /// assert_eq!("foo", path.as_str());
    /// assert_eq!("foo.bar", path.field("bar").as_str());
    /// ```
    pub fn field(&self, name: &str) -> Self {
        if self.0.is_empty() {
            JsonPath(name.to_string())
        } else {
            JsonPath(format!("{}.{}", self.0, name))
        }
    }

    /// Returns a new path ending with the given array index.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// # use gltf::v2::validation::JsonPath;
    /// let path = JsonPath::new().field("foo");
    /// assert_eq!("foo[123]", path.index(123).as_str());
    /// ```
    pub fn index(&self, index: usize) -> Self {
        JsonPath(format!("{}[{}]", self.0, index))
    }

    /// Returns a new path ending with the given object key.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// # use gltf::v2::validation::JsonPath;
    /// let path = JsonPath::new().field("foo");
    /// assert_eq!("foo[\"bar\"]", path.key("bar").as_str());
    /// ```
    pub fn key(&self, key: &str) -> Self {
        JsonPath(format!("{}[\"{}\"]", self.0, key))
    }

    /// Returns a view into the internal representation.
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl std::fmt::Display for JsonPath {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl<T: Validate> Validate for HashMap<String, T> {
    fn validate<F>(&self, root: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error)
    {
        for (key, value) in self.iter() {
            value.validate(root, path.key(key), report);
        }
    }
}

impl<T: Validate> Validate for Option<T> {
    fn validate<F>(&self, root: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error)
    {
        if let Some(value) = self.as_ref() {
            value.validate(root, path, report);
        }
    }
}

impl<T: Validate> Validate for Vec<T> {
    fn validate<F>(&self, root: &Root, path: JsonPath, report: &mut F)
        where F: FnMut(Error)
    {
        for (index, value) in self.iter().enumerate() {
            value.validate(root, path.index(index), report);
        }
    }
}

impl Validate for bool {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for u32 {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for i32 {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for f32 {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for [f32; 3] {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for [f32; 4] {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for [f32; 16] {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for () {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for String {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

impl Validate for serde_json::Value {
    fn validate<F>(&self, _root: &Root, _path: JsonPath, _report: &mut F)
        where F: FnMut(Error)
    {
        // nop
    }
}

<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use gl_context::GLContext;
use shader::*;
use std::ffi::CString;
use std::mem;
use std::num;
use std::ptr;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case)]
pub fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  let c_str = CString::from_slice(name.as_bytes());
  let ptr = c_str.as_ptr() as *const i8;
  unsafe {
    gl::GetAttribLocation(shader_program, ptr)
  }
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
}

impl<'a> BufferHandle<'a> {
  pub fn new<'b:'a>(_gl: &'a GLContext) -> BufferHandle<'b> {
    let mut gl_id = 0;

    unsafe {
      gl::GenBuffers(1, &mut gl_id);
    }

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for BufferHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.gl_id);
    }
  }
}

/// Fixed-size VRAM buffer for individual bytes.
pub struct GLByteBuffer<'a> {
  pub handle: BufferHandle<'a>,
  /// number of bytes in the buffer.
  pub length: usize,
  /// maximum number of bytes in the buffer.
  pub capacity: usize,
}

impl<'a> GLByteBuffer<'a> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new<'b:'a>(
    gl: &'a mut GLContext,
    capacity: usize,
  ) -> GLByteBuffer<'b> {
    let handle = BufferHandle::new(gl);

    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, handle.gl_id);

      gl::BufferData(
        gl::ARRAY_BUFFER,
        capacity as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );
    }

    match gl.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => warn!("OpenGL error 0x{:x}", err),
    }

    GLByteBuffer {
      handle: handle,
      length: 0,
      capacity: capacity,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);
    }
  }

  /// Add more data into this buffer.
  /// Returns false and does nothing if this would exceed the capacity of the buffer.
  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: usize) -> bool {
    if self.length + count > self.capacity {
      // This would overflow the buffer.
      return false;
    }

    self.update_inner(gl, self.length, vs, count);
    self.length += count;

    true
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: usize, count: usize) {
    assert!(count <= self.length);
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLByteBuffer::swap_remove would cause copy in overlapping regions"
      );

      unsafe {
        gl::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as i64,
          i as i64,
          count as i64,
        );
      }
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub unsafe fn update(&self, gl: &mut GLContext, idx: usize, vs: *const u8, count: usize) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  unsafe fn update_inner(
    &self,
    _gl: &mut GLContext,
    idx: usize,
    vs: *const u8,
    count: usize,
  ) {
    assert!(idx + count <= self.capacity);

    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      idx as i64,
      count as i64,
      mem::transmute(vs)
    );
  }
}

/// Fixed-size typed VRAM buffer, optimized for bulk inserts.
pub struct GLBuffer<'a, T> {
  pub byte_buffer: GLByteBuffer<'a>,
}

impl<'a, T> GLBuffer<'a, T> {
  pub fn new<'b:'a>(
    gl: &'a mut GLContext,
    capacity: usize,
  ) -> GLBuffer<'b, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, capacity * mem::size_of::<T>()),
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) -> bool {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      )
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn update(&mut self, gl: &mut GLContext, idx: usize, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
  }
}

#[derive(Debug)]
#[derive(Copy, Clone)]
pub enum DrawMode {
  Lines,
  Triangles,
  Points,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match *self {
      DrawMode::Lines     => gl::LINES,
      DrawMode::Triangles => gl::TRIANGLES,
      DrawMode::Points    => gl::POINTS,
    }
  }
}

#[derive(Debug)]
#[derive(Copy, Clone)]
pub enum GLType {
  Float,
  UInt,
  Int,
}

impl GLType {
  pub fn size(&self) -> u32 {
    num::cast(
      match *self {
        GLType::Float => mem::size_of::<GLfloat>(),
        GLType::UInt  => mem::size_of::<GLuint>(),
        GLType::Int   => mem::size_of::<GLint>(),
      })
    .unwrap()
  }

  pub fn gl_enum(&self) -> GLenum {
    match *self {
      GLType::Float => gl::FLOAT,
      GLType::UInt  => gl::UNSIGNED_INT,
      GLType::Int   => gl::INT,
    }
  }

  pub fn is_integral(&self) -> bool {
    match *self {
      GLType::Float => false,
      GLType::UInt  => true,
      GLType::Int   => true,
    }
  }
}

#[derive(Debug)]
/// Specifies how to pass data from OpenGL to the vertex shaders.
pub struct VertexAttribData<'a> {
  /// Cooresponds to the shader's `input variable`.
  pub name: &'a str,
  /// The size of this attribute, in the provided units.
  pub size: u32,
  pub unit: GLType,
}

pub struct ArrayHandle<'a> {
  pub gl_id: GLuint,
}

impl<'a> ArrayHandle<'a> {
  pub fn new<'b:'a>(_gl: &'a GLContext) -> ArrayHandle<'b> {
    let mut gl_id = 0;
    unsafe {
      gl::GenVertexArrays(1, &mut gl_id);
    }

    ArrayHandle {
      gl_id: gl_id,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ArrayHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteVertexArrays(1, &self.gl_id);
    }
  }
}

/// A fixed-capacity array of bytes passed to OpenGL.
pub struct GLArray<'a, T> {
  pub buffer: GLBuffer<'a, T>,
  pub handle: ArrayHandle<'a>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// length in `T`s.
  pub length: usize,
}

impl<'a, T> GLArray<'a, T> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new<'b:'a>(
    gl: &'a mut GLContext,
    shader_program: &Shader<'b>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'b, T>,
  ) -> GLArray<'b, T> {
    let handle = ArrayHandle::new(gl);

    unsafe {
      gl::BindVertexArray(handle.gl_id);
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size * attrib.unit.size();
      }
      attrib_span
    };
    for attrib in attribs.iter() {
      let shader_attrib =
        glGetAttribLocation(
          shader_program.handle.gl_id,
          attrib.name
        );
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);
      let shader_attrib = shader_attrib as GLuint;

      unsafe {
        gl::EnableVertexAttribArray(shader_attrib);

        if attrib.unit.is_integral() {
          gl::VertexAttribIPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        } else {
          gl::VertexAttribPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            gl::FALSE as GLboolean,
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        }
      }
      offset += (attrib.size * attrib.unit.size()) as isize;
    }

    match unsafe { gl::GetError() } {
      gl::NO_ERROR => {},
      err => warn!("OpenGL error 0x{:x}", err),
    }

    assert_eq!(attrib_span as usize, mem::size_of::<T>());

    let length = buffer.byte_buffer.length / mem::size_of::<T>();

    GLArray {
      buffer: buffer,
      handle: handle,
      mode: mode.to_enum(),
      length: length,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  /// The array doesn't need to be bound.
  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) -> bool {
    self.length += vs.len();
    let r = self.buffer.push(gl, vs);
    r
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  /// The array doesn't need to be bound.
  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count;
  }

  /// Draws all the queued triangles to the screen.
  /// N.B. For performance reasons, this does NOT bind the array.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  /// N.B. For performance reasons, this does NOT bind the array.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: usize, len: usize) {
    assert!(start + len <= self.length);

    unsafe {
      gl::DrawArrays(self.mode, start as i32, len as i32);
    }
  }
}
<commit_msg>i64 -> GLsizeiptr/GLintptr in gl[Copy]BufferSubData params.<commit_after>use gl;
use gl::types::*;
use gl_context::GLContext;
use shader::*;
use std::ffi::CString;
use std::mem;
use std::num;
use std::ptr;

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case)]
pub fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  let c_str = CString::from_slice(name.as_bytes());
  let ptr = c_str.as_ptr() as *const i8;
  unsafe {
    gl::GetAttribLocation(shader_program, ptr)
  }
}

pub struct BufferHandle<'a> {
  pub gl_id: GLuint,
}

impl<'a> BufferHandle<'a> {
  pub fn new<'b:'a>(_gl: &'a GLContext) -> BufferHandle<'b> {
    let mut gl_id = 0;

    unsafe {
      gl::GenBuffers(1, &mut gl_id);
    }

    assert!(gl_id != 0);

    BufferHandle {
      gl_id: gl_id,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for BufferHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.gl_id);
    }
  }
}

/// Fixed-size VRAM buffer for individual bytes.
pub struct GLByteBuffer<'a> {
  pub handle: BufferHandle<'a>,
  /// number of bytes in the buffer.
  pub length: usize,
  /// maximum number of bytes in the buffer.
  pub capacity: usize,
}

impl<'a> GLByteBuffer<'a> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new<'b:'a>(
    gl: &'a mut GLContext,
    capacity: usize,
  ) -> GLByteBuffer<'b> {
    let handle = BufferHandle::new(gl);

    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, handle.gl_id);

      gl::BufferData(
        gl::ARRAY_BUFFER,
        capacity as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );
    }

    match gl.get_error() {
      gl::NO_ERROR => {},
      gl::OUT_OF_MEMORY => panic!("Out of VRAM"),
      err => warn!("OpenGL error 0x{:x}", err),
    }

    GLByteBuffer {
      handle: handle,
      length: 0,
      capacity: capacity,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindBuffer(gl::ARRAY_BUFFER, self.handle.gl_id);
    }
  }

  /// Add more data into this buffer.
  /// Returns false and does nothing if this would exceed the capacity of the buffer.
  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub unsafe fn push(&mut self, gl: &mut GLContext, vs: *const u8, count: usize) -> bool {
    if self.length + count > self.capacity {
      // This would overflow the buffer.
      return false;
    }

    self.update_inner(gl, self.length, vs, count);
    self.length += count;

    true
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn swap_remove(&mut self, _gl: &mut GLContext, i: usize, count: usize) {
    assert!(count <= self.length);
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLByteBuffer::swap_remove would cause copy in overlapping regions"
      );

      unsafe {
        gl::CopyBufferSubData(
          gl::ARRAY_BUFFER,
          gl::ARRAY_BUFFER,
          self.length as GLintptr,
          i as GLintptr,
          count as GLsizeiptr,
        );
      }
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub unsafe fn update(&self, gl: &mut GLContext, idx: usize, vs: *const u8, count: usize) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  unsafe fn update_inner(
    &self,
    _gl: &mut GLContext,
    idx: usize,
    vs: *const u8,
    count: usize,
  ) {
    assert!(idx + count <= self.capacity);

    gl::BufferSubData(
      gl::ARRAY_BUFFER,
      idx as GLintptr,
      count as GLsizeiptr,
      mem::transmute(vs),
    );
  }
}

/// Fixed-size typed VRAM buffer, optimized for bulk inserts.
pub struct GLBuffer<'a, T> {
  pub byte_buffer: GLByteBuffer<'a>,
}

impl<'a, T> GLBuffer<'a, T> {
  pub fn new<'b:'a>(
    gl: &'a mut GLContext,
    capacity: usize,
  ) -> GLBuffer<'b, T> {
    GLBuffer {
      byte_buffer: GLByteBuffer::new(gl, capacity * mem::size_of::<T>()),
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) -> bool {
    unsafe {
      self.byte_buffer.push(
        gl,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len()
      )
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn update(&mut self, gl: &mut GLContext, idx: usize, vs: &[T]) {
    unsafe {
      self.byte_buffer.update(
        gl,
        mem::size_of::<T>() * idx,
        mem::transmute(vs.as_ptr()),
        mem::size_of::<T>() * vs.len(),
      );
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.byte_buffer.swap_remove(
      gl,
      mem::size_of::<T>() * idx,
      mem::size_of::<T>() * count,
    );
  }
}

#[derive(Debug)]
#[derive(Copy, Clone)]
pub enum DrawMode {
  Lines,
  Triangles,
  Points,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match *self {
      DrawMode::Lines     => gl::LINES,
      DrawMode::Triangles => gl::TRIANGLES,
      DrawMode::Points    => gl::POINTS,
    }
  }
}

#[derive(Debug)]
#[derive(Copy, Clone)]
pub enum GLType {
  Float,
  UInt,
  Int,
}

impl GLType {
  pub fn size(&self) -> u32 {
    num::cast(
      match *self {
        GLType::Float => mem::size_of::<GLfloat>(),
        GLType::UInt  => mem::size_of::<GLuint>(),
        GLType::Int   => mem::size_of::<GLint>(),
      })
    .unwrap()
  }

  pub fn gl_enum(&self) -> GLenum {
    match *self {
      GLType::Float => gl::FLOAT,
      GLType::UInt  => gl::UNSIGNED_INT,
      GLType::Int   => gl::INT,
    }
  }

  pub fn is_integral(&self) -> bool {
    match *self {
      GLType::Float => false,
      GLType::UInt  => true,
      GLType::Int   => true,
    }
  }
}

#[derive(Debug)]
/// Specifies how to pass data from OpenGL to the vertex shaders.
pub struct VertexAttribData<'a> {
  /// Cooresponds to the shader's `input variable`.
  pub name: &'a str,
  /// The size of this attribute, in the provided units.
  pub size: u32,
  pub unit: GLType,
}

pub struct ArrayHandle<'a> {
  pub gl_id: GLuint,
}

impl<'a> ArrayHandle<'a> {
  pub fn new<'b:'a>(_gl: &'a GLContext) -> ArrayHandle<'b> {
    let mut gl_id = 0;
    unsafe {
      gl::GenVertexArrays(1, &mut gl_id);
    }

    ArrayHandle {
      gl_id: gl_id,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ArrayHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteVertexArrays(1, &self.gl_id);
    }
  }
}

/// A fixed-capacity array of bytes passed to OpenGL.
pub struct GLArray<'a, T> {
  pub buffer: GLBuffer<'a, T>,
  pub handle: ArrayHandle<'a>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// length in `T`s.
  pub length: usize,
}

impl<'a, T> GLArray<'a, T> {
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub fn new<'b:'a>(
    gl: &'a mut GLContext,
    shader_program: &Shader<'b>,
    attribs: &[VertexAttribData],
    mode: DrawMode,
    buffer: GLBuffer<'b, T>,
  ) -> GLArray<'b, T> {
    let handle = ArrayHandle::new(gl);

    unsafe {
      gl::BindVertexArray(handle.gl_id);
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size * attrib.unit.size();
      }
      attrib_span
    };
    for attrib in attribs.iter() {
      let shader_attrib =
        glGetAttribLocation(
          shader_program.handle.gl_id,
          attrib.name
        );
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);
      let shader_attrib = shader_attrib as GLuint;

      unsafe {
        gl::EnableVertexAttribArray(shader_attrib);

        if attrib.unit.is_integral() {
          gl::VertexAttribIPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        } else {
          gl::VertexAttribPointer(
            shader_attrib,
            attrib.size as i32,
            attrib.unit.gl_enum(),
            gl::FALSE as GLboolean,
            attrib_span as i32,
            ptr::null().offset(offset),
          );
        }
      }
      offset += (attrib.size * attrib.unit.size()) as isize;
    }

    match unsafe { gl::GetError() } {
      gl::NO_ERROR => {},
      err => warn!("OpenGL error 0x{:x}", err),
    }

    assert_eq!(attrib_span as usize, mem::size_of::<T>());

    let length = buffer.byte_buffer.length / mem::size_of::<T>();

    GLArray {
      buffer: buffer,
      handle: handle,
      mode: mode.to_enum(),
      length: length,
    }
  }

  pub fn bind(&self, _: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.handle.gl_id);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.buffer.byte_buffer.handle.gl_id);
    }
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  /// The array doesn't need to be bound.
  pub fn push(&mut self, gl: &mut GLContext, vs: &[T]) -> bool {
    self.length += vs.len();
    let r = self.buffer.push(gl, vs);
    r
  }

  /// N.B. For performance reasons, this does NOT bind the buffer.
  /// It will do the wrong thing if `bind` has not been correctly called.
  /// The array doesn't need to be bound.
  pub fn swap_remove(&mut self, gl: &mut GLContext, idx: usize, count: usize) {
    self.buffer.swap_remove(gl, idx, count);
    self.length -= count;
  }

  /// Draws all the queued triangles to the screen.
  /// N.B. For performance reasons, this does NOT bind the array.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn draw(&self, gl: &mut GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  /// N.B. For performance reasons, this does NOT bind the array.
  /// It will do the wrong thing if `bind` has not been correctly called.
  pub fn draw_slice(&self, _gl: &mut GLContext, start: usize, len: usize) {
    assert!(start + len <= self.length);

    unsafe {
      gl::DrawArrays(self.mode, start as i32, len as i32);
    }
  }
}
<|endoftext|>


<commit_before>use buffer::{mod, Buffer};
use gl;
use GlObject;

/// A list of verices loaded in the graphics card's memory.
#[deriving(Show)]
pub struct VertexBuffer<T> {
    buffer: Buffer,
    bindings: VertexBindings,
}

/// Don't use this function outside of glium
#[doc(hidden)]
pub fn get_elements_size<T>(vb: &VertexBuffer<T>) -> uint {
    vb.buffer.get_elements_size()
}

/// Don't use this function outside of glium
#[doc(hidden)]
pub fn get_bindings<T>(vb: &VertexBuffer<T>) -> &VertexBindings {
    &vb.bindings
}

impl<T: VertexFormat + 'static + Send> VertexBuffer<T> {
    /// Builds a new vertex buffer.
    ///
    /// # Example
    ///
    /// ```
    /// # #![feature(phase)]
    /// # #[phase(plugin)]
    /// # extern crate glium_macros;
    /// # extern crate glium;
    /// # extern crate glutin;
    /// # use glium::DisplayBuild;
    /// # fn main() {
    /// #[vertex_format]
    /// struct Vertex {
    ///     position: [f32, ..3],
    ///     texcoords: [f32, ..2],
    /// }
    ///
    /// # let display: glium::Display = glutin::HeadlessRendererBuilder::new(1024, 768)
    /// #   .build_glium().unwrap();
    /// let vertex_buffer = glium::VertexBuffer::new(&display, vec![
    ///     Vertex { position: [0.0,  0.0, 0.0], texcoords: [0.0, 1.0] },
    ///     Vertex { position: [5.0, -3.0, 2.0], texcoords: [1.0, 0.0] },
    /// ]);
    /// # }
    /// ```
    ///
    pub fn new(display: &super::Display, data: Vec<T>) -> VertexBuffer<T> {
        let bindings = VertexFormat::build_bindings(None::<T>);

        VertexBuffer {
            buffer: Buffer::new::<buffer::ArrayBuffer, T>(display, data, gl::STATIC_DRAW),
            bindings: bindings,
        }
    }

    /// Builds a new vertex buffer.
    ///
    /// This function will create a buffer that has better performances when it is modified
    ///  frequently.
    pub fn new_dynamic(display: &super::Display, data: Vec<T>) -> VertexBuffer<T> {
        let bindings = VertexFormat::build_bindings(None::<T>);

        VertexBuffer {
            buffer: Buffer::new::<buffer::ArrayBuffer, T>(display, data, gl::DYNAMIC_DRAW),
            bindings: bindings,
        }
    }

    /// Maps the buffer to allow write access to it.
    ///
    /// **Warning**: using this function can slow things down a lot because the function
    /// waits for all the previous commands to be executed before returning.
    ///
    /// # Panic
    ///
    /// OpenGL ES doesn't support mapping buffers. Using this function will thus panic.
    /// If you want to be compatible with all platforms, it is preferable to disable the
    /// `gl_extensions` feature.
    ///
    /// # Features
    ///
    /// Only available if the `gl_extensions` feature is enabled.
    #[cfg(feature = "gl_extensions")]
    pub fn map<'a>(&'a mut self) -> Mapping<'a, T> {
        Mapping(self.buffer.map::<buffer::ArrayBuffer, T>())
    }

    /// Reads the content of the buffer.
    ///
    /// This function is usually better if are just doing one punctual read, while `map` is better
    /// if you want to have multiple small reads.
    ///
    /// # Panic
    ///
    /// OpenGL ES doesn't support reading buffers. Using this function will thus panic.
    /// If you want to be compatible with all platforms, it is preferable to disable the
    /// `gl_extensions` feature.
    ///
    /// # Features
    ///
    /// Only available if the `gl_extensions` feature is enabled.
    #[cfg(feature = "gl_extensions")]
    pub fn read(&self) -> Vec<T> {
        self.buffer.read::<buffer::ArrayBuffer, T>()
    }

    /// Reads the content of the buffer.
    ///
    /// This function is usually better if are just doing one punctual read, while `map` is better
    /// if you want to have multiple small reads.
    ///
    /// The offset and size are expressed in number of elements.
    ///
    /// ## Panic
    ///
    /// Panics if `offset` or `offset + size` are greated than the size of the buffer.
    ///
    /// OpenGL ES doesn't support reading buffers. Using this function will thus panic.
    /// If you want to be compatible with all platforms, it is preferable to disable the
    /// `gl_extensions` feature.
    ///
    /// # Features
    ///
    /// Only available if the `gl_extensions` feature is enabled.
    #[cfg(feature = "gl_extensions")]
    pub fn read_slice(&self, offset: uint, size: uint) -> Vec<T> {
        self.buffer.read_slice::<buffer::ArrayBuffer, T>(offset, size)
    }
}

#[unsafe_destructor]
impl<T> Drop for VertexBuffer<T> {
    fn drop(&mut self) {
        // removing VAOs which contain this vertex buffer
        let mut vaos = self.buffer.get_display().vertex_array_objects.lock();
        let to_delete = vaos.keys().filter(|&&(v, _, _)| v == self.buffer.get_id())
            .map(|k| k.clone()).collect::<Vec<_>>();
        for k in to_delete.into_iter() {
            vaos.remove(&k);
        }
    }
}

impl<T> GlObject for VertexBuffer<T> {
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// Describes the attribute of a vertex.
///
/// When you create a vertex buffer, you need to pass some sort of array of data. In order for
/// OpenGL to use this data, we must tell it some informations about each field of each
/// element. This structure describes one such field.
#[deriving(Show, Clone)]
pub struct VertexAttrib {
    /// The offset, in bytes, between the start of each vertex and the attribute.
    pub offset: uint,

    /// Type of the field.
    pub data_type: gl::types::GLenum,

    /// Number of invidual elements in the attribute.
    ///
    /// For example if `data_type` is a f32 and `elements_count` is 2, then you have a `vec2`.
    pub elements_count: u32,
}

/// Describes the layout of each vertex in a vertex buffer.
pub type VertexBindings = Vec<(String, VertexAttrib)>;

/// Trait for structures that represent a vertex.
pub trait VertexFormat: Copy {
    /// Builds the `VertexBindings` representing the layout of this element.
    fn build_bindings(Option<Self>) -> VertexBindings;
}

/// A mapping of a buffer.
///
/// # Features
///
/// Only available if the `gl_extensions` feature is enabled.
#[cfg(feature = "gl_extensions")]
pub struct Mapping<'a, T>(buffer::Mapping<'a, buffer::ArrayBuffer, T>);

#[cfg(feature = "gl_extensions")]
impl<'a, T> Deref<[T]> for Mapping<'a, T> {
    fn deref<'b>(&'b self) -> &'b [T] {
        self.0.deref()
    }
}

#[cfg(feature = "gl_extensions")]
impl<'a, T> DerefMut<[T]> for Mapping<'a, T> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut [T] {
        self.0.deref_mut()
    }
}
<commit_msg>Add VertexBuffer::new_raw<commit_after>use buffer::{mod, Buffer};
use gl;
use GlObject;

/// A list of verices loaded in the graphics card's memory.
#[deriving(Show)]
pub struct VertexBuffer<T> {
    buffer: Buffer,
    bindings: VertexBindings,
    elements_size: uint,
}

/// Don't use this function outside of glium
#[doc(hidden)]
pub fn get_elements_size<T>(vb: &VertexBuffer<T>) -> uint {
    vb.elements_size
}

/// Don't use this function outside of glium
#[doc(hidden)]
pub fn get_bindings<T>(vb: &VertexBuffer<T>) -> &VertexBindings {
    &vb.bindings
}

impl<T: VertexFormat + 'static + Send> VertexBuffer<T> {
    /// Builds a new vertex buffer.
    ///
    /// # Example
    ///
    /// ```
    /// # #![feature(phase)]
    /// # #[phase(plugin)]
    /// # extern crate glium_macros;
    /// # extern crate glium;
    /// # extern crate glutin;
    /// # use glium::DisplayBuild;
    /// # fn main() {
    /// #[vertex_format]
    /// struct Vertex {
    ///     position: [f32, ..3],
    ///     texcoords: [f32, ..2],
    /// }
    ///
    /// # let display: glium::Display = glutin::HeadlessRendererBuilder::new(1024, 768)
    /// #   .build_glium().unwrap();
    /// let vertex_buffer = glium::VertexBuffer::new(&display, vec![
    ///     Vertex { position: [0.0,  0.0, 0.0], texcoords: [0.0, 1.0] },
    ///     Vertex { position: [5.0, -3.0, 2.0], texcoords: [1.0, 0.0] },
    /// ]);
    /// # }
    /// ```
    ///
    pub fn new(display: &super::Display, data: Vec<T>) -> VertexBuffer<T> {
        let bindings = VertexFormat::build_bindings(None::<T>);

        let buffer = Buffer::new::<buffer::ArrayBuffer, T>(display, data, gl::STATIC_DRAW);
        let elements_size = buffer.get_elements_size();

        VertexBuffer {
            buffer: buffer,
            bindings: bindings,
            elements_size: elements_size,
        }
    }

    /// Builds a new vertex buffer.
    ///
    /// This function will create a buffer that has better performances when it is modified
    ///  frequently.
    pub fn new_dynamic(display: &super::Display, data: Vec<T>) -> VertexBuffer<T> {
        let bindings = VertexFormat::build_bindings(None::<T>);

        let buffer = Buffer::new::<buffer::ArrayBuffer, T>(display, data, gl::DYNAMIC_DRAW);
        let elements_size = buffer.get_elements_size();

        VertexBuffer {
            buffer: buffer,
            bindings: bindings,
            elements_size: elements_size,
        }
    }
}

impl<T: Send + Copy> VertexBuffer<T> {
    /// Builds a new vertex buffer from an undeterminate data type and bindings.
    ///
    /// # Example
    ///
    /// ```
    /// # #![feature(phase)]
    /// # #[phase(plugin)]
    /// # extern crate glium_macros;
    /// # extern crate glium;
    /// # extern crate glutin;
    /// # use glium::DisplayBuild;
    /// # fn main() {
    /// let bindings = vec![
    ///     ("position".to_string(), glium::vertex_buffer::VertexAttrib {
    ///         offset: 0,
    ///         data_type: 0x1406,  // GL_FLOAT
    ///         elements_count: 2,
    ///     }),
    ///     ("color".to_string(), glium::vertex_buffer::VertexAttrib {
    ///         offset: 2 * ::std::mem::size_of::<f32>(),
    ///         data_type: 0x1406,  // GL_FLOAT
    ///         elements_count: 1,
    ///     }),
    /// ];
    ///
    /// # let display: glium::Display = glutin::HeadlessRendererBuilder::new(1024, 768)
    /// #   .build_glium().unwrap();
    /// let data = vec![
    ///     1.0, -0.3, 409.0,
    ///     -0.4, 2.8, 715.0f32
    /// ];
    ///
    /// let vertex_buffer = unsafe {
    ///     glium::VertexBuffer::new_raw(&display, data, bindings, 3 * ::std::mem::size_of::<f32>())
    /// };
    /// # }
    /// ```
    ///
    #[experimental]
    pub unsafe fn new_raw(display: &super::Display, data: Vec<T>,
                          bindings: VertexBindings, elements_size: uint) -> VertexBuffer<T>
    {
        VertexBuffer {
            buffer: Buffer::new::<buffer::ArrayBuffer, T>(display, data, gl::STATIC_DRAW),
            bindings: bindings,
            elements_size: elements_size,
        }
    }

    /// Maps the buffer to allow write access to it.
    ///
    /// **Warning**: using this function can slow things down a lot because the function
    /// waits for all the previous commands to be executed before returning.
    ///
    /// # Panic
    ///
    /// OpenGL ES doesn't support mapping buffers. Using this function will thus panic.
    /// If you want to be compatible with all platforms, it is preferable to disable the
    /// `gl_extensions` feature.
    ///
    /// # Features
    ///
    /// Only available if the `gl_extensions` feature is enabled.
    #[cfg(feature = "gl_extensions")]
    pub fn map<'a>(&'a mut self) -> Mapping<'a, T> {
        Mapping(self.buffer.map::<buffer::ArrayBuffer, T>())
    }

    /// Reads the content of the buffer.
    ///
    /// This function is usually better if are just doing one punctual read, while `map` is better
    /// if you want to have multiple small reads.
    ///
    /// # Panic
    ///
    /// OpenGL ES doesn't support reading buffers. Using this function will thus panic.
    /// If you want to be compatible with all platforms, it is preferable to disable the
    /// `gl_extensions` feature.
    ///
    /// # Features
    ///
    /// Only available if the `gl_extensions` feature is enabled.
    #[cfg(feature = "gl_extensions")]
    pub fn read(&self) -> Vec<T> {
        self.buffer.read::<buffer::ArrayBuffer, T>()
    }

    /// Reads the content of the buffer.
    ///
    /// This function is usually better if are just doing one punctual read, while `map` is better
    /// if you want to have multiple small reads.
    ///
    /// The offset and size are expressed in number of elements.
    ///
    /// ## Panic
    ///
    /// Panics if `offset` or `offset + size` are greated than the size of the buffer.
    ///
    /// OpenGL ES doesn't support reading buffers. Using this function will thus panic.
    /// If you want to be compatible with all platforms, it is preferable to disable the
    /// `gl_extensions` feature.
    ///
    /// # Features
    ///
    /// Only available if the `gl_extensions` feature is enabled.
    #[cfg(feature = "gl_extensions")]
    pub fn read_slice(&self, offset: uint, size: uint) -> Vec<T> {
        self.buffer.read_slice::<buffer::ArrayBuffer, T>(offset, size)
    }
}

#[unsafe_destructor]
impl<T> Drop for VertexBuffer<T> {
    fn drop(&mut self) {
        // removing VAOs which contain this vertex buffer
        let mut vaos = self.buffer.get_display().vertex_array_objects.lock();
        let to_delete = vaos.keys().filter(|&&(v, _, _)| v == self.buffer.get_id())
            .map(|k| k.clone()).collect::<Vec<_>>();
        for k in to_delete.into_iter() {
            vaos.remove(&k);
        }
    }
}

impl<T> GlObject for VertexBuffer<T> {
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

/// Describes the attribute of a vertex.
///
/// When you create a vertex buffer, you need to pass some sort of array of data. In order for
/// OpenGL to use this data, we must tell it some informations about each field of each
/// element. This structure describes one such field.
#[deriving(Show, Clone)]
pub struct VertexAttrib {
    /// The offset, in bytes, between the start of each vertex and the attribute.
    pub offset: uint,

    /// Type of the field.
    pub data_type: gl::types::GLenum,

    /// Number of invidual elements in the attribute.
    ///
    /// For example if `data_type` is a f32 and `elements_count` is 2, then you have a `vec2`.
    pub elements_count: u32,
}

/// Describes the layout of each vertex in a vertex buffer.
pub type VertexBindings = Vec<(String, VertexAttrib)>;

/// Trait for structures that represent a vertex.
pub trait VertexFormat: Copy {
    /// Builds the `VertexBindings` representing the layout of this element.
    fn build_bindings(Option<Self>) -> VertexBindings;
}

/// A mapping of a buffer.
///
/// # Features
///
/// Only available if the `gl_extensions` feature is enabled.
#[cfg(feature = "gl_extensions")]
pub struct Mapping<'a, T>(buffer::Mapping<'a, buffer::ArrayBuffer, T>);

#[cfg(feature = "gl_extensions")]
impl<'a, T> Deref<[T]> for Mapping<'a, T> {
    fn deref<'b>(&'b self) -> &'b [T] {
        self.0.deref()
    }
}

#[cfg(feature = "gl_extensions")]
impl<'a, T> DerefMut<[T]> for Mapping<'a, T> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut [T] {
        self.0.deref_mut()
    }
}
<|endoftext|>