<commit_before>use builder;
use ffi;
use util;
use libc;
use std::{cmp, fmt};

#[derive(Copy,Clone)]
/// A Ruby value.
pub struct Value(pub ffi::VALUE);

impl Value
{
    /// Gets `nil`.
    pub fn nil() -> Self {
        Self::from(ffi::Qnil)
    }

    /// Gets a boolean value.
    pub fn boolean(b: bool) -> Self {
        if b { Value::boolean_true() } else { Value::boolean_false() }
    }

    /// Gets the boolean `true` value.
    pub fn boolean_true() -> Self {
        Self::from(ffi::Qtrue)
    }

    /// Gets the boolean `false` value.
    pub fn boolean_false() -> Self {
        Self::from(ffi::Qfalse)
    }

    /// Creates a new symbol.
    pub fn symbol<S>(name: S) -> Self where S: AsRef<str> {
        Self::from(unsafe { ffi::rb_id2sym(Self::intern(name.as_ref())) })
    }

    /// Creates a new String.
    pub fn string<S>(s: S) -> Self where S: AsRef<String> {
        Self::from(unsafe { ffi::rb_id2str(Self::intern(s.as_ref())) })
    }

    /// Creates a new `Integer`.
    pub fn integer(v: i64) -> Self {
        Self::from(ffi::INT2FIX(v as _))
    }

    /// Creates a new `Float`.
    pub fn float(v: f64) -> Self {
        Self::from(unsafe { ffi::rb_float_new(v as libc::c_double) })
    }

    /// Converts the value into a symbol.
    pub fn to_sym(&self) -> Value {
        Self::from(unsafe { ffi::rb_to_symbol(self.0) })
    }

    /// Converts the value to a 64-bit signed integer.
    pub fn to_i64(&self) -> i64 {
        unsafe { ffi::rb_num2long(self.0) as i64 }
    }

    /// Converts the value to a 64-bit unsigned integer.
    pub fn to_u64(&self) -> u64 {
        unsafe { ffi::rb_num2ulong(self.0) as u64 }
    }

    /// Converts the value into a 64-bit float.
    pub fn to_f64(&self) -> f64 {
        unsafe { ffi::rb_num2dbl(self.0) as f64 }
    }

    /// Gets the class.
    pub fn class(&self) -> Value {
        Self::from(unsafe { ffi::rb_class_of(self.0) })
    }

    /// Creates a nested class.
    pub fn nested_class<S>(self, name: S) -> builder::Class
        where S: Into<String> {
        builder::Class::new_under(name, Some(self))
    }

    /// Creates a nested module.
    pub fn nested_module<S>(self, name: S) -> builder::Module
        where S: Into<String> {
        builder::Module::new_under(name, Some(self))
    }

    /// The value of `Object#to_s`.
    pub fn display_string(&self) -> String {
        self.call_no_args("to_s").as_string().expect("Object#to_s did not return a String")
    }

    /// The value of `Object#inspect`.
    pub fn inspect_string(&self) -> String {
        self.call_no_args("inspect").as_string().expect("Object#inspect did not return a String")
    }

    /// Gets the name of the class of the object.
    pub fn class_name(&self) -> String {
        unsafe { util::string(ffi::rb_obj_classname(self.0)) }
    }

    /// Checks if the value is `nil`.
    pub fn is_nil(&self)   -> bool { self.0 == ffi::Qnil }
    /// Checks if the value is `true`.
    pub fn is_true(&self)  -> bool { self.0 == ffi::Qtrue }
    /// Checks if the value is `false.`
    pub fn is_false(&self) -> bool { self.0 == ffi::Qfalse }

    /// Checks if the value is a `String` type.
    pub fn is_string(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_STRING) }
    /// Checks if the value is a regex.
    pub fn is_regex(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_REGEXP) }
    /// Checks if the value is an `Integer` type.
    pub fn is_integer(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_FIXNUM) }
    /// Checks if the value is a complex number.
    pub fn is_complex_number(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_COMPLEX) }
    /// Checks if the value is a rational number.
    pub fn is_rational(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_RATIONAL) }
    /// Checks if the value is a symbol.
    pub fn is_symbol(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_SYMBOL) }
    /// Checks if the value is a float.
    pub fn is_float(&self)  -> bool { ffi::TYPE_P(self.0, ffi::T_FLOAT) }
    /// Checks if the value is an array.
    pub fn is_array(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_ARRAY) }
    /// Checks if the value is a hash.
    pub fn is_hash(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_HASH) }
    /// Checks if the value is an object.
    pub fn is_object(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_OBJECT) }
    /// Checks if the value is a class.
    pub fn is_class(&self)  -> bool { ffi::TYPE_P(self.0, ffi::T_CLASS) }
    /// Checks if the value is a `Struct`.
    pub fn is_struct(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_STRUCT) }
    /// Checks if the value is a module.
    pub fn is_module(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_MODULE) }

    /// Ruby's version of '=='
    pub fn is_equal_to(&self, other: Self) -> Self {
        Self::from(unsafe { ffi::rb_equal(self.0, other.0) })
    }

    /// Converts a Ruby `String` into a Rust `String`.
    /// Returns `None` if the value is not a Ruby `String`.
    pub fn as_string(&self) -> Option<String> {
        if self.is_string() {
            let c_str = unsafe { ffi::rb_string_value_cstr(&self.0 as *const _) };
            Some(util::string(c_str))
        } else {
            None
        }
    }

    /// Calls a method with no args.
    pub fn call_no_args(&self, method_name: &str) -> Self {
        Self::from(unsafe { ffi::rb_funcall(self.0, Self::intern(method_name), 0) })
    }

    /// Sends a message to the value.
    pub fn send(&self, method_name: &str, args: &[Self]) -> Self {
        Self::from(unsafe {
            ffi::rb_funcallv(
                self.0,
                Self::intern(method_name),
                args.len() as libc::c_int,
                args.as_ptr() as *const _,
            )
        })
    }

    /// Gets the value of an instance variable by name.
    /// Returns `nil` if it doesn't exist.
    pub fn get_ivar(&self, name: &str) -> Self {
        Self::from(unsafe { ffi::rb_iv_get(self.0, util::c_string(name).as_ptr()) })
    }

    /// Sets the value of an instance variable (or creates a new one).
    pub fn set_ivar(&self, name: &str, value: Self) -> Self {
        Self::from(unsafe { ffi::rb_iv_set(self.0, util::c_string(name).as_ptr(), value.0) })
    }

    fn intern(s: &str) -> ffi::ID {
        unsafe { ffi::rb_intern(util::c_string(s).as_ptr()) }
    }
}

impl cmp::PartialEq for Value
{
    fn eq(&self, rhs: &Value) -> bool {
        self.is_equal_to(*rhs).is_true()
    }
}

impl cmp::Eq for Value { }

impl fmt::Display for Value
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.display_string().fmt(fmt)
    }
}

impl fmt::Debug for Value
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.display_string().fmt(fmt)
    }
}

impl From<ffi::VALUE> for Value
{
    fn from(value: ffi::VALUE) -> Value {
        Value(value)
    }
}

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

    #[test]
    fn can_create_booleans() {
        assert!(Value::boolean_true().is_true());
        assert!(Value::boolean_false().is_false());
        assert!(Value::boolean(true).is_true());
        assert!(Value::boolean(false).is_false());
    }

    #[test]
    fn can_create_integers() {
        assert_eq!(50, Value::integer(50).to_u64());
        assert_eq!(0xdeadbeef, Value::integer(0xdeadbeef).to_u64());
    }
}

<commit_msg>Fix a typo<commit_after>use builder;
use ffi;
use util;
use libc;
use std::{cmp, fmt};

#[derive(Copy,Clone)]
/// A Ruby value.
pub struct Value(pub ffi::VALUE);

impl Value
{
    /// Gets `nil`.
    pub fn nil() -> Self {
        Self::from(ffi::Qnil)
    }

    /// Gets a boolean value.
    pub fn boolean(b: bool) -> Self {
        if b { Value::boolean_true() } else { Value::boolean_false() }
    }

    /// Gets the boolean `true` value.
    pub fn boolean_true() -> Self {
        Self::from(ffi::Qtrue)
    }

    /// Gets the boolean `false` value.
    pub fn boolean_false() -> Self {
        Self::from(ffi::Qfalse)
    }

    /// Creates a new symbol.
    pub fn symbol<S>(name: S) -> Self where S: AsRef<str> {
        Self::from(unsafe { ffi::rb_id2sym(Self::intern(name.as_ref())) })
    }

    /// Creates a new String.
    pub fn string<S>(s: S) -> Self where S: AsRef<str> {
        Self::from(unsafe { ffi::rb_id2str(Self::intern(s.as_ref())) })
    }

    /// Creates a new `Integer`.
    pub fn integer(v: i64) -> Self {
        Self::from(ffi::INT2FIX(v as _))
    }

