mongo_driver 0.16.3

Mongo Rust driver built on top of the Mongo C driver
//! This driver is a thin wrapper around the production-ready [Mongo C driver](https://github.com/mongodb/mongo-c-driver).
//!
//! It aims to provide a safe and ergonomic Rust interface which handles all the gnarly usage details of
//! the C driver for you. We use Rust's type system to make sure that we can only use the
//! underlying C driver in the recommended way specified in it's [documentation](http://mongoc.org/libmongoc/current/).
//!
//! To get started create a client pool wrapped in an `Arc` so we can share it between threads. Then pop a client from it
//! you can use to perform operations.
//!
//! # Example
//!
//! ```no_run
//! use std::sync::Arc;
//! use mongo_driver::client::{ClientPool,Uri};
//!
//! let uri = Uri::new("mongodb://localhost:27017/").unwrap();
//! let pool = Arc::new(ClientPool::new(uri.clone(), None));
//! let client = pool.pop();
//! client.get_server_status(None).unwrap();
//! ```
//!
//! See the documentation for the available modules to find out how you can use the driver beyond
//! this.

extern crate libc;
extern crate mongoc_sys as mongoc;

#[macro_use]
extern crate bson;

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;
extern crate serde;

use std::ffi::CStr;
use std::ptr;
use std::result;
use std::sync::Once;

use crate::mongoc::bindings;

pub mod client;
pub mod collection;
pub mod cursor;
pub mod database;
pub mod flags;
pub mod read_prefs;
pub mod write_concern;

mod bsonc;
mod error;

pub use crate::error::{MongoError,BsoncError,MongoErrorDomain,MongoErrorCode,InvalidParamsError,BulkOperationError};

/// Result that's used in all functions that perform operations on the database.
pub type Result<T> = result::Result<T, MongoError>;

/// Result that's used in bulk operations.
pub type BulkOperationResult<T> = result::Result<T, BulkOperationError>;

static MONGOC_INIT: Once = Once::new();

/// Init mongo driver, needs to be called once before doing
/// anything else.
fn init() {
    MONGOC_INIT.call_once(|| {
        unsafe {
            // Init mongoc subsystem
            bindings::mongoc_init();

            // Set mongoc log handler
            bindings::mongoc_log_set_handler(
                Some(mongoc_log_handler),
                ptr::null_mut()
            );
        }
    });
}

unsafe extern "C" fn mongoc_log_handler(
    log_level:  bindings::mongoc_log_level_t,
    log_domain: *const ::libc::c_char,
    message:    *const ::libc::c_char,
    _:          *mut ::libc::c_void
) {
    let log_domain_str = CStr::from_ptr(log_domain).to_string_lossy();
    let message_str = CStr::from_ptr(message).to_string_lossy();
    let log_line = format!("mongoc: {} - {}", log_domain_str, message_str);

    match log_level {
        bindings::MONGOC_LOG_LEVEL_ERROR    => error!("{}", log_line),
        bindings::MONGOC_LOG_LEVEL_CRITICAL => error!("{}", log_line),
        bindings::MONGOC_LOG_LEVEL_WARNING  => warn!("{}", log_line),
        bindings::MONGOC_LOG_LEVEL_MESSAGE  => info!("{}", log_line),
        bindings::MONGOC_LOG_LEVEL_INFO     => info!("{}", log_line),
        bindings::MONGOC_LOG_LEVEL_DEBUG    => debug!("{}", log_line),
        bindings::MONGOC_LOG_LEVEL_TRACE    => trace!("{}", log_line),
        _ => panic!("Unknown mongoc log level")
    }
}

/// Options to configure both command and find operations.
pub struct CommandAndFindOptions {
    /// Flags to use
    pub query_flags: flags::Flags<flags::QueryFlag>,
    /// Number of documents to skip, zero to ignore
    pub skip:        u32,
    /// Max number of documents to return, zero to ignore
    pub limit:       u32,
    /// Number of documents in each batch, zero to ignore (default is 100)
    pub batch_size:  u32,
    /// Fields to return, not all commands support this option
    pub fields:      Option<bson::Document>,
    /// Read prefs to use
    pub read_prefs:  Option<read_prefs::ReadPrefs>
}

impl CommandAndFindOptions {
    /// Default options used if none are provided.
    pub fn default() -> CommandAndFindOptions {
        CommandAndFindOptions {
            query_flags: flags::Flags::new(),
            skip:        0,
            limit:       0,
            batch_size:  0,
            fields:      None,
            read_prefs:  None
        }
    }

    pub fn with_fields(fields: bson::Document) -> CommandAndFindOptions {
        CommandAndFindOptions {
            query_flags: flags::Flags::new(),
            skip:        0,
            limit:       0,
            batch_size:  0,
            fields:      Some(fields),
            read_prefs:  None
        }
    }

    fn fields_bsonc(&self) -> Option<bsonc::Bsonc> {
        match self.fields {
            Some(ref f) => Some(bsonc::Bsonc::from_document(f).unwrap()),
            None => None
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_init() {
        super::init();
        super::init();
    }
}