<commit_before>#![allow(dead_code)]

use std::sync::{Once, ONCE_INIT};
use std::{mem, raw};
use std::collections::HashMap;
use libc::{c_int,c_long,c_double,size_t};
use super::{consts,err,info,opt};
use super::err::ErrCode;
use http::body::Body;
use http::{header,Response};

use curl_ffi as ffi;

pub type ProgressCb<'a> = FnMut(usize, usize, usize, usize) + 'a;

pub struct Easy {
    curl: *mut ffi::CURL
}

impl Easy {
    pub fn new() -> Easy {
        // Ensure that curl is globally initialized
        global_init();

        let handle = unsafe {
            let p = ffi::curl_easy_init();
            ffi::curl_easy_setopt(p, opt::NOPROGRESS, 0);
            p
        };

        Easy { curl: handle }
    }

    #[inline]
    pub fn setopt<T: opt::OptVal>(&mut self, option: opt::Opt, val: T) -> Result<(), err::ErrCode> {
        // TODO: Prevent setting callback related options
        let mut res = err::ErrCode(err::OK);

        unsafe {
            val.with_c_repr(|repr| {
                res = err::ErrCode(ffi::curl_easy_setopt(self.curl, option, repr));
            })
        }

        if res.is_success() { Ok(()) } else { Err(res) }
    }

    pub fn perform(&mut self,
                   body: Option<&mut Body>,
                   progress: Option<Box<ProgressCb>>)
                   -> Result<Response, err::ErrCode> {
        let mut builder = ResponseBuilder::new();

        unsafe {
            let resp_p: usize = mem::transmute(&builder);
            let body_p: usize = match body {
                Some(b) => mem::transmute(b),
                None => 0
            };

            let progress_p: usize = match progress.as_ref() {
                Some(cb) => mem::transmute(cb),
                None => 0
            };

            // Set callback options
            ffi::curl_easy_setopt(self.curl, opt::READFUNCTION, curl_read_fn);
            ffi::curl_easy_setopt(self.curl, opt::READDATA, body_p);

            ffi::curl_easy_setopt(self.curl, opt::WRITEFUNCTION, curl_write_fn);
            ffi::curl_easy_setopt(self.curl, opt::WRITEDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::HEADERFUNCTION, curl_header_fn);
            ffi::curl_easy_setopt(self.curl, opt::HEADERDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::PROGRESSFUNCTION, curl_progress_fn);
            ffi::curl_easy_setopt(self.curl, opt::PROGRESSDATA, progress_p);
        }

        let err = err::ErrCode(unsafe { ffi::curl_easy_perform(self.curl) });

        // If the request failed, abort here
        if !err.is_success() {
            return Err(err);
        }

        // Try to get the response code
        builder.code = try!(self.get_response_code());

        Ok(builder.build())
    }

    pub fn get_response_code(&self) -> Result<u32, err::ErrCode> {
        Ok(try!(self.get_info_long(info::RESPONSE_CODE)) as u32)
    }

    pub fn get_total_time(&self) -> Result<usize, err::ErrCode> {
        Ok(try!(self.get_info_long(info::TOTAL_TIME)) as usize)
    }

    fn get_info_long(&self, key: info::Key) -> Result<c_long, err::ErrCode> {
        let v: c_long = 0;
        let res = err::ErrCode(unsafe {
            ffi::curl_easy_getinfo(self.curl as *const _, key, &v)
        });

        if !res.is_success() {
            return Err(res);
        }

        Ok(v)
    }
}

#[inline]
fn global_init() {
    // Schedule curl to be cleaned up after we're done with this whole process
    static mut INIT: Once = ONCE_INIT;
    unsafe {
        INIT.call_once(|| ::std::rt::at_exit(|| ffi::curl_global_cleanup()))
    }
}

impl Drop for Easy {
    fn drop(&mut self) {
        unsafe { ffi::curl_easy_cleanup(self.curl) }
    }
}

/*
 *
 * TODO: Move this into handle
 *
 */

struct ResponseBuilder {
    code: u32,
    hdrs: HashMap<String,Vec<String>>,
    body: Vec<u8>
}

impl ResponseBuilder {
    fn new() -> ResponseBuilder {
        ResponseBuilder {
            code: 0,
            hdrs: HashMap::new(),
            body: Vec::new()
        }
    }