    /// Creates a new `Float`.
    pub fn float(v: f64) -> Self {
        Self::from(unsafe { ffi::rb_float_new(v as libc::c_double) })
    }

    /// Converts the value into a symbol.
    pub fn to_sym(&self) -> Value {
        Self::from(unsafe { ffi::rb_to_symbol(self.0) })
    }

    /// Converts the value to a 64-bit signed integer.
    pub fn to_i64(&self) -> i64 {
        unsafe { ffi::rb_num2long(self.0) as i64 }
    }

    /// Converts the value to a 64-bit unsigned integer.
    pub fn to_u64(&self) -> u64 {
        unsafe { ffi::rb_num2ulong(self.0) as u64 }
    }

    /// Converts the value into a 64-bit float.
    pub fn to_f64(&self) -> f64 {
        unsafe { ffi::rb_num2dbl(self.0) as f64 }
    }

    /// Gets the class.
    pub fn class(&self) -> Value {
        Self::from(unsafe { ffi::rb_class_of(self.0) })
    }

    /// Creates a nested class.
    pub fn nested_class<S>(self, name: S) -> builder::Class
        where S: Into<String> {
        builder::Class::new_under(name, Some(self))
    }

    /// Creates a nested module.
    pub fn nested_module<S>(self, name: S) -> builder::Module
        where S: Into<String> {
        builder::Module::new_under(name, Some(self))
    }

    /// The value of `Object#to_s`.
    pub fn display_string(&self) -> String {
        self.call_no_args("to_s").as_string().expect("Object#to_s did not return a String")
    }

    /// The value of `Object#inspect`.
    pub fn inspect_string(&self) -> String {
        self.call_no_args("inspect").as_string().expect("Object#inspect did not return a String")
    }

    /// Gets the name of the class of the object.
    pub fn class_name(&self) -> String {
        unsafe { util::string(ffi::rb_obj_classname(self.0)) }
    }

    /// Checks if the value is `nil`.
    pub fn is_nil(&self)   -> bool { self.0 == ffi::Qnil }
    /// Checks if the value is `true`.
    pub fn is_true(&self)  -> bool { self.0 == ffi::Qtrue }
    /// Checks if the value is `false.`
    pub fn is_false(&self) -> bool { self.0 == ffi::Qfalse }

    /// Checks if the value is a `String` type.
    pub fn is_string(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_STRING) }
    /// Checks if the value is a regex.
    pub fn is_regex(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_REGEXP) }
    /// Checks if the value is an `Integer` type.
    pub fn is_integer(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_FIXNUM) }
    /// Checks if the value is a complex number.
    pub fn is_complex_number(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_COMPLEX) }
    /// Checks if the value is a rational number.
    pub fn is_rational(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_RATIONAL) }
    /// Checks if the value is a symbol.
    pub fn is_symbol(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_SYMBOL) }
    /// Checks if the value is a float.
    pub fn is_float(&self)  -> bool { ffi::TYPE_P(self.0, ffi::T_FLOAT) }
    /// Checks if the value is an array.
    pub fn is_array(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_ARRAY) }
    /// Checks if the value is a hash.
    pub fn is_hash(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_HASH) }
    /// Checks if the value is an object.
    pub fn is_object(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_OBJECT) }
    /// Checks if the value is a class.
    pub fn is_class(&self)  -> bool { ffi::TYPE_P(self.0, ffi::T_CLASS) }
    /// Checks if the value is a `Struct`.
    pub fn is_struct(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_STRUCT) }
    /// Checks if the value is a module.
    pub fn is_module(&self) -> bool { ffi::TYPE_P(self.0, ffi::T_MODULE) }

    /// Ruby's version of '=='
    pub fn is_equal_to(&self, other: Self) -> Self {
        Self::from(unsafe { ffi::rb_equal(self.0, other.0) })
    }

    /// Converts a Ruby `String` into a Rust `String`.
    /// Returns `None` if the value is not a Ruby `String`.
    pub fn as_string(&self) -> Option<String> {
        if self.is_string() {
            let c_str = unsafe { ffi::rb_string_value_cstr(&self.0 as *const _) };
            Some(util::string(c_str))
        } else {
            None
        }
    }

    /// Calls a method with no args.
    pub fn call_no_args(&self, method_name: &str) -> Self {
        Self::from(unsafe { ffi::rb_funcall(self.0, Self::intern(method_name), 0) })
    }

    /// Sends a message to the value.
    pub fn send(&self, method_name: &str, args: &[Self]) -> Self {
        Self::from(unsafe {
            ffi::rb_funcallv(
                self.0,
                Self::intern(method_name),
                args.len() as libc::c_int,
                args.as_ptr() as *const _,
            )
        })
    }

    /// Gets the value of an instance variable by name.
    /// Returns `nil` if it doesn't exist.
    pub fn get_ivar(&self, name: &str) -> Self {
        Self::from(unsafe { ffi::rb_iv_get(self.0, util::c_string(name).as_ptr()) })
    }

    /// Sets the value of an instance variable (or creates a new one).
    pub fn set_ivar(&self, name: &str, value: Self) -> Self {
        Self::from(unsafe { ffi::rb_iv_set(self.0, util::c_string(name).as_ptr(), value.0) })
    }

    fn intern(s: &str) -> ffi::ID {
        unsafe { ffi::rb_intern(util::c_string(s).as_ptr()) }
    }
}

impl cmp::PartialEq for Value
{
    fn eq(&self, rhs: &Value) -> bool {
        self.is_equal_to(*rhs).is_true()
    }
}

impl cmp::Eq for Value { }

impl fmt::Display for Value
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.display_string().fmt(fmt)
    }
}

impl fmt::Debug for Value
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.display_string().fmt(fmt)
    }
}

impl From<ffi::VALUE> for Value
{
    fn from(value: ffi::VALUE) -> Value {
        Value(value)
    }
}

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

    #[test]
    fn can_create_booleans() {
        assert!(Value::boolean_true().is_true());
        assert!(Value::boolean_false().is_false());
        assert!(Value::boolean(true).is_true());
        assert!(Value::boolean(false).is_false());
    }

    #[test]
    fn can_create_integers() {
        assert_eq!(50, Value::integer(50).to_u64());
        assert_eq!(0xdeadbeef, Value::integer(0xdeadbeef).to_u64());
    }
}

<|endoftext|>


<commit_before>extern crate time;
extern crate serde;
extern crate serde_json;
extern crate mongodb;
extern crate bson;

use super::worker_pool;
use super::cove;

use std::thread;
use std::sync::{Arc, Mutex};
use self::serde_json::Value;
use self::mongodb::db::{Database, ThreadedDatabase};
use self::mongodb::coll::options::FindOneAndUpdateOptions;
use self::bson::Document;
use self::bson::Bson;

///
/// Holds a program object
///
pub struct Program {
    pub data: String,
    pub program_id: u64
}

///
/// Does the actual ingestion
///
pub fn ingest(first_time: bool, db: &Database, num_workers: usize) {
    let total_programs = get_total_programs();
    let mut updated_date = Arc::new(String::from(""));

    if !first_time {
        let current_time = time::now_utc();
        updated_date = Arc::new(format!("{}-{}-{}", 1900 + current_time.tm_year, current_time.tm_mon, current_time.tm_mday));
    }

    let mut worker_pool = worker_pool::WorkerPool::new(num_workers);

    for i in (0..total_programs).step_by(200) {
        let shared_updated_date = updated_date.clone();
        let shared_db = db.clone();

        worker_pool.add_worker(thread::spawn(move || {
            let programs = get_programs(i);
            let mut worker_pool = worker_pool::WorkerPool::new(num_workers);
            let coll = shared_db.collection("programs");

            for program in programs {
                let video_ids = Arc::new(Mutex::new(vec![]));
                let program_id = program.program_id;

                let filter = doc! {
                    "program_id" => program_id
                };

                // Can't use doc! macro because it escapes the JSON data.
                let mut update = Document::new();
                update.insert("program_id", program_id);
                update.insert("data", Bson::JavaScriptCode(program.data.clone()));

                let mut options = FindOneAndUpdateOptions::new();
                options.upsert = true;
                coll.find_one_and_replace(filter, update, Some(options)).expect("Can't insert program into database!");

                let shared_updated_date = shared_updated_date.clone();
                let shared_db = shared_db.clone();

                // We need this final shared DB because shared_db is moved into the thread so it can't be used to delete
                // at the end.
                let final_shared_db = shared_db.clone();

                let shared_video_ids = video_ids.clone();

                worker_pool.add_worker(thread::spawn(move || {
                    let total_videos = get_video_count_for_program(&shared_updated_date, &program);
                    let mut worker_pool = worker_pool::WorkerPool::new(num_workers);
                    let program = Arc::new(program);
                    let shared_video_ids = shared_video_ids.clone();

                    for j in (0..total_videos).step_by(200) {
                        let shared_program = program.clone();
                        let shared_updated_date = shared_updated_date.clone();
                        let shared_db = shared_db.clone();
                        let shared_video_ids = shared_video_ids.clone();

                        worker_pool.add_worker(thread::spawn(move || {
                            get_videos(&shared_updated_date, j, &shared_program, &shared_db, &shared_video_ids);
                        }));
                    }

                    worker_pool.wait_for_children();
                }));

                let video_ids_str = format!("[{}]", video_ids.lock().unwrap().join(","));
                let filter = doc! {
                    "tp_media_object_id" => video_ids_str,
                    "cond" => "$ne"
                };

                let video_coll = final_shared_db.collection("videos");
                video_coll.delete_many(filter, None).unwrap();
            }

            worker_pool.wait_for_children();
        }));
    }

    worker_pool.wait_for_children();
}

