use crate::*;
use bson;
use bson::Bson;
use libc;
use std::ffi;
#[repr(C)]
pub struct wrapped_bson {
pub value: *mut ffi::c_void,
pub value_length: usize,
}
impl wrapped_bson {
pub fn new_success(result: &Bson) -> wrapped_bson {
wrapped_bson::from(bson::doc! {
"success": true,
"result": result
})
}
pub fn new_success_null() -> wrapped_bson {
wrapped_bson::new_success(&Bson::Null)
}
pub fn new_delete_result(result: DeleteResult) -> wrapped_bson {
wrapped_bson::from(bson::doc! {
"success": true,
"result": {
"nDeleted": result.n_deleted as i64,
}
})
}
pub fn new_update_result(result: UpdateResult) -> wrapped_bson {
let upserted_id = match result.upserted_id {
Some(id) => id,
None => Bson::Null,
};
wrapped_bson::from(bson::doc! {
"success": true,
"result": {
"matchedCount": result.matched_count as i64,
"modifiedCount": result.modified_count as i64,
"upsertedId": upserted_id,
}
})
}
pub fn new_insert_one_result(result: InsertOneResult) -> wrapped_bson {
wrapped_bson::from(bson::doc! {
"success": true,
"result": {
"insertedId": result.inserted_id,
}
})
}
pub fn new_insert_many_result(result: InsertManyResult) -> wrapped_bson {
wrapped_bson::from(bson::doc! {
"success": true,
"result": {
"insertedIds": Bson::Array(result.inserted_ids),
}
})
}
pub fn new_error(error_message: &str) -> wrapped_bson {
wrapped_bson::from(bson::doc! {
"success": false,
"errorMessage": error_message
})
}
pub fn consume_into_document(self) -> bson::Document {
let as_slice =
unsafe { std::slice::from_raw_parts(self.value as *mut u8, self.value_length) };
bson::Document::from_reader(as_slice).unwrap()
}
}
impl From<bson::Document> for wrapped_bson {
fn from(document: bson::Document) -> Self {
unsafe {
let bytes_vec = bson::ser::to_vec(&document).unwrap();
let bytes_c = libc::malloc(bytes_vec.len());
for ii in 0..bytes_vec.len() {
*(bytes_c as *mut u8).offset(ii as isize) = bytes_vec[ii];
}
wrapped_bson {
value: bytes_c,
value_length: bytes_vec.len(),
}
}
}
}
impl Drop for wrapped_bson {
fn drop(&mut self) {
unsafe {
libc::free(self.value);
}
}
}
unsafe fn get_collection<'a>(
db: &'a mut Database,
collection_name: *const libc::c_char,
) -> Result<&'a mut Collection, String> {
let collection_name = match ffi::CStr::from_ptr(collection_name).to_str() {
Ok(s) => s,
Err(_) => return Err("The collection name is not a valid UTF-8 C-String".to_string()),
};
Ok(db.collection_mut(collection_name))
}
unsafe fn get_filter(filter: wrapped_bson) -> Result<FindQuery, String> {
let filter = filter.consume_into_document();
FindQuery::parse_bson(filter)
}
unsafe fn get_update(filter: wrapped_bson) -> Result<UpdateQuery, String> {
let filter = filter.consume_into_document();
UpdateQuery::parse_bson(filter)
}
unsafe fn get_projection<'a>(projection: wrapped_bson) -> Result<Projection, String> {
let projection = projection.consume_into_document();
let projection: &Bson = match projection.get("projection") {
Some(projection) => projection,
None => return Err("The projection parameter does not contain a projection".to_string()),
};
Projection::parse_bson(projection)
}
unsafe fn get_sort(sort: wrapped_bson) -> Result<Sort, String> {
let sort = sort.consume_into_document();
let sort: &Bson = match sort.get("sort") {
Some(sort) => sort,
None => return Err("The sort parameter does not contain a sort order.".to_string()),
};
Sort::parse_bson(sort)
}
fn parse_compression(compression: u32) -> Result<Compression, String> {
match compression {
0 => Ok(Compression::None),
1 => Ok(Compression::Zip),
_ => Err("The compression parameter is not a valid compression type.".to_string()),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_test_function(value: usize) -> usize {
value + 1
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_get_metadata() -> wrapped_bson {
wrapped_bson::from(bson::doc! {
"version": env!("CARGO_PKG_VERSION")
})
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_malloc(n_bytes: usize) -> *mut ffi::c_void {
libc::malloc(n_bytes)
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_free(value: *mut ffi::c_void) {
libc::free(value);
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_new_empty() -> *mut ffi::c_void {
let db = libc::malloc(std::mem::size_of::<Database>()) as *mut Database;
db.write(Database::new_empty());
db as *mut ffi::c_void
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_free(db: *mut ffi::c_void) {
let db = db as *mut Database;
db.drop_in_place();
libc::free(db as *mut libc::c_void);
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_populate_from_bson_value(
db: *mut ffi::c_void,
contents: wrapped_bson,
) -> wrapped_bson {
let contents = contents.consume_into_document();
let db = db as *mut Database;
match Database::new_from_bson_value(&contents.into()) {
Ok(new_db) => {
db.write(new_db);
wrapped_bson::new_success_null()
}
Err(error) => wrapped_bson::new_error(&error),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_populate_from_bson_file(
db: *mut ffi::c_void,
file_name: *const libc::c_char,
compression: u32,
) -> wrapped_bson {
let file_name = match ffi::CStr::from_ptr(file_name).to_str() {
Ok(s) => s,
Err(_) => return wrapped_bson::new_error("The file name is not a valid UTF-8 C-String"),
};
let compression = match parse_compression(compression) {
Ok(compression) => compression,
Err(error) => return wrapped_bson::new_error(&error),
};
let db = db as *mut Database;
let res = match Database::new_from_bson_file(&file_name, compression) {
Ok(new_db) => {
db.write(new_db);
wrapped_bson::new_success_null()
}
Err(error) => wrapped_bson::new_error(&error),
};
res
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_populate_from_json_string(
db: *mut ffi::c_void,
contents: wrapped_bson,
) -> wrapped_bson {
let args = contents.consume_into_document();
let contents = match args.get_str("contents") {
Ok(contents) => contents,
Err(_) => return wrapped_bson::new_error("Missing an argument for `contents`."),
};
let db = db as *mut Database;
let res = match Database::new_from_json_string(&contents) {
Ok(new_db) => {
db.write(new_db);
wrapped_bson::new_success_null()
}
Err(error) => wrapped_bson::new_error(&error),
};
res
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_populate_from_json_file(
db: *mut ffi::c_void,
file_name: *const libc::c_char,
compression: u32,
) -> wrapped_bson {
let file_name = match ffi::CStr::from_ptr(file_name).to_str() {
Ok(s) => s,
Err(_) => return wrapped_bson::new_error("The file name is not a valid UTF-8 C-String"),
};
let compression = match parse_compression(compression) {
Ok(compression) => compression,
Err(error) => return wrapped_bson::new_error(&error),
};
let db = db as *mut Database;
let res = match Database::new_from_json_file(&file_name, compression) {
Ok(new_db) => {
db.write(new_db);
wrapped_bson::new_success_null()
}
Err(error) => wrapped_bson::new_error(&error),
};
res
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_dump_to_json_file(
db: *mut ffi::c_void,
path: *const libc::c_char,
relaxed: bool,
format: bool,
n_backups: u32,
compression: u32,
) -> wrapped_bson {
let db = db as *mut Database;
let path = match ffi::CStr::from_ptr(path).to_str() {
Ok(path) => path,
Err(_) => return wrapped_bson::new_error("The path is not a valid UTF-8 C-String."),
};
let compression = match parse_compression(compression) {
Ok(compression) => compression,
Err(error) => return wrapped_bson::new_error(&error),
};
match (*db).dump_to_json_file(&path, relaxed, format, n_backups, compression) {
Ok(_) => wrapped_bson::new_success_null(),
Err(error) => wrapped_bson::new_error(&error),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_dump_to_json_string(
db: *mut ffi::c_void,
relaxed: bool,
format: bool,
) -> wrapped_bson {
let db = db as *mut Database;
match (*db).dump_to_json_string(relaxed, format) {
Ok(result) => wrapped_bson::new_success(&bson::bson!(result)),
Err(error) => wrapped_bson::new_error(&error),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_dump_to_bson_file(
db: *mut ffi::c_void,
path: *const libc::c_char,
n_backups: u32,
compression: u32,
) -> wrapped_bson {
let db = db as *mut Database;
let path = match ffi::CStr::from_ptr(path).to_str() {
Ok(path) => path,
Err(_) => return wrapped_bson::new_error("The path is not a valid UTF-8 C-String."),
};
let compression = match parse_compression(compression) {
Ok(compression) => compression,
Err(error) => return wrapped_bson::new_error(&error),
};
match (*db).dump_to_bson_file(&path, n_backups, compression) {
Ok(_) => wrapped_bson::new_success_null(),
Err(error) => wrapped_bson::new_error(&error),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_dump_to_bson_value(db: *mut ffi::c_void) -> wrapped_bson {
let db = db as *mut Database;
wrapped_bson::new_success(&(*db).dump_to_bson_value().into())
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_drop_collection(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
) -> wrapped_bson {
let db = db as *mut Database;
let collection_name = match ffi::CStr::from_ptr(collection_name).to_str() {
Ok(s) => s,
Err(_) => {
return wrapped_bson::new_error("The collection name is not a valid UTF-8 C-String")
}
};
(*db).drop_collection(collection_name);
wrapped_bson::new_success_null()
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_n_collections(db: *mut ffi::c_void) -> wrapped_bson {
let db = db as *mut Database;
wrapped_bson::new_success(&bson::bson!((*db).n_collections() as i64))
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_db_collection_names(db: *mut ffi::c_void) -> wrapped_bson {
let db = db as *mut Database;
let names_bson = (*db)
.collection_names()
.into_iter()
.map(|name| Bson::String(name))
.collect();
wrapped_bson::new_success(&Bson::Array(names_bson))
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_count_all_documents(
db: *mut ffi::c_void,
collection: *const libc::c_char,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match ffi::CStr::from_ptr(collection).to_str() {
Ok(collection) => collection,
Err(_) => {
return wrapped_bson::new_error("The collection name is not a valid UTF-8 C-String.")
}
};
let collection = (*db).collection_mut(collection);
wrapped_bson::new_success(&bson::bson!(collection.len() as i64))
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_count_documents(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
filter: wrapped_bson,
skip: usize,
limit: usize,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let filter = match get_filter(filter) {
Ok(filter) => filter,
Err(message) => return wrapped_bson::new_error(&message),
};
match collection.count_documents(&filter, skip, limit) {
Ok(result) => wrapped_bson::new_success(&bson::bson!(result as i64)),
Err(message) => wrapped_bson::new_error(&message),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_delete_many(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
filter: wrapped_bson,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let filter = match get_filter(filter) {
Ok(filter) => filter,
Err(message) => return wrapped_bson::new_error(&message),
};
match collection.delete_many(&filter) {
Ok(result) => wrapped_bson::new_delete_result(result),
Err(message) => wrapped_bson::new_error(&message),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_delete_one(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
filter: wrapped_bson,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let filter = match get_filter(filter) {
Ok(filter) => filter,
Err(message) => return wrapped_bson::new_error(&message),
};
match collection.delete_one(&filter) {
Ok(result) => wrapped_bson::new_delete_result(result),
Err(message) => wrapped_bson::new_error(&message),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_find(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
filter: wrapped_bson,
projection: wrapped_bson,
skip: usize,
limit: usize,
sort: wrapped_bson,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let filter = match get_filter(filter) {
Ok(filter) => filter,
Err(message) => return wrapped_bson::new_error(&message),
};
let projection = match get_projection(projection) {
Ok(projection) => projection,
Err(message) => return wrapped_bson::new_error(&message),
};
let sort = match get_sort(sort) {
Ok(sort) => sort,
Err(message) => return wrapped_bson::new_error(&message),
};
let result: Vec<Bson> = collection
.find(&filter, &projection, skip, limit, &sort)
.into_iter()
.map(|doc| Bson::Document(doc))
.collect();
wrapped_bson::new_success(&Bson::Array(result))
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_find_one(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
filter: wrapped_bson,
projection: wrapped_bson,
skip: usize,
sort: wrapped_bson,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let filter = match get_filter(filter) {
Ok(filter) => filter,
Err(message) => return wrapped_bson::new_error(&message),
};
let projection = match get_projection(projection) {
Ok(projection) => projection,
Err(message) => return wrapped_bson::new_error(&message),
};
let sort = match get_sort(sort) {
Ok(sort) => sort,
Err(message) => return wrapped_bson::new_error(&message),
};
match collection.find_one(&filter, &projection, skip, &sort) {
Some(doc) => wrapped_bson::new_success(&Bson::Document(doc)),
None => wrapped_bson::new_success_null(),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_insert_one(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
document: wrapped_bson,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let document = document.consume_into_document();
match collection.insert_one(document) {
Ok(result) => wrapped_bson::new_insert_one_result(result),
Err(message) => wrapped_bson::new_error(&message),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_insert_many(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
documents: wrapped_bson,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let raw_documents: Vec<Bson> = match documents.consume_into_document().get_array("documents") {
Ok(documents) => documents.clone(), Err(_) => return wrapped_bson::new_error("Invalid documents argument."),
};
let mut documents: Vec<bson::Document> = Vec::new();
for document in raw_documents {
match document {
Bson::Document(document) => documents.push(document),
_ => return wrapped_bson::new_error("The values to insert have to be documents."),
}
}
match collection.insert_many(documents) {
Ok(result) => wrapped_bson::new_insert_many_result(result),
Err(message) => wrapped_bson::new_error(&message),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_replace_one(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
filter: wrapped_bson,
replacement: wrapped_bson,
upsert: bool,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let filter = match get_filter(filter) {
Ok(filter) => filter,
Err(message) => return wrapped_bson::new_error(&message),
};
let replacement = wrapped_bson::consume_into_document(replacement);
match collection.replace_one(&filter, replacement, upsert) {
Ok(result) => wrapped_bson::new_update_result(result),
Err(message) => wrapped_bson::new_error(&message),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_update_one(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
filter: wrapped_bson,
update: wrapped_bson,
upsert: bool,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let filter = match get_filter(filter) {
Ok(filter) => filter,
Err(message) => return wrapped_bson::new_error(&message),
};
let update = match get_update(update) {
Ok(update) => update,
Err(message) => return wrapped_bson::new_error(&message),
};
match collection.update_one(&filter, &update, upsert) {
Ok(result) => wrapped_bson::new_update_result(result),
Err(message) => wrapped_bson::new_error(&message),
}
}
#[no_mangle]
pub unsafe extern "C" fn notmongo_collection_update_many(
db: *mut ffi::c_void,
collection_name: *const libc::c_char,
filter: wrapped_bson,
update: wrapped_bson,
upsert: bool,
) -> wrapped_bson {
let db = db as *mut Database;
let collection = match get_collection(&mut *db, collection_name) {
Ok(collection) => collection,
Err(message) => return wrapped_bson::new_error(&message),
};
let filter = match get_filter(filter) {
Ok(filter) => filter,
Err(message) => return wrapped_bson::new_error(&message),
};
let update = match get_update(update) {
Ok(update) => update,
Err(message) => return wrapped_bson::new_error(&message),
};
match collection.update_many(&filter, &update, upsert) {
Ok(result) => wrapped_bson::new_update_result(result),
Err(message) => wrapped_bson::new_error(&message),
}
}