bigtable 0.4.0

Lib for interfacing with Google BigTable Data API
Documentation
use support::Table;
use error::BTErr;
use curl::easy::{Easy, List};
use method::{BigTable, ReadRows};
use std;
use goauth::auth::Token;
use serde_json;
use serde_json::Value;
use std::io::Read;
use protobuf_json;

pub struct BTRequest<'a, T: BigTable> {
    pub base: Option<&'a str>,
    pub table: Table,
    pub method: T
}

impl<'a> Default for BTRequest<'a, ReadRows> {
    fn default() -> Self {
        BTRequest {
            base: None,
            table: Default::default(),
            method: ReadRows::new()
        }
    }
}

impl<'a, T: BigTable> BTRequest<'a, T> {
    pub fn form_url(&self) -> Result<String, BTErr> {
        let base = match self.base {
            Some(x) => x,
            None => "https://bigtable.googleapis.com/v2"
        };
        Ok(String::from(format!("{}/projects/{}/instances/{}/tables/{}{}",
                             base,
                             self.table.instance.project.name,
                             self.table.instance.name,
                             self.table.name,
                             self.method.url_method()
                    )
        ))
    }

    pub fn execute(&self, token: &Token) -> Result<Value, BTErr>{
        let mut response_data: Vec<u8> = Vec::new();
        let mut easy = Easy::new();

        let payload = protobuf_json::proto_to_json(self.method.payload());
        let s_payload = serde_json::to_string(&payload)?;
        let mut b_payload = s_payload.as_bytes();

        easy.url(&self.form_url()?)?;

        if self.method.is_post() {
            easy.post(true)?;
            easy.post_field_size(b_payload.len() as u64)?;
        }

        easy.http_headers(gen_headers(token)?)?;

        {
            let mut transfer = easy.transfer();
            transfer.read_function(|buf| {
                Ok(b_payload.read(buf).unwrap_or(0))
            })?;
            transfer.write_function(|response| {
                response_data.extend_from_slice(response);
                Ok(response.len())
            })?;
            transfer.header_function(|header| {
                debug!("header: {}", std::str::from_utf8(header).unwrap());
                true
            })?;
            transfer.perform()?;
        }

        let response_str = std::str::from_utf8(&response_data)?;

        debug!("Bytes transfered: {}", response_data.len());
        debug!("Response: {}", response_str);

        Ok(serde_json::from_str(response_str)?)
    }
}

fn gen_headers(token: &Token) -> Result<List, BTErr> {
    let mut list = List::new();
    let auth = format!("Authorization: {} {}", token.token_type(), token.access_token());
    list.append(&auth)?;
    list.append("Content-Type: application/json")?;
    Ok(list)
}