///
/// Gets the total programs to break them up
///
fn get_total_programs() -> u64 {
    cove::video_api("programs", vec![]).as_object().unwrap().get("count").unwrap().as_u64().unwrap()
}

///
/// Gets all the shows from COVE
///
fn get_programs(start_index: u64) -> Vec<Program> {
    let cove_data = cove::video_api("programs", vec![["limit_start", start_index.to_string().as_str()]]);
    let programs: &Vec<Value> = cove_data.as_object().unwrap().get("results").unwrap().as_array().unwrap();
    let mut programs_data = vec![];

    for program in programs {
        let program_uri = program.as_object().unwrap().get("resource_uri").unwrap().as_str().unwrap();
        let program_id: u64 = program_uri.split("/").nth(4).unwrap().parse().unwrap();

        programs_data.push(Program {data: program.to_string(), program_id: program_id});
    }

    programs_data
}

///
/// Gets the total videos for a program so they can be chunked
///
fn get_video_count_for_program<'a>(updated_date: &Arc<String>, program: &Program) -> u64 {
    let program_id = program.program_id.to_string();
    let mut params = vec![
        ["filter_program", program_id.as_str()],
        ["exclude_type", "Other"]
    ];

    if updated_date.as_str() != "" {
        params.push(["filter_record_last_updated_datetime__gt", updated_date.as_str()]);
    }

    cove::video_api("videos", params).as_object().unwrap().get("count").unwrap().as_u64().unwrap()
}

///
/// Gets all videos from COVE for a program, 200 at a time
///
fn get_videos(updated_date: &Arc<String>, start_index: u64, program: &Arc<Program>, db: &Database, video_ids: &Arc<Mutex<Vec<String>>>) {
    let program_id = program.program_id.to_string();
    let str_start_index = start_index.to_string();
    let mut params = vec![
        ["filter_program", program_id.as_str()],
        ["limit_start", str_start_index.as_str()],
        ["exclude_type", "Other"]
    ];

    if updated_date.as_str() != "" {
        params.push(["filter_record_last_updated_datetime__gt", updated_date.as_str()]);
    }

    let cove_data = cove::video_api("videos", params);
    let videos:&Vec<Value> = cove_data.as_object().unwrap().get("results").unwrap().as_array().unwrap();
    let coll = db.collection("videos");
    let mut page_video_ids = vec![];

    for video in videos {

        //
        // Not everything has a tp_media_object_id.  Ignore the ones that don't.
        //
        match video.as_object().unwrap().get("tp_media_object_id").unwrap().as_u64() {
            Some(tp_media_object_id) => {
                page_video_ids.push(tp_media_object_id.to_string());

                let filter = doc! {
                    "tp_media_object_id" => tp_media_object_id
                };

                // Can't use doc! macro because it escapes the data.
                let mut update = Document::new();
                update.insert("tp_media_object_id", tp_media_object_id);
                update.insert("program_id", program.program_id);
                update.insert("data", Bson::JavaScriptCode(video.to_string()));

                let mut options = FindOneAndUpdateOptions::new();
                options.upsert = true;

                coll.find_one_and_replace(filter, update, Some(options)).expect("Can't insert video into database!");
            },
            None => {}
        };
    }

    let shared_video_ids = video_ids.clone();
    let mut locked_video_ids = shared_video_ids.lock().unwrap();
    locked_video_ids.extend(page_video_ids);
}<commit_msg>Fixed removal of videos condition<commit_after>extern crate time;
extern crate serde;
extern crate serde_json;
extern crate mongodb;
extern crate bson;

use super::worker_pool;
use super::cove;

use std::thread;
use std::sync::{Arc, Mutex};
use self::serde_json::Value;
use self::mongodb::db::{Database, ThreadedDatabase};
use self::mongodb::coll::options::FindOneAndUpdateOptions;
use self::bson::Document;
use self::bson::Bson;

///
/// Holds a program object
///
pub struct Program {
    pub data: String,
    pub program_id: u64
}

///
/// Does the actual ingestion
///
pub fn ingest(first_time: bool, db: &Database, num_workers: usize) {
    let total_programs = get_total_programs();
    let mut updated_date = Arc::new(String::from(""));

    if !first_time {
        let current_time = time::now_utc();
        updated_date = Arc::new(format!("{}-{}-{}", 1900 + current_time.tm_year, current_time.tm_mon, current_time.tm_mday));
    }

    let mut worker_pool = worker_pool::WorkerPool::new(num_workers);

    for i in (0..total_programs).step_by(200) {
        let shared_updated_date = updated_date.clone();
        let shared_db = db.clone();

        worker_pool.add_worker(thread::spawn(move || {
            let programs = get_programs(i);
            let mut worker_pool = worker_pool::WorkerPool::new(num_workers);
            let coll = shared_db.collection("programs");

            for program in programs {
                let video_ids = Arc::new(Mutex::new(vec![]));
                let program_id = program.program_id;

                let filter = doc! {
                    "program_id" => program_id
                };

                // Can't use doc! macro because it escapes the JSON data.
                let mut update = Document::new();
                update.insert("program_id", program_id);
                update.insert("data", Bson::JavaScriptCode(program.data.clone()));

                let mut options = FindOneAndUpdateOptions::new();
                options.upsert = true;
                coll.find_one_and_replace(filter, update, Some(options)).expect("Can't insert program into database!");

                let shared_updated_date = shared_updated_date.clone();
                let shared_db = shared_db.clone();

                // We need this final shared DB because shared_db is moved into the thread so it can't be used to delete
                // at the end.
                let final_shared_db = shared_db.clone();

                let shared_video_ids = video_ids.clone();

                worker_pool.add_worker(thread::spawn(move || {
                    let total_videos = get_video_count_for_program(&shared_updated_date, &program);
                    let mut worker_pool = worker_pool::WorkerPool::new(num_workers);
                    let program = Arc::new(program);
                    let shared_video_ids = shared_video_ids.clone();

                    for j in (0..total_videos).step_by(200) {
                        let shared_program = program.clone();
                        let shared_updated_date = shared_updated_date.clone();
                        let shared_db = shared_db.clone();
                        let shared_video_ids = shared_video_ids.clone();

                        worker_pool.add_worker(thread::spawn(move || {
                            get_videos(&shared_updated_date, j, &shared_program, &shared_db, &shared_video_ids);
                        }));
                    }

                    worker_pool.wait_for_children();
                }));

                let video_ids_str = format!("[{}]", video_ids.lock().unwrap().join(","));
                let filter = doc! {
                    "tp_media_object_id" => video_ids_str,
                    "cond" => "$nin"
                };

                let video_coll = final_shared_db.collection("videos");
                video_coll.delete_many(filter, None).unwrap();
            }

            worker_pool.wait_for_children();
        }));
    }

    worker_pool.wait_for_children();
}

///
/// Gets the total programs to break them up
///
fn get_total_programs() -> u64 {
    cove::video_api("programs", vec![]).as_object().unwrap().get("count").unwrap().as_u64().unwrap()
}

///
/// Gets all the shows from COVE
///
fn get_programs(start_index: u64) -> Vec<Program> {
    let cove_data = cove::video_api("programs", vec![["limit_start", start_index.to_string().as_str()]]);
    let programs: &Vec<Value> = cove_data.as_object().unwrap().get("results").unwrap().as_array().unwrap();
    let mut programs_data = vec![];

    for program in programs {
        let program_uri = program.as_object().unwrap().get("resource_uri").unwrap().as_str().unwrap();
        let program_id: u64 = program_uri.split("/").nth(4).unwrap().parse().unwrap();

        programs_data.push(Program {data: program.to_string(), program_id: program_id});
    }

    programs_data
}