    fn add_header(&mut self, name: &str, val: &str) {<commit_msg>Use atexit instead of rt::at_exit<commit_after>#![allow(dead_code)]

use std::sync::{Once, ONCE_INIT};
use std::{mem, raw};
use std::collections::HashMap;
use libc::{self, c_int, c_long, c_double, size_t};
use super::{consts, err, info, opt};
use super::err::ErrCode;
use http::body::Body;
use http::{header, Response};

use curl_ffi as ffi;

pub type ProgressCb<'a> = FnMut(usize, usize, usize, usize) + 'a;

pub struct Easy {
    curl: *mut ffi::CURL
}

impl Easy {
    pub fn new() -> Easy {
        // Ensure that curl is globally initialized
        global_init();

        let handle = unsafe {
            let p = ffi::curl_easy_init();
            ffi::curl_easy_setopt(p, opt::NOPROGRESS, 0);
            p
        };

        Easy { curl: handle }
    }

    #[inline]
    pub fn setopt<T: opt::OptVal>(&mut self, option: opt::Opt, val: T) -> Result<(), err::ErrCode> {
        // TODO: Prevent setting callback related options
        let mut res = err::ErrCode(err::OK);

        unsafe {
            val.with_c_repr(|repr| {
                res = err::ErrCode(ffi::curl_easy_setopt(self.curl, option, repr));
            })
        }

        if res.is_success() { Ok(()) } else { Err(res) }
    }

    pub fn perform(&mut self,
                   body: Option<&mut Body>,
                   progress: Option<Box<ProgressCb>>)
                   -> Result<Response, err::ErrCode> {
        let mut builder = ResponseBuilder::new();

        unsafe {
            let resp_p: usize = mem::transmute(&builder);
            let body_p: usize = match body {
                Some(b) => mem::transmute(b),
                None => 0
            };

            let progress_p: usize = match progress.as_ref() {
                Some(cb) => mem::transmute(cb),
                None => 0
            };

            // Set callback options
            ffi::curl_easy_setopt(self.curl, opt::READFUNCTION, curl_read_fn);
            ffi::curl_easy_setopt(self.curl, opt::READDATA, body_p);

            ffi::curl_easy_setopt(self.curl, opt::WRITEFUNCTION, curl_write_fn);
            ffi::curl_easy_setopt(self.curl, opt::WRITEDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::HEADERFUNCTION, curl_header_fn);
            ffi::curl_easy_setopt(self.curl, opt::HEADERDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::PROGRESSFUNCTION, curl_progress_fn);
            ffi::curl_easy_setopt(self.curl, opt::PROGRESSDATA, progress_p);
        }

        let err = err::ErrCode(unsafe { ffi::curl_easy_perform(self.curl) });

        // If the request failed, abort here
        if !err.is_success() {
            return Err(err);
        }

        // Try to get the response code
        builder.code = try!(self.get_response_code());

        Ok(builder.build())
    }

    pub fn get_response_code(&self) -> Result<u32, err::ErrCode> {
        Ok(try!(self.get_info_long(info::RESPONSE_CODE)) as u32)
    }

    pub fn get_total_time(&self) -> Result<usize, err::ErrCode> {
        Ok(try!(self.get_info_long(info::TOTAL_TIME)) as usize)
    }

    fn get_info_long(&self, key: info::Key) -> Result<c_long, err::ErrCode> {
        let v: c_long = 0;
        let res = err::ErrCode(unsafe {
            ffi::curl_easy_getinfo(self.curl as *const _, key, &v)
        });

        if !res.is_success() {
            return Err(res);
        }

        Ok(v)
    }
}

#[inline]
fn global_init() {
    // Schedule curl to be cleaned up after we're done with this whole process
    static INIT: Once = ONCE_INIT;
    INIT.call_once(|| unsafe {
        assert_eq!(libc::atexit(cleanup), 0);
    });

    extern fn cleanup() {
        unsafe { ffi::curl_global_cleanup() }
    }
}

impl Drop for Easy {
    fn drop(&mut self) {
        unsafe { ffi::curl_easy_cleanup(self.curl) }
    }
}

/*
 *
 * TODO: Move this into handle
 *
 */

struct ResponseBuilder {
    code: u32,
    hdrs: HashMap<String,Vec<String>>,
    body: Vec<u8>
}

impl ResponseBuilder {
    fn new() -> ResponseBuilder {
        ResponseBuilder {
            code: 0,
            hdrs: HashMap::new(),
            body: Vec::new()
        }
    }

    fn add_header(&mut self, name: &str, val: &str) {
{'fraction_non_alphanumeric': 0.1405138101555904, 'fraction_numerical': 0.003015317814497648, 'mean_word_length': 2.234009360374415, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5063109', 'n_tokens_mistral': 2865, 'n_tokens_neox': 2716, 'n_words': 594}