///
/// Gets the total videos for a program so they can be chunked
///
fn get_video_count_for_program<'a>(updated_date: &Arc<String>, program: &Program) -> u64 {
    let program_id = program.program_id.to_string();
    let mut params = vec![
        ["filter_program", program_id.as_str()],
        ["exclude_type", "Other"]
    ];

    if updated_date.as_str() != "" {
        params.push(["filter_record_last_updated_datetime__gt", updated_date.as_str()]);
    }

    cove::video_api("videos", params).as_object().unwrap().get("count").unwrap().as_u64().unwrap()
}

///
/// Gets all videos from COVE for a program, 200 at a time
///
fn get_videos(updated_date: &Arc<String>, start_index: u64, program: &Arc<Program>, db: &Database, video_ids: &Arc<Mutex<Vec<String>>>) {
    let program_id = program.program_id.to_string();
    let str_start_index = start_index.to_string();
    let mut params = vec![
        ["filter_program", program_id.as_str()],
        ["limit_start", str_start_index.as_str()],
        ["exclude_type", "Other"]
    ];

    if updated_date.as_str() != "" {
        params.push(["filter_record_last_updated_datetime__gt", updated_date.as_str()]);
    }

    let cove_data = cove::video_api("videos", params);
    let videos:&Vec<Value> = cove_data.as_object().unwrap().get("results").unwrap().as_array().unwrap();
    let coll = db.collection("videos");
    let mut page_video_ids = vec![];

    for video in videos {

        //
        // Not everything has a tp_media_object_id.  Ignore the ones that don't.
        //
        match video.as_object().unwrap().get("tp_media_object_id").unwrap().as_u64() {
            Some(tp_media_object_id) => {
                page_video_ids.push(tp_media_object_id.to_string());

                let filter = doc! {
                    "tp_media_object_id" => tp_media_object_id
                };

                // Can't use doc! macro because it escapes the data.
                let mut update = Document::new();
                update.insert("tp_media_object_id", tp_media_object_id);
                update.insert("program_id", program.program_id);
                update.insert("data", Bson::JavaScriptCode(video.to_string()));

                let mut options = FindOneAndUpdateOptions::new();
                options.upsert = true;

                coll.find_one_and_replace(filter, update, Some(options)).expect("Can't insert video into database!");
            },
            None => {}
        };
    }

    let shared_video_ids = video_ids.clone();
    let mut locked_video_ids = shared_video_ids.lock().unwrap();
    locked_video_ids.extend(page_video_ids);
}<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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 rustc::mir::{Local, Location};
use rustc::mir::Mir;
use rustc::mir::visit::PlaceContext;
use rustc::mir::visit::Visitor;

// The Visitor walks the MIR to return the assignment statements corresponding
// to a Local.
pub struct FindLocalAssignmentVisitor {
    needle: Local,
    locations: Vec<Location>,
}

impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
    fn visit_local(&mut self,
                   local: &Local,
                   place_context: PlaceContext<'tcx>,
                   location: Location) {
        if self.needle != *local {
            return;
        }

        match place_context {
            PlaceContext::Store | PlaceContext::Call => {
                self.locations.push(location);
            }
            PlaceContext::AsmOutput |
            PlaceContext::Drop |
            PlaceContext::Inspect |
            PlaceContext::Borrow { .. } |
            PlaceContext::Projection(..) |
            PlaceContext::Copy |
            PlaceContext::Move |
            PlaceContext::StorageLive |
            PlaceContext::StorageDead |
            PlaceContext::Validate => {
                // TO-DO
                // self.super_local(local)
            }
        }
    }
    // TO-DO
    // fn super_local()
}

crate trait FindAssignments {
    fn find_assignments(&self, local: Local) -> Vec<Location>;
    }

impl<'tcx> FindAssignments for Mir<'tcx>{
    fn find_assignments(&self, local: Local) -> Vec<Location>{
            let mut visitor = FindLocalAssignmentVisitor{ needle: local, locations: vec![]};
            visitor.visit_mir(self);
            visitor.locations
    }
}
<commit_msg>tidy fixes<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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 rustc::mir::{Local, Location};
use rustc::mir::Mir;
use rustc::mir::visit::PlaceContext;
use rustc::mir::visit::Visitor;

// The Visitor walks the MIR to return the assignment statements corresponding
// to a Local.
pub struct FindLocalAssignmentVisitor {
    needle: Local,
    locations: Vec<Location>,
}

impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
    fn visit_local(&mut self,
                   local: &Local,
                   place_context: PlaceContext<'tcx>,
                   location: Location) {
        if self.needle != *local {
            return;
        }

        match place_context {
            PlaceContext::Store | PlaceContext::Call => {
                self.locations.push(location);
            }
            PlaceContext::AsmOutput |
            PlaceContext::Drop |
            PlaceContext::Inspect |
            PlaceContext::Borrow { .. } |
            PlaceContext::Projection(..) |
            PlaceContext::Copy |
            PlaceContext::Move |
            PlaceContext::StorageLive |
            PlaceContext::StorageDead |
            PlaceContext::Validate => {
                // TO-DO
                // self.super_local(local)
            }
        }
    }
    // TO-DO
    // fn super_local()
}

crate trait FindAssignments {
    fn find_assignments(&self, local: Local) -> Vec<Location>;
    }

impl<'tcx> FindAssignments for Mir<'tcx>{
    fn find_assignments(&self, local: Local) -> Vec<Location>{
            let mut visitor = FindLocalAssignmentVisitor{ needle: local, locations: vec![]};
            visitor.visit_mir(self);
            visitor.locations
    }
}
<|endoftext|>


<commit_before><commit_msg>#[allow(dead_code)]<commit_after><|endoftext|>


<commit_before>extern crate bio;
use std::io;
use std::cmp;
use bio::io::fasta;

fn main() {
   let reader = fasta::Reader::new(io::stdin());
   let mut num_seqs = 0;
   let mut total = 0;
   let mut max_len = 0;
   let mut min_len = 0;
   let mut this_len;

   println!("FILENAME\tTOTAL\tNUMSEQ\tMIN\tAVG\tMAX");

   for next in reader.records() {
      match next {
         Ok(record) => {
            num_seqs += 1;
            this_len = record.seq().len();
            total += this_len;
            if num_seqs == 1 {
               max_len = this_len;
               min_len = this_len;
            }
            else {
               max_len = cmp::max(max_len, this_len);
               min_len = cmp::min(min_len, this_len);
            }
         },
         Err(error) => println!("{}", error),
      }
   }
   if num_seqs > 0 {
      let average = ((total as f64) / (num_seqs as f64)).floor() as usize;
      println!("{}\t{}\t{}\t{}\t{}", num_seqs, total, min_len, average, max_len);
   }
   else {
      println!("0\t0\t-\t-\t-");
   }
}
<commit_msg>Use struct for FastaStats, clean up main function. Use Display for printing<commit_after>extern crate bio;
use std::io;
use std::cmp;
use bio::io::fasta;
use std::fmt;

struct FastaStats {
   min_len: u64,
   average_len: u64,
   max_len: u64,
   total: u64,
   num_seqs: u64,
}

impl FastaStats {
   pub fn new<R: io::Read>(reader: R) -> Option<FastaStats> {
      let fasta_reader = fasta::Reader::new(reader);
      let mut num_seqs:u64 = 0;
      let mut total:u64 = 0;
      let mut max_len:u64 = 0;
      let mut min_len:u64 = 0;
      let mut this_len:u64;

      for next in fasta_reader.records() {
         match next {
            Ok(record) => {
               num_seqs += 1;
               this_len = record.seq().len() as u64;
               total += this_len;
               if num_seqs == 1 {
                  max_len = this_len;
                  min_len = this_len;
               }
               else {
                  max_len = cmp::max(max_len, this_len);
                  min_len = cmp::min(min_len, this_len);
               }
            },
            // XXX handle errors properly
            Err(error) => println!("{}", error),
         }
      }
      if num_seqs > 0 {
         // XXX check whether integer division does floor
         let average_len = ((total as f64) / (num_seqs as f64)).floor() as u64;
         Some(FastaStats { min_len: min_len,
                           average_len: average_len,
                           max_len: max_len,
                           total: total,
                           num_seqs: num_seqs })
      }
      else {
         None
      }
   }
}

impl fmt::Display for FastaStats {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "{}\t{}\t{}\t{}\t{}", self.num_seqs, self.total, self.min_len, self.average_len, self.max_len)
   }
}

fn main() {
   println!("FILENAME\tTOTAL\tNUMSEQ\tMIN\tAVG\tMAX");
   match FastaStats::new(io::stdin()) {
      Some(stats) => {
         println!("{}", stats);
      }
      None => {
         println!("0\t0\t-\t-\t-");
      }
   }
}
<|endoftext|>


<commit_before>extern crate nanomsg;

use nanomsg::{Socket, Protocol};
use std::io::{Read, Write};

const ADDRESS: &'static str = "ipc:///tmp/a.ipc";

fn main() {
    let mut socket = Socket::new(Protocol::Rep).unwrap();
    println!("Connecting to address '{}'", ADDRESS);
    let mut endpoint = socket.bind(ADDRESS).unwrap();

    let mut request = String::new();
    loop {
        println!("Waiting for a message");
        socket.read_to_string(&mut request).unwrap();
        println!("Received '{}'", request);

        match request.as_ref() {
            "PING" => {
                reply(&mut socket, "PONG");
            }
            "STOP" => {
                reply(&mut socket, "OK");
                println!("Shutting down");
                break;
            },
            _ => reply(&mut socket, "UNKNOWN REQUEST")
        }

        request.clear();
    }

    endpoint.shutdown().unwrap();
}

fn reply(socket: &mut Socket, reply: &str) {
    socket.write_all(reply.as_bytes()).unwrap();
    println!("Replied with '{}'", reply)
}

<commit_msg>Updated to Rust 1.4<commit_after>extern crate nanomsg;

use nanomsg::{Socket, Protocol};
use std::io::{Read, Write};

const ADDRESS: &'static str = "ipc:///tmp/a.ipc";

fn main() {
    let mut socket = Socket::new(Protocol::Rep).unwrap();
    println!("Connecting to address '{}'", ADDRESS);
    let mut endpoint = socket.bind(ADDRESS).unwrap();

    let mut request = String::new();
    loop {
        println!("Waiting for a message");
        socket.read_to_string(&mut request).expect("Failed to read request");
        println!("Received '{}'", request);

        match request.as_ref() {
            "PING" => {
                reply(&mut socket, "PONG");
            }
            "STOP" => {
                reply(&mut socket, "OK");
                println!("Shutting down");
                break;
            },
            _ => reply(&mut socket, "UNKNOWN REQUEST")
        }

        request.clear();
    }

    endpoint.shutdown().expect("Failed to shutdown gracefully");
}

fn reply(socket: &mut Socket, reply: &str) {
    socket.write_all(reply.as_bytes()).expect("Failed to send reply");
    println!("Replied with '{}'", reply)
}

<|endoftext|>


<commit_before>///
/// This example parses, sorts and groups the iris dataset
/// and does some simple manipulations.
///
/// Iterators and itertools functionality are used throughout.
///
///

extern crate itertools;

use itertools::Itertools;
use std::collections::HashMap;
use std::iter::repeat;
use std::num::ParseFloatError;
use std::str::FromStr;

static DATA: &'static str = include_str!("iris.data");

#[derive(Clone, Debug)]
struct Iris {
    name: String,
    data: [f32; 4],
}

#[derive(Clone, Debug)]
enum ParseError {
    Numeric(ParseFloatError),
    Other(&'static str),
}

impl From<ParseFloatError> for ParseError {
    fn from(err: ParseFloatError) -> Self {
        ParseError::Numeric(err)
    }
}

/// Parse an Iris from a comma-separated line
impl FromStr for Iris {
    type Err = ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut iris = Iris { name: "".into(), data: [0.; 4] };
        let mut parts = s.split(",").map(str::trim);

        // using Iterator::by_ref()
        for (index, part) in parts.by_ref().take(4).enumerate() {
            iris.data[index] = try!(part.parse::<f32>());
        }
        if let Some(name) = parts.next() {
            iris.name = name.into();
        } else {
            return Err(ParseError::Other("Missing name"))
        }
        Ok(iris)
    }
}

fn main() {
    // using Itertools::fold_results to create the result of parsing
    let irises = DATA.lines()
                     .map(str::parse)
                     .fold_results(Vec::new(), |mut v, iris: Iris| {
                         v.push(iris);
                         v
                     });
    let mut irises = match irises {
        Err(e) => {
            println!("Error parsing: {:?}", e);
            std::process::exit(1);
        }
        Ok(data) => data,
    };

    // Sort them and group them
    irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));

    // using Iterator::cycle()
    let mut plot_symbols = "+ox".chars().cycle();
    let mut symbolmap = HashMap::new();

    // using Itertools::group_by_lazy
    for (species, species_group) in &irises.iter().group_by_lazy(|iris| &iris.name) {
        // assign a plot symbol
        symbolmap.entry(species).or_insert_with(|| {
            plot_symbols.next().unwrap()
        });
        println!("{} (symbol={})", species, symbolmap[species]);

        for iris in species_group {
            // using Itertools::format for lazy formatting
            println!("{}",
                     iris.data.iter()
                     .format(", ", |elt, f| f(&format_args!("{:>3.1}", elt))));
        }

    }

    // Look at all combinations of the four columns
    //
    // See https://en.wikipedia.org/wiki/Iris_flower_data_set
    //
    let n = 30; // plot size
    let mut plot = vec![' '; n * n];

    // using Itertools::combinations
    for (a, b) in (0..4).combinations() {
        println!("Column {} vs {}:", a, b);

        // Clear plot
        //
        // using std::iter::repeat;
        // using Itertools::set_from
        plot.iter_mut().set_from(repeat(' '));

        // using Itertools::fold1
        let min_max = |data: &[Iris], col| {
            data.iter()
                .map(|iris| iris.data[col])
                .map(|x| (x, x))
                .fold1(|(min, max), (elt, _)|
                    (f32::min(min, elt), f32::max(max, elt))
                ).expect("Can't find min/max of empty iterator")
        };
        let (min_x, max_x) = min_max(&irises, a);
        let (min_y, max_y) = min_max(&irises, b);

        // Plot the data points
        let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n - 1) as f32)) as usize;
        let flip = |ix| n - 1 - ix; // reverse axis direction

        for iris in &irises {
            let ix = round_to_grid(iris.data[a], min_x, max_x);
            let iy = flip(round_to_grid(iris.data[b], min_y, max_y));
            plot[n * iy + ix] = symbolmap[&iris.name];
        }

        // render plot
        //
        // using Itertools::join
        for line in plot.chunks(n) {
            println!("{}", line.iter().join(" "))
        }
    }
}
<commit_msg>Use format_default() and minmax() in iris<commit_after>///
/// This example parses, sorts and groups the iris dataset
/// and does some simple manipulations.
///
/// Iterators and itertools functionality are used throughout.
///
///

extern crate itertools;

use itertools::Itertools;
use std::collections::HashMap;
use std::iter::repeat;
use std::num::ParseFloatError;
use std::str::FromStr;

static DATA: &'static str = include_str!("iris.data");

#[derive(Clone, Debug)]
struct Iris {
    name: String,
    data: [f32; 4],
}

#[derive(Clone, Debug)]
enum ParseError {
    Numeric(ParseFloatError),
    Other(&'static str),
}

impl From<ParseFloatError> for ParseError {
    fn from(err: ParseFloatError) -> Self {
        ParseError::Numeric(err)
    }
}

/// Parse an Iris from a comma-separated line
impl FromStr for Iris {
    type Err = ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut iris = Iris { name: "".into(), data: [0.; 4] };
        let mut parts = s.split(",").map(str::trim);

        // using Iterator::by_ref()
        for (index, part) in parts.by_ref().take(4).enumerate() {
            iris.data[index] = try!(part.parse::<f32>());
        }
        if let Some(name) = parts.next() {
            iris.name = name.into();
        } else {
            return Err(ParseError::Other("Missing name"))
        }
        Ok(iris)
    }
}

fn main() {
    // using Itertools::fold_results to create the result of parsing
    let irises = DATA.lines()
                     .map(str::parse)
                     .fold_results(Vec::new(), |mut v, iris: Iris| {
                         v.push(iris);
                         v
                     });
    let mut irises = match irises {
        Err(e) => {
            println!("Error parsing: {:?}", e);
            std::process::exit(1);
        }
        Ok(data) => data,
    };

    // Sort them and group them
    irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));

    // using Iterator::cycle()
    let mut plot_symbols = "+ox".chars().cycle();
    let mut symbolmap = HashMap::new();

    // using Itertools::group_by_lazy
    for (species, species_group) in &irises.iter().group_by_lazy(|iris| &iris.name) {
        // assign a plot symbol
        symbolmap.entry(species).or_insert_with(|| {
            plot_symbols.next().unwrap()
        });
        println!("{} (symbol={})", species, symbolmap[species]);

        for iris in species_group {
            // using Itertools::format_default for lazy formatting
            println!("{:>3.1}", iris.data.iter().format_default(", "));
        }

    }

    // Look at all combinations of the four columns
    //
    // See https://en.wikipedia.org/wiki/Iris_flower_data_set
    //
    let n = 30; // plot size
    let mut plot = vec![' '; n * n];

    // using Itertools::combinations
    for (a, b) in (0..4).combinations() {
        println!("Column {} vs {}:", a, b);

        // Clear plot
        //
        // using std::iter::repeat;
        // using Itertools::set_from
        plot.iter_mut().set_from(repeat(' '));

        // using Itertools::minmax_by
        let min_max = |data: &[Iris], col| {
            data.iter()
                .map(|iris| iris.data[col])
                .minmax_by(|a, b| f32::partial_cmp(a, b).unwrap())
                .into_option()
                .expect("Can't find min/max of empty iterator")
        };
        let (min_x, max_x) = min_max(&irises, a);
        let (min_y, max_y) = min_max(&irises, b);

        // Plot the data points
        let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n - 1) as f32)) as usize;
        let flip = |ix| n - 1 - ix; // reverse axis direction

        for iris in &irises {
            let ix = round_to_grid(iris.data[a], min_x, max_x);
            let iy = flip(round_to_grid(iris.data[b], min_y, max_y));
            plot[n * iy + ix] = symbolmap[&iris.name];
        }

        // render plot
        //
        // using Itertools::join
        for line in plot.chunks(n) {
            println!("{}", line.iter().join(" "))
        }
    }
}
<|endoftext|>


<commit_before>use value::{Value};

#[derive(Clone, Debug, Copy)]
pub enum Primitive {
    Add,
    Subtract,
    Count,
    Sum,
    Mean,
    StandardDeviation,
    Empty,
}

pub fn resolve_as_scalar<'a>(mut ix: usize, constants: &'a [Value], outer: &'a [Value]) -> &'a Value {
    if ix < constants.len() {
        return &constants[ix];
    } else {
        ix = ix - constants.len()
    }
    return &outer[ix];
}

pub fn resolve_as_vector<'a>(mut ix: usize, constants: &'a [Value], outer: &'a [Value], inner: &'a [Vec<Value>]) -> Vec<&'a Value> {
    if ix < constants.len() {
        return vec![&constants[ix]; inner.len()];
    } else {
        ix = ix - constants.len()
    }
    if ix < outer.len() {
        return vec![&outer[ix]; inner.len()];
    } else {
        ix = ix - outer.len()
    }
    return inner.iter().map(|values| &values[ix]).collect();
}

impl Primitive {
    pub fn eval_from_join<'a>(&self, arguments: &[usize], inputs: &[&Value]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        let values = arguments.iter().map(|ix| inputs[*ix]).collect::<Vec<_>>();
        match (*self, &values[..]) {
            (Add, [&Float(a), &Float(b)]) => vec![vec![Float(a+b)]],
            (Subtract, [&Float(a), &Float(b)]) => vec![vec![Float(a-b)]],
            (Count, _) => panic!("Cannot use {:?} in a join", self),
            (Sum, _) => panic!("Cannot use {:?} in a join", self),
            (Mean, _) => panic!("Cannot use {:?} in a join", self),
            (StandardDeviation, _) => panic!("Cannot use {:?} in a join", self),
            (Empty, _) => panic!("Cannot use {:?} in a join", self),
            _ => panic!("Type error while calling: {:?} {:?}", self, &arguments)
        }
    }

    pub fn eval_from_aggregate<'a>(&self, arguments: &[usize], constants: &[Value], outer: &[Value], inner: &[Vec<Value>]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        match (*self, arguments) {
            (Add, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Subtract, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Count, [_]) => {
                vec![vec![Float(inner.len() as f64)]]
            }
            (Sum, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                vec![vec![Float(sum)]]
            },
            (Mean, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let mean = sum / (in_values.len() as f64);
                vec![vec![Float(mean)]]
            },
            (StandardDeviation, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let sum_squares = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float.powi(2),
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let standard_deviation = ((sum_squares - sum.powi(2)) / (in_values.len() as f64)).sqrt();
                vec![vec![Float(standard_deviation)]]
            },
            (Empty, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                vec![vec![Bool(in_values.len() == 0)]]
            }
            _ => panic!("Wrong number of arguments while calling: {:?} {:?}", self, arguments),
        }
    }

    pub fn from_str(string: &str) -> Self {
        match string {
            "add" => Primitive::Add,
            "subtract" => Primitive::Subtract,
            "count" => Primitive::Count,
            "sum" => Primitive::Sum,
            "mean" => Primitive::Mean,
            "standard deviation" => Primitive::StandardDeviation,
            "empty" => Primitive::Empty,
            _ => panic!("Unknown primitive: {:?}", string),
        }
    }
}

pub fn primitives() -> Vec<(&'static str, Vec<&'static str>, Vec<&'static str>, Vec<&'static str>)> {
    vec![
        ("add", vec!["in A", "in B"], vec![], vec!["out"]),
        ("subtract", vec!["in A", "in B"], vec![], vec!["out"]),
        ("count", vec![], vec!["in"], vec!["out"]),
        ("sum", vec![], vec!["in"], vec!["out"]),
        ("mean", vec![], vec!["in"], vec!["out"]),
        ("standard deviation", vec![], vec!["in"], vec!["out"]),
        ("empty", vec![], vec!["in"], vec!["out"]),
    ]
}<commit_msg>Add contains<commit_after>use value::{Value};

#[derive(Clone, Debug, Copy)]
pub enum Primitive {
    Add,
    Subtract,
    Count,
    Contains,
    Sum,
    Mean,
    StandardDeviation,
    Empty,
}

pub fn resolve_as_scalar<'a>(mut ix: usize, constants: &'a [Value], outer: &'a [Value]) -> &'a Value {
    if ix < constants.len() {
        return &constants[ix];
    } else {
        ix = ix - constants.len()
    }
    return &outer[ix];
}

pub fn resolve_as_vector<'a>(mut ix: usize, constants: &'a [Value], outer: &'a [Value], inner: &'a [Vec<Value>]) -> Vec<&'a Value> {
    if ix < constants.len() {
        return vec![&constants[ix]; inner.len()];
    } else {
        ix = ix - constants.len()
    }
    if ix < outer.len() {
        return vec![&outer[ix]; inner.len()];
    } else {
        ix = ix - outer.len()
    }
    return inner.iter().map(|values| &values[ix]).collect();
}

impl Primitive {
    pub fn eval_from_join<'a>(&self, arguments: &[usize], inputs: &[&Value]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        let values = arguments.iter().map(|ix| inputs[*ix]).collect::<Vec<_>>();
        match (*self, &values[..]) {
            // NOTE be aware that arguments will be in alphabetical order by field id
            (Add, [&Float(a), &Float(b)]) => vec![vec![Float(a+b)]],
            (Subtract, [&Float(a), &Float(b)]) => vec![vec![Float(a-b)]],
            (Contains, [&String(ref inner), &String(ref outer)]) => vec![vec![Bool(outer.contains(inner))]],
            (Count, _) => panic!("Cannot use {:?} in a join", self),
            (Sum, _) => panic!("Cannot use {:?} in a join", self),
            (Mean, _) => panic!("Cannot use {:?} in a join", self),
            (StandardDeviation, _) => panic!("Cannot use {:?} in a join", self),
            (Empty, _) => panic!("Cannot use {:?} in a join", self),
            _ => panic!("Type error while calling: {:?} {:?}", self, &arguments)
        }
    }

    pub fn eval_from_aggregate<'a>(&self, arguments: &[usize], constants: &[Value], outer: &[Value], inner: &[Vec<Value>]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        match (*self, arguments) {
            // NOTE be aware that arguments will be in alphabetical order by field id
            (Add, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Subtract, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Contains, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Count, [_]) => {
                vec![vec![Float(inner.len() as f64)]]
            }
            (Sum, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                vec![vec![Float(sum)]]
            },
            (Mean, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let mean = sum / (in_values.len() as f64);
                vec![vec![Float(mean)]]
            },
            (StandardDeviation, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let sum_squares = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float.powi(2),
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let standard_deviation = ((sum_squares - sum.powi(2)) / (in_values.len() as f64)).sqrt();
                vec![vec![Float(standard_deviation)]]
            },
            (Empty, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                vec![vec![Bool(in_values.len() == 0)]]
            }
            _ => panic!("Wrong number of arguments while calling: {:?} {:?}", self, arguments),
        }
    }

    pub fn from_str(string: &str) -> Self {
        match string {
            "add" => Primitive::Add,
            "subtract" => Primitive::Subtract,
            "contains" => Primitive::Contains,
            "count" => Primitive::Count,
            "sum" => Primitive::Sum,
            "mean" => Primitive::Mean,
            "standard deviation" => Primitive::StandardDeviation,
            "empty" => Primitive::Empty,
            _ => panic!("Unknown primitive: {:?}", string),
        }
    }
}

pub fn primitives() -> Vec<(&'static str, Vec<&'static str>, Vec<&'static str>, Vec<&'static str>)> {
    vec![
        ("add", vec!["in A", "in B"], vec![], vec!["out"]),
        ("subtract", vec!["in A", "in B"], vec![], vec!["out"]),
        ("contains", vec!["inner", "outer"], vec![], vec!["out"]),
        ("count", vec![], vec!["in"], vec!["out"]),
        ("sum", vec![], vec!["in"], vec!["out"]),
        ("mean", vec![], vec!["in"], vec!["out"]),
        ("standard deviation", vec![], vec!["in"], vec!["out"]),
        ("empty", vec![], vec!["in"], vec!["out"]),
    ]
}<|endoftext|>


<commit_before>extern crate iron;
extern crate rustc_serialize;
extern crate queryst;

use rustc_serialize::json::{self, Json};
use iron::prelude::*;
use iron::status;
use queryst::parse;

#[derive(RustcEncodable)]
pub struct PadJson {
    str: String
}

fn left_pad(string: &str, len: u32, ch: &str) -> String {
    let i = -1;
    let mut temp_len = len - (string.len() as u32);
    return String::from("hallo");
}

fn main() {
    fn handler(req: &mut Request) -> IronResult<Response> {

        let query = req.url.query.clone().unwrap_or("".to_string());

        let query_params: Json = parse(&query.to_string()).unwrap();
        let obj                = query_params.as_object().unwrap();

        let string : &str = obj.get("str").unwrap().as_string().unwrap();
        let len : u32     = obj.get("len").unwrap().as_string().unwrap().parse().unwrap();
        let ch : &str     = obj.get("ch").unwrap().as_string().unwrap();

        let padded_resp = PadJson {
            str: left_pad(string, len, ch),
        };

        Ok(Response::with((status::Ok, json::encode(&padded_resp).unwrap())))
    }

    Iron::new(handler).http("localhost:3000").unwrap();
}
<commit_msg>Add not yet fully working outline for rust leftpad<commit_after>extern crate iron;
extern crate rustc_serialize;
extern crate queryst;

use rustc_serialize::json::{self, Json};
use iron::prelude::*;
use iron::status;
use queryst::parse;

#[derive(RustcEncodable)]
pub struct PadJson {
    str: String
}

fn left_pad(string: &str, len: u32, ch: &str) -> String {

    let mut i: i32 = -1;
    let temp_len: i32 = len as i32 - (string.len() as i32);
    let mut return_string : String = string.to_string();

    while i < temp_len {
        return_string = ch.to_string() + &string.to_string();
        i = i + 1;
    }

    return String::from(return_string);
}

fn main() {
    fn handler(req: &mut Request) -> IronResult<Response> {

        let query = req.url.query.clone().unwrap_or("".to_string());

        let query_params: Json = parse(&query.to_string()).unwrap();
        let obj                = query_params.as_object().unwrap();

        let string : &str = obj.get("str").unwrap().as_string().unwrap();
        let len : u32     = obj.get("len").unwrap().as_string().unwrap().parse().unwrap();
        let ch : &str     = obj.get("ch").unwrap().as_string().unwrap();

        let padded_resp = PadJson {
            str: left_pad(string, len, ch),
        };

        Ok(Response::with((status::Ok, json::encode(&padded_resp).unwrap())))
    }

    Iron::new(handler).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>//! A crate exposing the `pact` APIs to other languages
//! via a C Foreign Function Interface.

#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![warn(missing_copy_implementations)]

use std::ffi::CStr;
use std::str::FromStr;

use env_logger::Builder;
use libc::c_char;

use models::message::Message;
use pact_matching::{self as pm};
pub use pact_matching::Mismatch;
use pact_models::interaction::Interaction;
use pact_models::v4::pact::V4Pact;
use pact_models::pact::Pact;

use crate::util::*;

pub mod error;
pub mod log;
pub mod models;
pub(crate) mod util;
pub mod mock_server;
pub mod verifier;
pub mod plugins;

const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");

/// Get the current library version
#[no_mangle]
pub extern "C" fn pactffi_version() -> *const c_char {
    VERSION.as_ptr() as *const c_char
}

/// Initialise the mock server library, can provide an environment variable name to use to
/// set the log levels.
///
/// # Safety
///
/// log_env_var must be a valid NULL terminated UTF-8 string.
#[no_mangle]
pub unsafe extern fn pactffi_init(log_env_var: *const c_char) {
    init_windows();

    let log_env_var = if !log_env_var.is_null() {
        let c_str = CStr::from_ptr(log_env_var);
        match c_str.to_str() {
            Ok(str) => str,
            Err(err) => {
                ::log::warn!("Failed to parse the environment variable name as a UTF-8 string: {}", err);
                "LOG_LEVEL"
            }
        }
    } else {
        "LOG_LEVEL"
    };

    let env = env_logger::Env::new().filter(log_env_var);
    let mut builder = Builder::from_env(env);
    builder.try_init().unwrap_or(());
}

#[cfg(windows)]
fn init_windows() {
    if let Err(err) = ansi_term::enable_ansi_support() {
        warn!("Could not enable ANSI console support - {err}");
    }
}

#[cfg(not(windows))]
fn init_windows() { }

/// Initialises logging, and sets the log level explicitly.
///
/// # Safety
///
/// Exported functions are inherently unsafe.
#[no_mangle]
pub unsafe extern "C" fn pactffi_init_with_log_level(level: *const c_char) {
    let mut builder = Builder::from_default_env();
    let log_level = log_level_from_c_char(level);

    builder.filter_level(log_level.to_level_filter());
    builder.try_init().unwrap_or(());
}

/// Log using the shared core logging facility.
///
/// This is useful for callers to have a single set of logs.
///
/// * `source` - String. The source of the log, such as the class or caller framework to
///                      disambiguate log lines from the rust logging (e.g. pact_go)
/// * `log_level` - String. One of TRACE, DEBUG, INFO, WARN, ERROR
/// * `message` - Message to log
///
/// # Safety
/// This function will fail if any of the pointers passed to it are invalid.
#[no_mangle]
pub unsafe extern "C" fn pactffi_log_message(source: *const c_char, log_level: *const c_char, message: *const c_char) {
    let target = convert_cstr("target", source).unwrap_or("client");

    if !message.is_null() {
        if let Some(message) = convert_cstr("message", message) {
            ::log::log!(target: target, log_level_from_c_char(log_level), "{}", message)
        }
    }
}

unsafe fn log_level_from_c_char(log_level: *const c_char) -> ::log::Level {
    if !log_level.is_null() {
        let level = convert_cstr("log_level", log_level).unwrap_or("INFO");
        ::log::Level::from_str(level).unwrap_or(::log::Level::Info)
    } else {
        ::log::Level::Info
    }
}

fn convert_cstr(name: &str, value: *const c_char) -> Option<&str> {
    unsafe {
        if value.is_null() {
            ::log::warn!("{} is NULL!", name);
            None
        } else {
            let c_str = CStr::from_ptr(value);
            match c_str.to_str() {
                Ok(str) => Some(str),
                Err(err) => {
                    ::log::warn!("Failed to parse {} name as a UTF-8 string: {}", name, err);
                    None
                }
            }
        }
    }
}

ffi_fn! {
    /// Match a pair of messages, producing a collection of mismatches,
    /// which is empty if the two messages matched.
    fn pactffi_match_message(msg_1: *const Message, msg_2: *const Message) -> *const Mismatches {
        let msg_1: Box<dyn Interaction + Send + Sync> = unsafe { Box::from_raw(msg_1 as *mut Message) };
        let msg_2: Box<dyn Interaction + Send + Sync> = unsafe { Box::from_raw(msg_2 as *mut Message) };

        let runtime = tokio::runtime::Runtime::new().unwrap();
        let mismatches = runtime.block_on(async move {
            // TODO: match_message also requires the Pact that the messages belong to
            Mismatches(pm::match_message(&msg_1, &msg_2, &V4Pact::default().boxed()).await)
        });

        ptr::raw_to(mismatches) as *const Mismatches
    } {
        ptr::null_to::<Mismatches>() as *const Mismatches
    }
}

ffi_fn! {
    /// Get an iterator over mismatches.
    fn pactffi_mismatches_get_iter(mismatches: *const Mismatches) -> *mut MismatchesIterator {
        let mismatches = as_ref!(mismatches);
        let iter = MismatchesIterator { current: 0, mismatches };
        ptr::raw_to(iter)
    } {
        ptr::null_mut_to::<MismatchesIterator>()
    }
}

ffi_fn! {
    /// Delete mismatches
    fn pactffi_mismatches_delete(mismatches: *const Mismatches) {
        ptr::drop_raw(mismatches as *mut Mismatches);
    }
}

ffi_fn! {
    /// Get the next mismatch from a mismatches iterator.
    ///
    /// Returns a null pointer if no mismatches remain.
    fn pactffi_mismatches_iter_next(iter: *mut MismatchesIterator) -> *const Mismatch {
        let iter = as_mut!(iter);
        let mismatches = as_ref!(iter.mismatches);
        let index = iter.next();
        let mismatch = mismatches
            .0
            .get(index)
            .ok_or(anyhow::anyhow!("iter past the end of mismatches"))?;
       mismatch as *const Mismatch
    } {
        ptr::null_to::<Mismatch>()
    }
}

ffi_fn! {
    /// Delete a mismatches iterator when you're done with it.
    fn pactffi_mismatches_iter_delete(iter: *mut MismatchesIterator) {
        ptr::drop_raw(iter);
    }
}

ffi_fn! {
    /// Get a JSON representation of the mismatch.
    fn pactffi_mismatch_to_json(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let json = mismatch.to_json().to_string();
        string::to_c(&json)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get the type of a mismatch.
    fn pactffi_mismatch_type(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let t = mismatch.mismatch_type();
        string::to_c(t)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get a summary of a mismatch.
    fn pactffi_mismatch_summary(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let summary = mismatch.summary();
        string::to_c(&summary)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get a description of a mismatch.
    fn pactffi_mismatch_description(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let description = mismatch.description();
        string::to_c(&description)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get an ANSI-compatible description of a mismatch.
    fn pactffi_mismatch_ansi_description(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let ansi_description = mismatch.ansi_description();
        string::to_c(&ansi_description)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

/// A collection of mismatches from a matching comparison.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct Mismatches(Vec<Mismatch>);

/// An iterator over mismatches.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct MismatchesIterator {
    current: usize,
    mismatches: *const Mismatches,
}

impl MismatchesIterator {
    fn next(&mut self) -> usize {
        let idx = self.current;
        self.current += 1;
        idx
    }
}
<commit_msg>chore: fix missing import on Windows<commit_after>//! A crate exposing the `pact` APIs to other languages
//! via a C Foreign Function Interface.

#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![warn(missing_copy_implementations)]

use std::ffi::CStr;
use std::str::FromStr;

use ::log::warn;
use env_logger::Builder;
use libc::c_char;
use pact_models::interaction::Interaction;
use pact_models::pact::Pact;
use pact_models::v4::pact::V4Pact;

use models::message::Message;
use pact_matching as pm;
pub use pact_matching::Mismatch;

use crate::util::*;

pub mod error;
pub mod log;
pub mod models;
pub(crate) mod util;
pub mod mock_server;
pub mod verifier;
pub mod plugins;

const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");

/// Get the current library version
#[no_mangle]
pub extern "C" fn pactffi_version() -> *const c_char {
    VERSION.as_ptr() as *const c_char
}

/// Initialise the mock server library, can provide an environment variable name to use to
/// set the log levels.
///
/// # Safety
///
/// log_env_var must be a valid NULL terminated UTF-8 string.
#[no_mangle]
pub unsafe extern fn pactffi_init(log_env_var: *const c_char) {
    init_windows();

    let log_env_var = if !log_env_var.is_null() {
        let c_str = CStr::from_ptr(log_env_var);
        match c_str.to_str() {
            Ok(str) => str,
            Err(err) => {
                warn!("Failed to parse the environment variable name as a UTF-8 string: {}", err);
                "LOG_LEVEL"
            }
        }
    } else {
        "LOG_LEVEL"
    };

    let env = env_logger::Env::new().filter(log_env_var);
    let mut builder = Builder::from_env(env);
    builder.try_init().unwrap_or(());
}

#[cfg(windows)]
fn init_windows() {
    if let Err(err) = ansi_term::enable_ansi_support() {
        warn!("Could not enable ANSI console support - {err}");
    }
}

#[cfg(not(windows))]
fn init_windows() { }

/// Initialises logging, and sets the log level explicitly.
///
/// # Safety
///
/// Exported functions are inherently unsafe.
#[no_mangle]
pub unsafe extern "C" fn pactffi_init_with_log_level(level: *const c_char) {
    let mut builder = Builder::from_default_env();
    let log_level = log_level_from_c_char(level);

    builder.filter_level(log_level.to_level_filter());
    builder.try_init().unwrap_or(());
}

/// Log using the shared core logging facility.
///
/// This is useful for callers to have a single set of logs.
///
/// * `source` - String. The source of the log, such as the class or caller framework to
///                      disambiguate log lines from the rust logging (e.g. pact_go)
/// * `log_level` - String. One of TRACE, DEBUG, INFO, WARN, ERROR
/// * `message` - Message to log
///
/// # Safety
/// This function will fail if any of the pointers passed to it are invalid.
#[no_mangle]
pub unsafe extern "C" fn pactffi_log_message(source: *const c_char, log_level: *const c_char, message: *const c_char) {
    let target = convert_cstr("target", source).unwrap_or("client");

    if !message.is_null() {
        if let Some(message) = convert_cstr("message", message) {
            ::log::log!(target: target, log_level_from_c_char(log_level), "{}", message)
        }
    }
}

unsafe fn log_level_from_c_char(log_level: *const c_char) -> ::log::Level {
    if !log_level.is_null() {
        let level = convert_cstr("log_level", log_level).unwrap_or("INFO");
        ::log::Level::from_str(level).unwrap_or(::log::Level::Info)
    } else {
        ::log::Level::Info
    }
}

fn convert_cstr(name: &str, value: *const c_char) -> Option<&str> {
    unsafe {
        if value.is_null() {
            ::log::warn!("{} is NULL!", name);
            None
        } else {
            let c_str = CStr::from_ptr(value);
            match c_str.to_str() {
                Ok(str) => Some(str),
                Err(err) => {
                    ::log::warn!("Failed to parse {} name as a UTF-8 string: {}", name, err);
                    None
                }
            }
        }
    }
}

ffi_fn! {
    /// Match a pair of messages, producing a collection of mismatches,
    /// which is empty if the two messages matched.
    fn pactffi_match_message(msg_1: *const Message, msg_2: *const Message) -> *const Mismatches {
        let msg_1: Box<dyn Interaction + Send + Sync> = unsafe { Box::from_raw(msg_1 as *mut Message) };
        let msg_2: Box<dyn Interaction + Send + Sync> = unsafe { Box::from_raw(msg_2 as *mut Message) };

        let runtime = tokio::runtime::Runtime::new().unwrap();
        let mismatches = runtime.block_on(async move {
            // TODO: match_message also requires the Pact that the messages belong to
            Mismatches(pm::match_message(&msg_1, &msg_2, &V4Pact::default().boxed()).await)
        });

        ptr::raw_to(mismatches) as *const Mismatches
    } {
        ptr::null_to::<Mismatches>() as *const Mismatches
    }
}

ffi_fn! {
    /// Get an iterator over mismatches.
    fn pactffi_mismatches_get_iter(mismatches: *const Mismatches) -> *mut MismatchesIterator {
        let mismatches = as_ref!(mismatches);
        let iter = MismatchesIterator { current: 0, mismatches };
        ptr::raw_to(iter)
    } {
        ptr::null_mut_to::<MismatchesIterator>()
    }
}

ffi_fn! {
    /// Delete mismatches
    fn pactffi_mismatches_delete(mismatches: *const Mismatches) {
        ptr::drop_raw(mismatches as *mut Mismatches);
    }
}

ffi_fn! {
    /// Get the next mismatch from a mismatches iterator.
    ///
    /// Returns a null pointer if no mismatches remain.
    fn pactffi_mismatches_iter_next(iter: *mut MismatchesIterator) -> *const Mismatch {
        let iter = as_mut!(iter);
        let mismatches = as_ref!(iter.mismatches);
        let index = iter.next();
        let mismatch = mismatches
            .0
            .get(index)
            .ok_or(anyhow::anyhow!("iter past the end of mismatches"))?;
       mismatch as *const Mismatch
    } {
        ptr::null_to::<Mismatch>()
    }
}

ffi_fn! {
    /// Delete a mismatches iterator when you're done with it.
    fn pactffi_mismatches_iter_delete(iter: *mut MismatchesIterator) {
        ptr::drop_raw(iter);
    }
}

ffi_fn! {
    /// Get a JSON representation of the mismatch.
    fn pactffi_mismatch_to_json(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let json = mismatch.to_json().to_string();
        string::to_c(&json)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get the type of a mismatch.
    fn pactffi_mismatch_type(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let t = mismatch.mismatch_type();
        string::to_c(t)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get a summary of a mismatch.
    fn pactffi_mismatch_summary(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let summary = mismatch.summary();
        string::to_c(&summary)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get a description of a mismatch.
    fn pactffi_mismatch_description(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let description = mismatch.description();
        string::to_c(&description)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get an ANSI-compatible description of a mismatch.
    fn pactffi_mismatch_ansi_description(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let ansi_description = mismatch.ansi_description();
        string::to_c(&ansi_description)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

/// A collection of mismatches from a matching comparison.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct Mismatches(Vec<Mismatch>);

/// An iterator over mismatches.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct MismatchesIterator {
    current: usize,
    mismatches: *const Mismatches,
}

impl MismatchesIterator {
    fn next(&mut self) -> usize {
        let idx = self.current;
        self.current += 1;
        idx
    }
}
<|endoftext|>