diff --git a/src/mongocxx/lib/CMakeLists.txt b/src/mongocxx/lib/CMakeLists.txt index fbf89fac90..1ced1a37e9 100644 --- a/src/mongocxx/lib/CMakeLists.txt +++ b/src/mongocxx/lib/CMakeLists.txt @@ -13,10 +13,10 @@ # limitations under the License. set(mongocxx_sources_private - mongocxx/private/bson.cpp mongocxx/private/conversions.cpp mongocxx/private/mongoc.cpp mongocxx/private/numeric_casting.cpp + mongocxx/private/scoped_bson.cpp ) set(mongocxx_sources_v_noabi @@ -255,7 +255,6 @@ set_dist_list(src_mongocxx_lib_DIST ${mongocxx_sources_v_noabi} ${mongocxx_sources_v1} mongocxx/private/append_aggregate_options.hh - mongocxx/private/bson.hh mongocxx/private/bulk_write.hh mongocxx/private/change_stream.hh mongocxx/private/client_encryption.hh @@ -277,6 +276,7 @@ set_dist_list(src_mongocxx_lib_DIST mongocxx/private/read_concern.hh mongocxx/private/read_preference.hh mongocxx/private/scoped_bson_value.hh + mongocxx/private/scoped_bson.hh mongocxx/private/search_index_model.hh mongocxx/private/search_index_view.hh mongocxx/private/ssl.hh @@ -289,6 +289,7 @@ set_dist_list(src_mongocxx_lib_DIST mongocxx/v_noabi/mongocxx/options/server_api.hh mongocxx/v_noabi/mongocxx/options/tls.hh mongocxx/v_noabi/mongocxx/options/transaction.hh + mongocxx/v_noabi/mongocxx/scoped_bson.hh mongocxx/v1/config/config.hpp.in mongocxx/v1/config/version.hpp.in ) diff --git a/src/mongocxx/lib/mongocxx/private/bson.cpp b/src/mongocxx/lib/mongocxx/private/bson.cpp deleted file mode 100644 index b7b8309248..0000000000 --- a/src/mongocxx/lib/mongocxx/private/bson.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2009-present MongoDB, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace mongocxx { -namespace libbson { - -namespace { - -void doc_to_bson_t(bsoncxx::v_noabi::document::view const& doc, bson_t* bson) { - // While bson_init_static is documented as returning false if the bson_t was unable to be - // initialized, this only occurs when the length of the data passed in is less than five. We - // assume that the data from the bsoncxx::v_noabi::document::view is valid and that - // bson_init_static will not be changed to fail to initialize the bson_t in any other case. - bson_init_static(bson, doc.data(), doc.length()); -} - -} // namespace - -scoped_bson_t::scoped_bson_t(bsoncxx::document::view_or_value doc) : _is_initialized{true}, _doc{std::move(doc)} { - doc_to_bson_t(*_doc, &_bson); -} - -void scoped_bson_t::init_from_static(bsoncxx::document::view_or_value doc) { - _is_initialized = true; - _doc = std::move(doc); - doc_to_bson_t(*_doc, &_bson); -} - -scoped_bson_t::scoped_bson_t(bsoncxx::document::view doc) : scoped_bson_t(bsoncxx::document::view_or_value(doc)) {} - -void scoped_bson_t::init_from_static(bsoncxx::document::view doc) { - this->init_from_static(bsoncxx::document::view_or_value(doc)); -} - -scoped_bson_t::scoped_bson_t(bsoncxx::document::value doc) - : scoped_bson_t(bsoncxx::document::view_or_value(std::move(doc))) {} - -void scoped_bson_t::init_from_static(bsoncxx::document::value doc) { - this->init_from_static(bsoncxx::document::view_or_value(std::move(doc))); -} - -scoped_bson_t::scoped_bson_t(bsoncxx::v_noabi::stdx::optional doc) { - if (doc) { - this->init_from_static(std::move(*doc)); - } -} - -void scoped_bson_t::init_from_static(bsoncxx::v_noabi::stdx::optional doc) { - if (doc) { - this->init_from_static(std::move(*doc)); - } -} - -void scoped_bson_t::init() { - _is_initialized = true; - bson_init(&_bson); -} - -void scoped_bson_t::flag_init() { - _is_initialized = true; -} - -scoped_bson_t::scoped_bson_t() : _is_initialized(false) {} - -scoped_bson_t::~scoped_bson_t() { - if (_is_initialized) { - bson_destroy(&_bson); - } -} - -bson_t* scoped_bson_t::bson() { - return _is_initialized ? &_bson : nullptr; -} - -bson_t* scoped_bson_t::bson_for_init() { - // C driver doesn't always return reply initted, so run an extra init - init(); - return &_bson; -} - -bsoncxx::v_noabi::document::view scoped_bson_t::view() { - // if we were initialized with a view_or_value just use that view - if (_doc) { - return _doc->view(); - } - // otherwise, if we were initialized from libmongoc, construct - if (_is_initialized) { - return bsoncxx::v_noabi::document::view{bson_get_data(bson()), bson()->len}; - } - // otherwise, return an empty view - return bsoncxx::v_noabi::document::view{}; -} - -namespace { - -void bson_free_deleter(std::uint8_t* ptr) { - bson_free(ptr); -} - -} // anonymous namespace - -bsoncxx::v_noabi::document::value scoped_bson_t::steal() { - if (!_is_initialized) { - return bsoncxx::v_noabi::document::value{bsoncxx::v_noabi::document::view()}; - } - - std::uint32_t length; - std::uint8_t* buff = bson_destroy_with_steal(bson(), true, &length); - - _is_initialized = false; - - return bsoncxx::v_noabi::document::value(buff, length, bson_free_deleter); -} - -} // namespace libbson -} // namespace mongocxx diff --git a/src/mongocxx/lib/mongocxx/private/bson.hh b/src/mongocxx/lib/mongocxx/private/bson.hh deleted file mode 100644 index 97782cc9a1..0000000000 --- a/src/mongocxx/lib/mongocxx/private/bson.hh +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2009-present MongoDB, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include - -#include - -#include - -namespace mongocxx { -namespace libbson { - -// -// Class that wraps and manages libmongoc's bson_t structures. It is useful for converting between -// mongocxx's bson::document::view() and libmongoc's bson_t when communicating with the underlying -// driver. It is an RAII style class that will destroy an initialized bson_t when destructed. -// -// Libmongoc's bson_destroy will not be called on the bson_t upon destruction unless either -// init(), flag_init(), init_from_static(), or bson_for_init() are called during a scoped_bson_t's -// lifetime after which the internal bson_t is considered initialized. -// -// Initialization of a scoped bson_t depends on how it is expected to be used. -// -// If the bson_t will be used in a read-only fashion then init_from_static should be called. -// -// If this bson_t will be used by a function that calls bson_init itself then flag_init() -// should be called after such use. If this bson_t will be used by a function that does -// not call init itself (expecting an already initialized bson_t) then init() could be called -// instead. -// -class scoped_bson_t { - public: - // - // Constructs a new scoped_bson_t having a non-initialized internal bson_t. - // - MONGOCXX_ABI_EXPORT_CDECL_TESTING() scoped_bson_t(); - - // - // Constructs a new scoped_bson_t from the provided document. - // - // The internal bson_t is considered initialized. - // - explicit MONGOCXX_ABI_EXPORT_CDECL_TESTING() scoped_bson_t(bsoncxx::document::view_or_value doc); - - // - // Initializes a bson_t from the provided document. - // - // The internal bson_t is considered initialized. - // - MONGOCXX_ABI_EXPORT_CDECL_TESTING(void) init_from_static(bsoncxx::document::view_or_value doc); - - // - // Constructs a new scoped_bson_t from the provided document. - // - // The internal bson_t is considered initialized. - // - explicit MONGOCXX_ABI_EXPORT_CDECL_TESTING() scoped_bson_t(bsoncxx::document::view doc); - - // - // Initializes a bson_t from the provided document. - // - // The internal bson_t is considered initialized. - // - MONGOCXX_ABI_EXPORT_CDECL_TESTING(void) init_from_static(bsoncxx::document::view doc); - - // - // Constructs a new scoped_bson_t from the provided document. - // - // The internal bson_t is considered initialized. - // - explicit MONGOCXX_ABI_EXPORT_CDECL_TESTING() scoped_bson_t(bsoncxx::document::value doc); - - // - // Initializes a bson_t from the provided document. - // - // The internal bson_t is considered initialized. - // - MONGOCXX_ABI_EXPORT_CDECL_TESTING(void) init_from_static(bsoncxx::document::value doc); - - // - // Constructs a new scoped_bson_t from the provided optional document. - // - // The internal bson_t is initialized if the optional contains a document. - // - explicit MONGOCXX_ABI_EXPORT_CDECL_TESTING() scoped_bson_t( - bsoncxx::v_noabi::stdx::optional doc); - - // - // Initializes a bson_t from the provided optional document. - // - // The internal bson_t is initialized if the optional contains a document. - // - MONGOCXX_ABI_EXPORT_CDECL_TESTING(void) - init_from_static(bsoncxx::v_noabi::stdx::optional doc); - - // - // Initialize the internal bson_t. - // - // This is equivalent to calling libmongoc's bson_init() and informing this scoped_bson_t - // instance that it should call bson_destroy on the internal bson_t when destructed. - // - MONGOCXX_ABI_EXPORT_CDECL_TESTING(void) init(); - - // - // Marks this bson_t as initialized (presumably by another libmongoc function). - // - // This C++ class has no way of knowing that the C driver has initialized this bson_t - // internally (possibly as a side effect of a function call) so this is a way of explictly - // saying so. - // - MONGOCXX_ABI_EXPORT_CDECL_TESTING(void) flag_init(); - - MONGOCXX_ABI_EXPORT_CDECL_TESTING() ~scoped_bson_t(); - - scoped_bson_t(scoped_bson_t const& rhs) = delete; - scoped_bson_t& operator=(scoped_bson_t const& rhs) = delete; - scoped_bson_t(scoped_bson_t&& rhs) = delete; - scoped_bson_t& operator=(scoped_bson_t&& rhs) = delete; - - // - // Get a pointer to the wrapped internal bson_t structure. If not - // initialized, nullptr is returned. To use this method to take - // ownership of a bson_t (by passing the pointer returned here as the - // output argument of another function), be sure to call flag_init() - // first. - // - MONGOCXX_ABI_EXPORT_CDECL_TESTING(bson_t*) bson(); - - // - // First calls flag_init() then returns a pointer to the wrapped internal bson_t structure. - // - MONGOCXX_ABI_EXPORT_CDECL_TESTING(bson_t*) bson_for_init(); - - MONGOCXX_ABI_EXPORT_CDECL_TESTING(bsoncxx::v_noabi::document::view) view(); - MONGOCXX_ABI_EXPORT_CDECL_TESTING(bsoncxx::v_noabi::document::value) steal(); - - private: - bson_t _bson; - bool _is_initialized = false; - - // If we are passed a value created on-the-fly, we'll need to own this. - bsoncxx::v_noabi::stdx::optional _doc; -}; - -} // namespace libbson -} // namespace mongocxx diff --git a/src/mongocxx/lib/mongocxx/private/change_stream.hh b/src/mongocxx/lib/mongocxx/private/change_stream.hh index 4897c8f880..9861cba5af 100644 --- a/src/mongocxx/lib/mongocxx/private/change_stream.hh +++ b/src/mongocxx/lib/mongocxx/private/change_stream.hh @@ -20,7 +20,8 @@ #include #include -#include +#include + #include #include @@ -77,22 +78,20 @@ class change_stream::impl { } void advance_iterator() { - bson_t const* out; + scoped_bson_view doc; // Happy-case. - if (libmongoc::change_stream_next(this->change_stream_, &out)) { - this->doc_ = bsoncxx::v_noabi::document::view{bson_get_data(out), out->len}; + if (libmongoc::change_stream_next(this->change_stream_, doc.out_ptr())) { + this->doc_ = doc.view(); return; } // Check for errors or just nothing left. bson_error_t error; - if (libmongoc::change_stream_error_document(this->change_stream_, &error, &out)) { + if (libmongoc::change_stream_error_document(this->change_stream_, &error, doc.out_ptr())) { this->mark_dead(); this->doc_ = bsoncxx::v_noabi::document::view{}; - mongocxx::libbson::scoped_bson_t scoped_error_reply{}; - bson_copy_to(out, scoped_error_reply.bson_for_init()); - throw_exception(scoped_error_reply.steal(), error); + throw_exception(bsoncxx::v_noabi::from_v1(doc.value()), error); } // Just nothing left. diff --git a/src/mongocxx/lib/mongocxx/private/client_encryption.hh b/src/mongocxx/lib/mongocxx/private/client_encryption.hh index 3d2111af27..fe1b3ed493 100644 --- a/src/mongocxx/lib/mongocxx/private/client_encryption.hh +++ b/src/mongocxx/lib/mongocxx/private/client_encryption.hh @@ -25,10 +25,11 @@ #include #include +#include + #include #include -#include #include #include #include @@ -40,8 +41,6 @@ namespace v_noabi { class client_encryption::impl { private: - using scoped_bson_t = mongocxx::libbson::scoped_bson_t; - struct encrypt_opts_deleter { void operator()(mongoc_client_encryption_encrypt_opts_t* ptr) noexcept { libmongoc::client_encryption_encrypt_opts_destroy(ptr); @@ -126,19 +125,14 @@ class client_encryption::impl { auto const encrypt_opts = encrypt_opts_ptr(static_cast(opts.convert())); - scoped_bson_t encrypted; bson_error_t error = {}; + scoped_bson encrypted; if (!libmongoc::client_encryption_encrypt_expression( - _client_encryption.get(), - scoped_bson_t(expr).bson(), - encrypt_opts.get(), - encrypted.bson_for_init(), - &error)) { + _client_encryption.get(), to_scoped_bson_view(expr), encrypt_opts.get(), encrypted.out_ptr(), &error)) { throw_exception(error); } - - return encrypted.steal(); + return from_v1(std::move(encrypted)); } bsoncxx::v_noabi::types::bson_value::value decrypt(bsoncxx::v_noabi::types::bson_value::view value) { @@ -173,19 +167,19 @@ class client_encryption::impl { auto const provider_terminated = opts.provider().terminated(); - scoped_bson_t bson_master_key; + scoped_bson_view bson_master_key{nullptr}; - if (auto const master_key_opt = opts.master_key()) { - bson_master_key.init_from_static(master_key_opt->view()); + if (auto const& master_key_opt = opts.master_key()) { + bson_master_key = to_scoped_bson_view(master_key_opt->view()); } bson_error_t error; if (!libmongoc::client_encryption_rewrap_many_datakey( _client_encryption.get(), - scoped_bson_t(filter).bson(), + to_scoped_bson_view(filter), provider_terminated.view().empty() ? nullptr : provider_terminated.data(), - bson_master_key.bson(), + bson_master_key, result.get(), &error)) { throw_exception(error); @@ -206,11 +200,11 @@ class client_encryption::impl { using bsoncxx::v_noabi::builder::basic::kvp; using bsoncxx::v_noabi::builder::basic::make_document; - scoped_bson_t reply; bson_error_t error; + scoped_bson reply; if (!libmongoc::client_encryption_delete_key( - _client_encryption.get(), detail::scoped_bson_value(id.view()).get(), reply.bson_for_init(), &error)) { + _client_encryption.get(), detail::scoped_bson_value(id.view()).get(), reply.out_ptr(), &error)) { throw_exception(error); } @@ -228,20 +222,19 @@ class client_encryption::impl { bsoncxx::v_noabi::stdx::optional get_key( bsoncxx::v_noabi::types::bson_value::view_or_value id) { - libbson::scoped_bson_t key_doc; bson_error_t error; + scoped_bson key; if (!libmongoc::client_encryption_get_key( - _client_encryption.get(), - detail::scoped_bson_value(id.view()).get(), - key_doc.bson_for_init(), - &error)) { + _client_encryption.get(), detail::scoped_bson_value(id.view()).get(), key.out_ptr(), &error)) { throw_exception(error); } - return key_doc.view().empty() - ? bsoncxx::v_noabi::stdx::nullopt - : bsoncxx::v_noabi::stdx::optional{key_doc.steal()}; + if (key.view().empty()) { + return {}; + } + + return from_v1(std::move(key)); } mongocxx::v_noabi::cursor get_keys() { @@ -259,56 +252,62 @@ class client_encryption::impl { bsoncxx::v_noabi::stdx::optional add_key_alt_name( bsoncxx::v_noabi::types::bson_value::view_or_value id, bsoncxx::v_noabi::string::view_or_value key_alt_name) { - scoped_bson_t key_doc; bson_error_t error; + scoped_bson key; if (!libmongoc::client_encryption_add_key_alt_name( _client_encryption.get(), detail::scoped_bson_value(id.view()).get(), key_alt_name.terminated().data(), - key_doc.bson_for_init(), + key.out_ptr(), &error)) { throw_exception(error); } - return key_doc.view().empty() - ? bsoncxx::v_noabi::stdx::nullopt - : bsoncxx::v_noabi::stdx::optional{key_doc.steal()}; + if (key.view().empty()) { + return {}; + } + + return from_v1(std::move(key)); } bsoncxx::v_noabi::stdx::optional get_key_by_alt_name( bsoncxx::v_noabi::string::view_or_value key_alt_name) { - scoped_bson_t key_doc; bson_error_t error; + scoped_bson key; if (!libmongoc::client_encryption_get_key_by_alt_name( - _client_encryption.get(), key_alt_name.terminated().data(), key_doc.bson_for_init(), &error)) { + _client_encryption.get(), key_alt_name.terminated().data(), key.out_ptr(), &error)) { throw_exception(error); } - return key_doc.view().empty() - ? bsoncxx::v_noabi::stdx::nullopt - : bsoncxx::v_noabi::stdx::optional{key_doc.steal()}; + if (key.view().empty()) { + return {}; + } + + return from_v1(std::move(key)); } bsoncxx::v_noabi::stdx::optional remove_key_alt_name( bsoncxx::v_noabi::types::bson_value::view_or_value id, bsoncxx::v_noabi::string::view_or_value key_alt_name) { - scoped_bson_t key_doc; bson_error_t error; + scoped_bson key; if (!libmongoc::client_encryption_remove_key_alt_name( _client_encryption.get(), detail::scoped_bson_value(id.view()).get(), key_alt_name.terminated().data(), - key_doc.bson_for_init(), + key.out_ptr(), &error)) { throw_exception(error); } - return key_doc.view().empty() - ? bsoncxx::v_noabi::stdx::nullopt - : bsoncxx::v_noabi::stdx::optional{key_doc.steal()}; + if (key.view().empty()) { + return {}; + } + + return from_v1(std::move(key)); } collection create_encrypted_collection( @@ -320,28 +319,23 @@ class client_encryption::impl { std::string const& kms_provider, bsoncxx::v_noabi::stdx::optional const& masterkey) { bson_error_t error = {}; - scoped_bson_t out_opts; - out_opts.init(); - bson_t* opt_mkey_ptr = nullptr; - scoped_bson_t opt_mkey; + scoped_bson_view opt_mkey{nullptr}; if (masterkey) { - opt_mkey.init_from_static(*masterkey); - opt_mkey_ptr = opt_mkey.bson(); + opt_mkey = to_scoped_bson_view(*masterkey); } - scoped_bson_t coll_opts{opts}; - + scoped_bson out; auto coll_ptr = libmongoc::client_encryption_create_encrypted_collection( _client_encryption.get(), db, coll_name.data(), - coll_opts.bson(), - out_opts.bson(), + to_scoped_bson_view(opts), + out.out_ptr(), kms_provider.data(), - opt_mkey_ptr, + opt_mkey, &error); - out_options = bsoncxx::helpers::value_from_bson_t(out_opts.bson()); + out_options = bsoncxx::helpers::value_from_bson_t(out); if (!coll_ptr) { throw_exception(error); } diff --git a/src/mongocxx/lib/mongocxx/private/client_session.hh b/src/mongocxx/lib/mongocxx/private/client_session.hh index 8534aae996..af309cd160 100644 --- a/src/mongocxx/lib/mongocxx/private/client_session.hh +++ b/src/mongocxx/lib/mongocxx/private/client_session.hh @@ -24,11 +24,11 @@ #include #include +#include #include #include -#include #include #include #include @@ -56,9 +56,8 @@ bool with_transaction_cpp_cb(mongoc_client_session_t*, void* ctx, bson_t** reply return true; } catch (operation_exception const& e) { make_bson_error(error, e); - if (e.raw_server_error()) { - libbson::scoped_bson_t raw{e.raw_server_error()->view()}; - *reply = bson_copy(raw.bson()); + if (auto const& raw = e.raw_server_error()) { + *reply = to_scoped_bson_view(*raw).copy(); } return false; } catch (...) { @@ -158,10 +157,10 @@ class client_session::impl { } void commit_transaction() { - libbson::scoped_bson_t reply; + scoped_bson reply; bson_error_t error; - if (!libmongoc::client_session_commit_transaction(_session_t.get(), reply.bson_for_init(), &error)) { - throw_exception(reply.steal(), error); + if (!libmongoc::client_session_commit_transaction(_session_t.get(), reply.out_ptr(), &error)) { + throw_exception(from_v1(std::move(reply)), error); } } @@ -178,18 +177,18 @@ class client_session::impl { with_transaction_ctx ctx{parent, std::move(cb), nullptr}; - libbson::scoped_bson_t reply; bson_error_t error; + scoped_bson reply; auto res = libmongoc::client_session_with_transaction( - session_t, &with_transaction_cpp_cb, opts_t, &ctx, reply.bson_for_init(), &error); + session_t, &with_transaction_cpp_cb, opts_t, &ctx, reply.out_ptr(), &error); if (!res) { if (ctx.eptr) { std::rethrow_exception(ctx.eptr); } - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } } diff --git a/src/mongocxx/lib/mongocxx/private/collection.hh b/src/mongocxx/lib/mongocxx/private/collection.hh index aa9f2d8032..2b8de3ecaa 100644 --- a/src/mongocxx/lib/mongocxx/private/collection.hh +++ b/src/mongocxx/lib/mongocxx/private/collection.hh @@ -22,7 +22,6 @@ #include -#include #include #include #include diff --git a/src/mongocxx/lib/mongocxx/private/index_view.hh b/src/mongocxx/lib/mongocxx/private/index_view.hh index 20a44de07a..3c83ab0c86 100644 --- a/src/mongocxx/lib/mongocxx/private/index_view.hh +++ b/src/mongocxx/lib/mongocxx/private/index_view.hh @@ -29,7 +29,8 @@ #include #include -#include +#include + #include #include @@ -44,9 +45,7 @@ class index_view::impl { impl(mongoc_collection_t* collection, mongoc_client_t* client) : _coll{collection}, _client{client} {} std::string get_index_name_from_keys(bsoncxx::v_noabi::document::view_or_value keys) { - libbson::scoped_bson_t keys_bson{keys}; - - auto name_from_keys = libmongoc::collection_keys_to_index_string(keys_bson.bson()); + auto name_from_keys = libmongoc::collection_keys_to_index_string(to_scoped_bson_view(keys)); std::string result{name_from_keys}; bson_free(name_from_keys); @@ -57,8 +56,7 @@ class index_view::impl { if (session) { bsoncxx::v_noabi::builder::basic::document options_builder; options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); - libbson::scoped_bson_t bson_options(options_builder.extract()); - return libmongoc::collection_find_indexes_with_opts(_coll, bson_options.bson()); + return libmongoc::collection_find_indexes_with_opts(_coll, to_scoped_bson_view(options_builder)); } return libmongoc::collection_find_indexes_with_opts(_coll, nullptr); @@ -126,7 +124,6 @@ class index_view::impl { document::view_or_value command = make_document( kvp("createIndexes", libmongoc::collection_get_name(_coll)), kvp("indexes", index_arr.view())); - libbson::scoped_bson_t reply; bson_error_t error; builder::basic::document opts_doc; @@ -161,17 +158,15 @@ class index_view::impl { command = make_document(concatenate(command), concatenate(options.commit_quorum()->view())); } - libbson::scoped_bson_t command_bson{command}; - libbson::scoped_bson_t opts_bson{opts_doc.view()}; - + scoped_bson reply; auto result = libmongoc::collection_write_command_with_opts( - _coll, command_bson.bson(), opts_bson.bson(), reply.bson_for_init(), &error); + _coll, to_scoped_bson_view(command), to_scoped_bson_view(opts_doc), reply.out_ptr(), &error); if (!result) { - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } - return reply.steal(); + return from_v1(std::move(reply)); } void drop_one( @@ -199,16 +194,14 @@ class index_view::impl { bsoncxx::v_noabi::document::value command = make_document(kvp("dropIndexes", libmongoc::collection_get_name(_coll)), kvp("index", name)); - libbson::scoped_bson_t reply; - libbson::scoped_bson_t command_bson{command.view()}; - libbson::scoped_bson_t opts_bson{opts_doc.view()}; bson_error_t error; + scoped_bson reply; bool result = libmongoc::collection_write_command_with_opts( - _coll, command_bson.bson(), opts_bson.bson(), reply.bson_for_init(), &error); + _coll, to_scoped_bson_view(command), to_scoped_bson_view(opts_doc), reply.out_ptr(), &error); if (!result) { - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } } @@ -216,11 +209,8 @@ class index_view::impl { bsoncxx::v_noabi::document::value command = make_document(kvp("dropIndexes", libmongoc::collection_get_name(_coll)), kvp("index", "*")); - libbson::scoped_bson_t reply; bson_error_t error; - libbson::scoped_bson_t command_bson{command.view()}; - bsoncxx::v_noabi::builder::basic::document opts_doc; if (options.max_time()) { @@ -235,13 +225,12 @@ class index_view::impl { opts_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - libbson::scoped_bson_t opts_bson{opts_doc.view()}; - + scoped_bson reply; bool result = libmongoc::collection_write_command_with_opts( - _coll, command_bson.bson(), opts_bson.bson(), reply.bson_for_init(), &error); + _coll, to_scoped_bson_view(command), to_scoped_bson_view(opts_doc), reply.out_ptr(), &error); if (!result) { - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } } diff --git a/src/mongocxx/lib/mongocxx/private/scoped_bson.cpp b/src/mongocxx/lib/mongocxx/private/scoped_bson.cpp new file mode 100644 index 0000000000..9cac44400f --- /dev/null +++ b/src/mongocxx/lib/mongocxx/private/scoped_bson.cpp @@ -0,0 +1,89 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +// + +#include +#include + +#include + +namespace mongocxx { + +scoped_bson& scoped_bson::operator+=(scoped_bson_view other) { + if (!_value) { + throw std::logic_error{"mongocxx::scoped_bson::operator+=: this->data() == nullptr"}; + } + + if (!other) { + throw std::logic_error{"mongocxx::scoped_bson::operator+=: other.data() == nullptr"}; + } + + auto const is_self_assignment = _value.data() == other.data(); + auto const is_bson_freeable = [&]() -> bool { + auto const deleter_ptr = _value.get_deleter().target(); + return deleter_ptr && *deleter_ptr == &bson_free; + }(); + + // Copy is required for strong exception safety or allocator compatibility. + if (is_self_assignment || !is_bson_freeable) { + bson_t bson = BSON_INITIALIZER; + + if (bson_concat(&bson, this->bson()) && bson_concat(&bson, other.bson())) { + return *this = scoped_bson{&bson}; // Ownership transfer. + } + + bson_destroy(&bson); + throw std::logic_error{"mongocxx::scoped_bson::operator+=: bson_new_from_data failed"}; + } + + // Compatible allocator: avoid an unnecessary copy by reusing the underlying BSON data. + else { + auto length = _value.length(); + + // Temporarily acquire ownership of underlying BSON data. + auto ptr = _value.release(); + + std::uint8_t* data = ptr.get(); + + // Conditional ownership transfer. + auto bson = bson_new_from_buffer(&data, &length, nullptr, nullptr); + + // Ownership transfer failed. + if (!bson) { + _value = bsoncxx::v1::document::value{std::move(ptr)}; // Strong exception safety. + throw std::logic_error{"mongocxx::scoped_bson::operator+=: bson_new_from_buffer failed"}; + } + + // Unset BSON_FLAG_NO_FREE: data is now owning. + bson->flags = 0; + + // Ownership transfer succeeded: fully release data. + (void)ptr.release(); + + auto const ret = bson_concat(bson, other.bson()); + + *this = scoped_bson{bson}; // Ownership transfer (success) + strong exception safety (failure). + + if (ret) { + return *this; + } + + throw std::logic_error{"mongocxx::scoped_bson::operator+=: bson_concat failed"}; + } +} + +} // namespace mongocxx diff --git a/src/mongocxx/lib/mongocxx/private/scoped_bson.hh b/src/mongocxx/lib/mongocxx/private/scoped_bson.hh new file mode 100644 index 0000000000..6373c80495 --- /dev/null +++ b/src/mongocxx/lib/mongocxx/private/scoped_bson.hh @@ -0,0 +1,364 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +namespace mongocxx { + +class scoped_bson_view { + private: + bsoncxx::v1::document::view _view; + bson_t _bson = {}; // Non-owning. + + public: + ~scoped_bson_view() = default; + + // Handled by the copy constructor. + // scoped_bson_view(scoped_bson_view&& other) noexcept = default; + + // Handled by the copy assignment operator. + // scoped_bson_view& operator=(scoped_bson_view&& other) noexcept = default; + + scoped_bson_view(scoped_bson_view const& other) noexcept : _view{other._view} { + this->sync_bson(); + } + + scoped_bson_view& operator=(scoped_bson_view const& other) noexcept { + _view = other._view; + this->sync_bson(); + return *this; + } + + // Initialize as an empty document. + scoped_bson_view() { + this->sync_bson(); + } + + // Prevent mistakenly creating a view of a temporary object: + // ```cpp + // scoped_bson_view v{BCON_NEW("x", "1")}; // Leak! + // ``` + explicit scoped_bson_view(bson_t*) = delete; + + explicit scoped_bson_view(bson_t const* v) : _view{v ? bson_get_data(v) : nullptr} { + this->sync_bson(); + } + + explicit scoped_bson_view(std::nullptr_t) : scoped_bson_view{static_cast(nullptr)} {} + + // Prevent mistakently creating a view of a temporary object. + explicit scoped_bson_view(bsoncxx::v1::document::value&&) = delete; + + /* explicit(false) */ scoped_bson_view(bsoncxx::v1::document::value const& v) : scoped_bson_view{v.view()} {} + + /* explicit(false) */ scoped_bson_view(bsoncxx::v1::document::view v) : _view{v} { + this->sync_bson(); + } + + std::uint8_t const* data() const { + return _view.data(); + } + + bson_t const* bson() const { + return _view ? &_bson : nullptr; + } + + /* explicit(false) */ operator bson_t const*() const { + return this->bson(); + } + + bsoncxx::v1::document::view view() const { + return _view; + } + + bsoncxx::v1::array::view array_view() const { + return bsoncxx::v1::array::view{_view.data()}; + } + + bsoncxx::v1::document::value value() const { + return bsoncxx::v1::document::value{_view}; + } + + // Return an owning copy. + bson_t* copy() const { + return _view ? bson_copy(&_bson) : nullptr; + } + + class out_ptr_type { + friend scoped_bson_view; + + private: + scoped_bson_view& _self; + bson_t const* _bson = nullptr; + + /* explicit(false) */ out_ptr_type(scoped_bson_view& self) : _self{self} {} + + public: + ~out_ptr_type() { + _self = scoped_bson_view{_bson}; + } + + out_ptr_type(out_ptr_type&&) = delete; + out_ptr_type& operator=(out_ptr_type&&) = delete; + out_ptr_type(out_ptr_type const&) = delete; + out_ptr_type& operator=(out_ptr_type const&) = delete; + + /* explicit(false) */ operator bson_t const**() && { + return &_bson; + } + + /* explicit(false) */ operator bson_t const*() const& = delete; + }; + + out_ptr_type out_ptr() & { + return {*this}; + } + + private: + void sync_bson() { + if (_view && !bson_init_static(&_bson, _view.data(), _view.length())) { + MONGOCXX_PRIVATE_UNREACHABLE; + } + } +}; + +class scoped_bson { + private: + bsoncxx::v1::document::value _value; + bson_t _bson = {}; // Non-owning. + + public: + ~scoped_bson() = default; + + scoped_bson(scoped_bson&& other) noexcept : _value{std::move(other._value)} { + this->sync_bson(); + other._bson = {}; + } + + scoped_bson& operator=(scoped_bson&& other) noexcept { + _value = std::move(other._value); + this->sync_bson(); + other._bson = {}; + return *this; + } + + scoped_bson(scoped_bson const& other) : _value{other._value} { + this->sync_bson(); + } + + scoped_bson& operator=(scoped_bson const& other) { + _value = other._value; + this->sync_bson(); + return *this; + } + + // Initialize as an empty document. + scoped_bson() { + this->sync_bson(); + } + + // Copy `v`. + explicit scoped_bson(scoped_bson_view v) : scoped_bson{v.view()} {} + + // Takes ownership of `v`. `v` is destroyed. + explicit scoped_bson(bson_t* v) + : _value{[&v]() -> bsoncxx::v1::document::value { + if (!v) { + return {nullptr, &bson_free}; + } else if (bson_empty(v)) { + bson_destroy(v); + return {}; // Avoid unnecessary allocations. + } else { + return {bson_destroy_with_steal(v, true, nullptr), &bson_free}; + } + }()} { + this->sync_bson(); + } + + // Copy `v`. + explicit scoped_bson(bson_t const* v) : scoped_bson{bsoncxx::v1::document::view{v ? bson_get_data(v) : nullptr}} {} + + explicit scoped_bson(std::nullptr_t) : scoped_bson{static_cast(nullptr)} {} + + explicit scoped_bson(bsoncxx::v1::document::value v) : _value{std::move(v)} { + this->sync_bson(); + } + + explicit scoped_bson(bsoncxx::v1::document::view v) : _value{v} { + this->sync_bson(); + } + + // For test convenience only: use `BCON_NEW` instead for explicit type correctness. + // ```cpp + // scoped_bson doc{R"({"x": 1})"}; // {"x": 1} + // ``` + explicit scoped_bson(bsoncxx::v1::stdx::string_view json) + : scoped_bson{[&json]() -> bson_t* { + bson_error_t error = {}; + if (auto const res = bson_new_from_json( + reinterpret_cast(json.data()), static_cast(json.size()), &error)) { + return res; + } + MONGOCXX_PRIVATE_UNREACHABLE; + }()} {} + + scoped_bson& operator+=(scoped_bson const& other) { + return (*this += scoped_bson_view{other.view()}); + } + + // Minimal support for building complex documents via concatenation. + // ```cpp + // scoped_bson doc{R"({"x": 1})"}; // {"x": 1} + // doc += scoped_bson{R"({"x": 2})"}; + // return doc; // {"x": 1, "x": 2} + // ``` + MONGOCXX_ABI_EXPORT_CDECL_TESTING(scoped_bson&) operator+=(scoped_bson_view other); + + std::uint8_t const* data() const { + return _value.data(); + } + + bson_t const* bson() const& { + return _value ? &_bson : nullptr; + } + + /* explicit(false) */ operator bson_t const*() const { + return this->bson(); + } + + bsoncxx::v1::document::view view() const { + return _value; + } + + // Convenient helper to obtain an array view of the underlying BSON data. + bsoncxx::v1::array::view array_view() const { + return bsoncxx::v1::array::view{_value.data()}; + } + + scoped_bson_view bson_view() const { + return {_value}; + } + + bsoncxx::v1::document::value const& value() const& { + return _value; + } + + bsoncxx::v1::document::value value() && { + return std::move(_value); // Assign-or-destroy-only. + } + + // Return an owning copy. + bson_t* copy() const { + return _value ? bson_copy(&_bson) : nullptr; + } + + class out_ptr_type { + friend scoped_bson; + + private: + scoped_bson& _self; + bson_t _bson = BSON_INITIALIZER; // Always pass a valid (overwritable) empty document. + + /* explicit(false) */ out_ptr_type(scoped_bson& self) : _self{self} {} + + public: + ~out_ptr_type() { + if (bson_empty(&_bson)) { + bson_destroy(&_bson); + _self = scoped_bson{}; // Avoid unnecessary allocations. + } else { + _self = scoped_bson{&_bson}; // Ownership transfer. + } + } + + out_ptr_type(out_ptr_type&&) = delete; + out_ptr_type& operator=(out_ptr_type&&) = delete; + out_ptr_type(out_ptr_type const&) = delete; + out_ptr_type& operator=(out_ptr_type const&) = delete; + + /* explicit(false) */ operator bson_t*() && { + return &_bson; + } + + /* explicit(false) */ operator bson_t*() const& = delete; + }; + + out_ptr_type out_ptr() & { + return {*this}; + } + + class inout_ptr_type { + friend scoped_bson; + + private: + scoped_bson& _self; + bson_t _bson = BSON_INITIALIZER; // Always pass a valid document (even when invalid). + + /* explicit(false) */ inout_ptr_type(scoped_bson& self) : _self{self} { + if (self._value && !self._value.empty()) { + bson_copy_to(&self._bson, &_bson); // Avoid unnecessary allocations. + } + } + + public: + ~inout_ptr_type() { + if (_bson.len == 0) { + // Some API *conditionally* use `bson_steal()` to take ownership of `_bson`. + _self = scoped_bson{nullptr}; + } else if (bson_empty(&_bson)) { + bson_destroy(&_bson); + _self = scoped_bson{}; // Avoid unnecessary allocations. + } else { + _self = scoped_bson{&_bson}; // Ownership transfer. + } + } + + inout_ptr_type(inout_ptr_type&&) = delete; + inout_ptr_type& operator=(inout_ptr_type&&) = delete; + inout_ptr_type(inout_ptr_type const&) = delete; + inout_ptr_type& operator=(inout_ptr_type const&) = delete; + + /* explicit(false) */ operator bson_t*() && { + return &_bson; + } + + /* explicit(false) */ operator bson_t*() const& = delete; + }; + + inout_ptr_type inout_ptr() & { + return {*this}; + } + + private: + void sync_bson() { + if (_value && !bson_init_static(&_bson, _value.data(), _value.length())) { + MONGOCXX_PRIVATE_UNREACHABLE; + } + } +}; + +} // namespace mongocxx diff --git a/src/mongocxx/lib/mongocxx/private/scoped_bson_value.hh b/src/mongocxx/lib/mongocxx/private/scoped_bson_value.hh index 5dcde7db58..22aa02a5bb 100644 --- a/src/mongocxx/lib/mongocxx/private/scoped_bson_value.hh +++ b/src/mongocxx/lib/mongocxx/private/scoped_bson_value.hh @@ -20,7 +20,6 @@ #include -#include namespace mongocxx { namespace detail { diff --git a/src/mongocxx/lib/mongocxx/private/search_index_view.hh b/src/mongocxx/lib/mongocxx/private/search_index_view.hh index 42db01131d..a312022d0e 100644 --- a/src/mongocxx/lib/mongocxx/private/search_index_view.hh +++ b/src/mongocxx/lib/mongocxx/private/search_index_view.hh @@ -9,8 +9,9 @@ #include +#include + #include -#include #include #include @@ -65,7 +66,6 @@ class search_index_view::impl { cursor list(client_session const* session, pipeline const& pipeline, options::aggregate const& options) { bsoncxx::v_noabi::builder::basic::document opts_doc; - libbson::scoped_bson_t stages(bsoncxx::v_noabi::document::view(pipeline.view_array())); append_aggregate_options(opts_doc, options); @@ -76,11 +76,13 @@ class search_index_view::impl { mongoc_read_prefs_t const* const rp_ptr = options.read_preference() ? options.read_preference()->_impl->read_preference_t : nullptr; - libbson::scoped_bson_t opts_bson(opts_doc.view()); - auto coll_copy = copy_and_apply_default_rw_concerns(_coll); return libmongoc::collection_aggregate( - coll_copy.get(), mongoc_query_flags_t(), stages.bson(), opts_bson.bson(), rp_ptr); + coll_copy.get(), + mongoc_query_flags_t(), + to_scoped_bson_view(pipeline.view_array()), + to_scoped_bson_view(opts_doc), + rp_ptr); } std::string create_one(client_session const* session, search_index_model const& model) { @@ -115,7 +117,6 @@ class search_index_view::impl { document::view_or_value command = make_document( kvp("createSearchIndexes", libmongoc::collection_get_name(_coll)), kvp("indexes", search_index_arr.view())); - libbson::scoped_bson_t reply; bson_error_t error; builder::basic::document opts_doc; @@ -124,18 +125,17 @@ class search_index_view::impl { opts_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - libbson::scoped_bson_t command_bson{command}; - libbson::scoped_bson_t opts_bson{opts_doc.view()}; - auto coll_copy = copy_and_apply_default_rw_concerns(_coll); + + scoped_bson reply; auto result = libmongoc::collection_write_command_with_opts( - coll_copy.get(), command_bson.bson(), opts_bson.bson(), reply.bson_for_init(), &error); + coll_copy.get(), to_scoped_bson_view(command), to_scoped_bson_view(opts_doc), reply.out_ptr(), &error); if (!result) { - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } - return reply.steal(); + return from_v1(std::move(reply)); } void drop_one(client_session const* session, bsoncxx::v_noabi::string::view_or_value name) { @@ -148,14 +148,13 @@ class search_index_view::impl { opts_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - libbson::scoped_bson_t reply; - libbson::scoped_bson_t command_bson{command.view()}; - libbson::scoped_bson_t opts_bson{opts_doc.view()}; bson_error_t error; auto coll_copy = copy_and_apply_default_rw_concerns(_coll); + + scoped_bson reply; bool result = libmongoc::collection_write_command_with_opts( - coll_copy.get(), command_bson.bson(), opts_bson.bson(), reply.bson_for_init(), &error); + coll_copy.get(), to_scoped_bson_view(command), to_scoped_bson_view(opts_doc), reply.out_ptr(), &error); uint32_t const serverErrorNamespaceNotFound = 26; if (error.domain == MONGOC_ERROR_QUERY && error.code == serverErrorNamespaceNotFound) { @@ -166,7 +165,7 @@ class search_index_view::impl { } if (!result) { - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } } @@ -184,17 +183,16 @@ class search_index_view::impl { opts_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - libbson::scoped_bson_t reply; - libbson::scoped_bson_t command_bson{command.view()}; - libbson::scoped_bson_t opts_bson{opts_doc.view()}; bson_error_t error; auto coll_copy = copy_and_apply_default_rw_concerns(_coll); + + scoped_bson reply; bool result = libmongoc::collection_write_command_with_opts( - coll_copy.get(), command_bson.bson(), opts_bson.bson(), reply.bson_for_init(), &error); + coll_copy.get(), to_scoped_bson_view(command), to_scoped_bson_view(opts_doc), reply.out_ptr(), &error); if (!result) { - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } } diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/bulk_write.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/bulk_write.cpp index 327286adda..4fa480e498 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/bulk_write.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/bulk_write.cpp @@ -20,9 +20,10 @@ #include #include +#include + #include -#include #include #include #include @@ -33,7 +34,6 @@ namespace mongocxx { namespace v_noabi { -using namespace libbson; using bsoncxx::v_noabi::builder::basic::kvp; bulk_write::bulk_write(bulk_write&&) noexcept = default; @@ -48,18 +48,15 @@ bool bulk_write::empty() const noexcept { bulk_write& bulk_write::append(model::write const& operation) { switch (operation.type()) { case write_type::k_insert_one: { - scoped_bson_t doc(operation.get_insert_one().document()); bson_error_t error; - auto result = libmongoc::bulk_operation_insert_with_opts(_impl->operation_t, doc.bson(), nullptr, &error); + auto result = libmongoc::bulk_operation_insert_with_opts( + _impl->operation_t, to_scoped_bson_view(operation.get_insert_one().document()), nullptr, &error); if (!result) { throw_exception(error); } break; } case write_type::k_update_one: { - scoped_bson_t filter(operation.get_update_one().filter()); - scoped_bson_t update(operation.get_update_one().update()); - bsoncxx::v_noabi::builder::basic::document options_builder; if (auto const collation = operation.get_update_one().collation()) { options_builder.append(kvp("collation", *collation)); @@ -76,20 +73,20 @@ bulk_write& bulk_write::append(model::write const& operation) { if (auto const array_filters = operation.get_update_one().array_filters()) { options_builder.append(kvp("arrayFilters", *array_filters)); } - scoped_bson_t options(options_builder.extract()); bson_error_t error; auto result = libmongoc::bulk_operation_update_one_with_opts( - _impl->operation_t, filter.bson(), update.bson(), options.bson(), &error); + _impl->operation_t, + to_scoped_bson_view(operation.get_update_one().filter()), + to_scoped_bson_view(operation.get_update_one().update()), + to_scoped_bson_view(options_builder.extract()), + &error); if (!result) { throw_exception(error); } break; } case write_type::k_update_many: { - scoped_bson_t filter(operation.get_update_many().filter()); - scoped_bson_t update(operation.get_update_many().update()); - bsoncxx::v_noabi::builder::basic::document options_builder; if (auto const collation = operation.get_update_many().collation()) { options_builder.append(kvp("collation", *collation)); @@ -103,19 +100,20 @@ bulk_write& bulk_write::append(model::write const& operation) { if (auto const array_filters = operation.get_update_many().array_filters()) { options_builder.append(kvp("arrayFilters", *array_filters)); } - scoped_bson_t options(options_builder.extract()); bson_error_t error; auto result = libmongoc::bulk_operation_update_many_with_opts( - _impl->operation_t, filter.bson(), update.bson(), options.bson(), &error); + _impl->operation_t, + to_scoped_bson_view(operation.get_update_many().filter()), + to_scoped_bson_view(operation.get_update_many().update()), + to_scoped_bson_view(options_builder.extract()), + &error); if (!result) { throw_exception(error); } break; } case write_type::k_delete_one: { - scoped_bson_t filter(operation.get_delete_one().filter()); - bsoncxx::v_noabi::builder::basic::document options_builder; if (auto const collation = operation.get_delete_one().collation()) { options_builder.append(kvp("collation", *collation)); @@ -123,19 +121,19 @@ bulk_write& bulk_write::append(model::write const& operation) { if (auto const hint = operation.get_delete_one().hint()) { options_builder.append(kvp("hint", *hint)); } - scoped_bson_t options(options_builder.extract()); bson_error_t error; auto result = libmongoc::bulk_operation_remove_one_with_opts( - _impl->operation_t, filter.bson(), options.bson(), &error); + _impl->operation_t, + to_scoped_bson_view(operation.get_delete_one().filter()), + to_scoped_bson_view(options_builder), + &error); if (!result) { throw_exception(error); } break; } case write_type::k_delete_many: { - scoped_bson_t filter(operation.get_delete_many().filter()); - bsoncxx::v_noabi::builder::basic::document options_builder; if (auto const collation = operation.get_delete_many().collation()) { options_builder.append(kvp("collation", *collation)); @@ -143,20 +141,19 @@ bulk_write& bulk_write::append(model::write const& operation) { if (auto const hint = operation.get_delete_many().hint()) { options_builder.append(kvp("hint", *hint)); } - scoped_bson_t options(options_builder.extract()); bson_error_t error; auto result = libmongoc::bulk_operation_remove_many_with_opts( - _impl->operation_t, filter.bson(), options.bson(), &error); + _impl->operation_t, + to_scoped_bson_view(operation.get_delete_many().filter()), + to_scoped_bson_view(options_builder), + &error); if (!result) { throw_exception(error); } break; } case write_type::k_replace_one: { - scoped_bson_t filter(operation.get_replace_one().filter()); - scoped_bson_t replace(operation.get_replace_one().replacement()); - bsoncxx::v_noabi::builder::basic::document options_builder; if (auto const collation = operation.get_replace_one().collation()) { options_builder.append(kvp("collation", *collation)); @@ -170,11 +167,14 @@ bulk_write& bulk_write::append(model::write const& operation) { if (auto const upsert = operation.get_replace_one().upsert()) { options_builder.append(kvp("upsert", *upsert)); } - scoped_bson_t options(options_builder.extract()); bson_error_t error; auto result = libmongoc::bulk_operation_replace_one_with_opts( - _impl->operation_t, filter.bson(), replace.bson(), options.bson(), &error); + _impl->operation_t, + to_scoped_bson_view(operation.get_replace_one().filter()), + to_scoped_bson_view(operation.get_replace_one().replacement()), + to_scoped_bson_view(options_builder), + &error); if (!result) { throw_exception(error); } @@ -189,11 +189,11 @@ bulk_write& bulk_write::append(model::write const& operation) { bsoncxx::v_noabi::stdx::optional bulk_write::execute() const { mongoc_bulk_operation_t* b = _impl->operation_t; - scoped_bson_t reply; bson_error_t error; - if (!libmongoc::bulk_operation_execute(b, reply.bson_for_init(), &error)) { - throw_exception(reply.steal(), error); + scoped_bson reply; + if (!libmongoc::bulk_operation_execute(b, reply.out_ptr(), &error)) { + throw_exception(from_v1(std::move(reply)), error); } // Reply is empty for unacknowledged writes, so return disengaged optional. @@ -201,7 +201,7 @@ bsoncxx::v_noabi::stdx::optional bulk_write::execute() const return bsoncxx::v_noabi::stdx::nullopt; } - result::bulk_write result(reply.steal()); + result::bulk_write result(from_v1(std::move(reply))); return bsoncxx::v_noabi::stdx::optional(std::move(result)); } @@ -226,9 +226,8 @@ bulk_write::bulk_write(collection const& coll, options::bulk_write const& option options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t bson_options(options_builder.extract()); - _impl = bsoncxx::make_unique( - libmongoc::collection_create_bulk_operation_with_opts(coll._get_impl().collection_t, bson_options.bson())); + _impl = bsoncxx::make_unique(libmongoc::collection_create_bulk_operation_with_opts( + coll._get_impl().collection_t, to_scoped_bson_view(options_builder))); if (auto validation = options.bypass_document_validation()) { libmongoc::bulk_operation_set_bypass_document_validation(_impl->operation_t, *validation); diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client.cpp index 112d9e1340..eec9c1892c 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client.cpp @@ -23,10 +23,10 @@ #include #include #include +#include #include -#include #include #include #include @@ -40,7 +40,6 @@ namespace mongocxx { namespace v_noabi { -using namespace libbson; using bsoncxx::v_noabi::builder::basic::kvp; namespace { @@ -210,13 +209,11 @@ cursor client::list_databases() const { cursor client::list_databases(client_session const& session) const { bsoncxx::v_noabi::builder::basic::document options_doc; options_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{session._get_impl().to_document()}); - scoped_bson_t options_bson(options_doc.extract()); - return libmongoc::client_find_databases_with_opts(_get_impl().client_t, options_bson.bson()); + return libmongoc::client_find_databases_with_opts(_get_impl().client_t, to_scoped_bson_view(options_doc)); } cursor client::list_databases(bsoncxx::v_noabi::document::view_or_value const opts) const { - scoped_bson_t opts_bson{opts.view()}; - return libmongoc::client_find_databases_with_opts(_get_impl().client_t, opts_bson.bson()); + return libmongoc::client_find_databases_with_opts(_get_impl().client_t, to_scoped_bson_view(opts)); } cursor client::list_databases(client_session const& session, bsoncxx::v_noabi::document::view_or_value const opts) @@ -224,8 +221,7 @@ cursor client::list_databases(client_session const& session, bsoncxx::v_noabi::d bsoncxx::v_noabi::builder::basic::document options_doc; options_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{session._get_impl().to_document()}); options_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{opts}); - mongocxx::libbson::scoped_bson_t opts_bson(options_doc.extract()); - return libmongoc::client_find_databases_with_opts(_get_impl().client_t, opts_bson.bson()); + return libmongoc::client_find_databases_with_opts(_get_impl().client_t, to_scoped_bson_view(options_doc)); } std::vector client::list_database_names(bsoncxx::v_noabi::document::view_or_value filter) const { @@ -233,11 +229,11 @@ std::vector client::list_database_names(bsoncxx::v_noabi::document: options_builder.append(kvp("filter", filter)); - scoped_bson_t options_bson(options_builder.extract()); bson_error_t error; database_names const names( - libmongoc::client_get_database_names_with_opts(_get_impl().client_t, options_bson.bson(), &error)); + libmongoc::client_get_database_names_with_opts( + _get_impl().client_t, to_scoped_bson_view(options_builder), &error)); if (!names) { throw_exception(error); @@ -259,11 +255,11 @@ std::vector client::list_database_names( options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session._get_impl().to_document()}); options_builder.append(kvp("filter", filter)); - mongocxx::libbson::scoped_bson_t opts_bson(options_builder.extract()); bson_error_t error; database_names const names( - libmongoc::client_get_database_names_with_opts(_get_impl().client_t, opts_bson.bson(), &error)); + libmongoc::client_get_database_names_with_opts( + _get_impl().client_t, to_scoped_bson_view(options_builder), &error)); if (!names) { throw_exception(error); @@ -306,7 +302,6 @@ change_stream client::_watch(client_session const* session, pipeline const& pipe, options::change_stream const& options) { bsoncxx::v_noabi::builder::basic::document container; container.append(bsoncxx::v_noabi::builder::basic::kvp("pipeline", pipe._impl->view_array())); - scoped_bson_t pipeline_bson{container.view()}; bsoncxx::v_noabi::builder::basic::document options_builder; options_builder.append(bsoncxx::v_noabi::builder::concatenate(options.as_bson())); @@ -314,9 +309,8 @@ client::_watch(client_session const* session, pipeline const& pipe, options::cha options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t options_bson{options_builder.extract()}; - - return change_stream{libmongoc::client_watch(_get_impl().client_t, pipeline_bson.bson(), options_bson.bson())}; + return change_stream{libmongoc::client_watch( + _get_impl().client_t, to_scoped_bson_view(container), to_scoped_bson_view(options_builder))}; } client::impl const& client::_get_impl() const { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client_encryption.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client_encryption.cpp index 6798f99c1d..831b947065 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client_encryption.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client_encryption.cpp @@ -22,8 +22,6 @@ namespace mongocxx { namespace v_noabi { -using mongocxx::libbson::scoped_bson_t; - client_encryption::client_encryption(options::client_encryption opts) : _impl(bsoncxx::make_unique(std::move(opts))) {} diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/collection.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/collection.cpp index a61548b41f..8bbcbd2cd2 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/collection.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/collection.cpp @@ -44,11 +44,12 @@ #include #include +#include + #include #include #include -#include #include #include #include @@ -70,8 +71,6 @@ using bsoncxx::v_noabi::document::view_or_value; namespace { -using mongocxx::libbson::scoped_bson_t; - char const* get_collection_name(mongoc_collection_t* collection) { return mongocxx::libmongoc::collection_get_name(collection); } @@ -93,7 +92,8 @@ bsoncxx::v_noabi::stdx::optional find_and_mod using unique_opts = std::unique_ptr>; - auto opts = unique_opts(mongocxx::libmongoc::find_and_modify_opts_new(), destroy_fam_opts); + auto const owner = unique_opts(mongocxx::libmongoc::find_and_modify_opts_new(), destroy_fam_opts); + auto const opts = owner.get(); bsoncxx::v_noabi::builder::basic::document extra; ::bson_error_t error; @@ -138,45 +138,40 @@ bsoncxx::v_noabi::stdx::optional find_and_mod extra.append(kvp("comment", *comment)); } - scoped_bson_t extra_bson{extra.view()}; - mongocxx::libmongoc::find_and_modify_opts_append(opts.get(), extra_bson.bson()); + mongocxx::libmongoc::find_and_modify_opts_append(opts, mongocxx::to_scoped_bson_view(extra)); if (update) { - scoped_bson_t update_bson{update->view()}; - mongocxx::libmongoc::find_and_modify_opts_set_update(opts.get(), update_bson.bson()); + mongocxx::libmongoc::find_and_modify_opts_set_update(opts, mongocxx::to_scoped_bson_view(*update)); } if (bypass) { - mongocxx::libmongoc::find_and_modify_opts_set_bypass_document_validation(opts.get(), true); + mongocxx::libmongoc::find_and_modify_opts_set_bypass_document_validation(opts, true); } if (auto const& sort = options.sort()) { - scoped_bson_t sort_bson{*sort}; - mongocxx::libmongoc::find_and_modify_opts_set_sort(opts.get(), sort_bson.bson()); + mongocxx::libmongoc::find_and_modify_opts_set_sort(opts, mongocxx::to_scoped_bson_view(*sort)); } if (auto const& projection = options.projection()) { - scoped_bson_t projection_bson{*projection}; - mongocxx::libmongoc::find_and_modify_opts_set_fields(opts.get(), projection_bson.bson()); + mongocxx::libmongoc::find_and_modify_opts_set_fields(opts, mongocxx::to_scoped_bson_view(*projection)); } if (auto const& max_time = options.max_time()) { - mongocxx::libmongoc::find_and_modify_opts_set_max_time_ms(opts.get(), static_cast(max_time->count())); + mongocxx::libmongoc::find_and_modify_opts_set_max_time_ms(opts, static_cast(max_time->count())); } // Upsert, remove, and new are passed in flags. - mongocxx::libmongoc::find_and_modify_opts_set_flags(opts.get(), flags); + mongocxx::libmongoc::find_and_modify_opts_set_flags(opts, flags); // Call mongoc_collection_find_and_modify_with_opts. - scoped_bson_t filter_bson{filter.view()}; - mongocxx::libbson::scoped_bson_t reply; - + mongocxx::scoped_bson reply; bool result = mongocxx::libmongoc::collection_find_and_modify_with_opts( - collection_t, filter_bson.bson(), opts.get(), reply.bson_for_init(), &error); + collection_t, mongocxx::to_scoped_bson_view(filter), opts, reply.out_ptr(), &error); if (!result) { if (!reply.view().empty()) { - mongocxx::v_noabi::throw_exception(reply.steal(), error); + mongocxx::v_noabi::throw_exception( + mongocxx::from_v1(std::move(reply)), error); } mongocxx::v_noabi::throw_exception(error); } @@ -197,8 +192,6 @@ bsoncxx::v_noabi::stdx::optional find_and_mod namespace mongocxx { namespace v_noabi { -using namespace libbson; - collection::collection() noexcept = default; collection::collection(collection&&) noexcept = default; collection& collection::operator=(collection&&) noexcept = default; @@ -228,14 +221,12 @@ void collection::_rename( opts_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t opts_bson{opts_doc.view()}; - bool result = libmongoc::collection_rename_with_opts( _get_impl().collection_t, _get_impl().database_name.c_str(), new_name.terminated().data(), drop_target_before_rename, - opts_bson.bson(), + mongocxx::to_scoped_bson_view(opts_doc), &error); if (!result) { @@ -394,8 +385,6 @@ bsoncxx::v_noabi::builder::basic::document build_find_options_document(options:: } // namespace cursor collection::_find(client_session const* session, view_or_value filter, options::find const& options) { - scoped_bson_t filter_bson{std::move(filter)}; - mongoc_read_prefs_t const* rp_ptr = nullptr; if (options.read_preference()) { rp_ptr = options.read_preference()->_impl->read_preference_t; @@ -406,10 +395,12 @@ cursor collection::_find(client_session const* session, view_or_value filter, op options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t options_bson{options_builder.extract()}; - cursor query_cursor{ - libmongoc::collection_find_with_opts(_get_impl().collection_t, filter_bson.bson(), options_bson.bson(), rp_ptr), + libmongoc::collection_find_with_opts( + _get_impl().collection_t, + mongocxx::to_scoped_bson_view(filter), + mongocxx::to_scoped_bson_view(options_builder), + rp_ptr), options.cursor_type()}; if (options.max_await_time()) { @@ -456,8 +447,6 @@ collection::find_one(client_session const& session, view_or_value filter, option cursor collection::_aggregate(client_session const* session, pipeline const& pipeline, options::aggregate const& options) { - scoped_bson_t stages(bsoncxx::v_noabi::document::view(pipeline._impl->view_array())); - bsoncxx::v_noabi::builder::basic::document b; options.append(b); @@ -466,8 +455,6 @@ collection::_aggregate(client_session const* session, pipeline const& pipeline, b.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t options_bson(b.view()); - ::mongoc_read_prefs_t const* rp_ptr = nullptr; if (options.read_preference()) { @@ -478,8 +465,8 @@ collection::_aggregate(client_session const* session, pipeline const& pipeline, libmongoc::collection_aggregate( _get_impl().collection_t, static_cast<::mongoc_query_flags_t>(0), - stages.bson(), - options_bson.bson(), + mongocxx::to_scoped_bson_view(pipeline._impl->view_array()), + mongocxx::to_scoped_bson_view(b), rp_ptr)); } @@ -1048,8 +1035,6 @@ bsoncxx::v_noabi::stdx::optional collection:: std::int64_t collection::_count_documents(client_session const* session, view_or_value filter, options::count const& options) { - scoped_bson_t bson_filter{filter}; - scoped_bson_t reply; bson_error_t error; mongoc_read_prefs_t const* read_prefs = nullptr; @@ -1087,11 +1072,16 @@ collection::_count_documents(client_session const* session, view_or_value filter opts_builder.append(kvp("limit", *limit)); } - scoped_bson_t opts_bson{opts_builder.view()}; + scoped_bson reply; auto result = libmongoc::collection_count_documents( - _get_impl().collection_t, bson_filter.bson(), opts_bson.bson(), read_prefs, reply.bson_for_init(), &error); + _get_impl().collection_t, + mongocxx::to_scoped_bson_view(filter), + mongocxx::to_scoped_bson_view(opts_builder), + read_prefs, + reply.out_ptr(), + &error); if (result < 0) { - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } return result; } @@ -1106,7 +1096,6 @@ collection::count_documents(client_session const& session, view_or_value filter, } std::int64_t collection::estimated_document_count(options::estimated_document_count const& options) { - scoped_bson_t reply; bson_error_t error; mongoc_read_prefs_t const* read_prefs = nullptr; @@ -1125,11 +1114,11 @@ std::int64_t collection::estimated_document_count(options::estimated_document_co opts_builder.append(kvp("comment", *comment)); } - scoped_bson_t opts_bson{opts_builder.view()}; + scoped_bson reply; auto result = libmongoc::collection_estimated_document_count( - _get_impl().collection_t, opts_bson.bson(), read_prefs, reply.bson_for_init(), &error); + _get_impl().collection_t, mongocxx::to_scoped_bson_view(opts_builder), read_prefs, reply.out_ptr(), &error); if (result < 0) { - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } return result; } @@ -1205,16 +1194,19 @@ cursor collection::_distinct( // // Send the command and validate the reply. // - scoped_bson_t reply; bson_error_t error; - scoped_bson_t command_bson{command_builder.extract()}; - scoped_bson_t opts_bson{opts_builder.extract()}; + scoped_bson reply; auto result = libmongoc::collection_read_command_with_opts( - _get_impl().collection_t, command_bson.bson(), rp_ptr, opts_bson.bson(), reply.bson_for_init(), &error); + _get_impl().collection_t, + mongocxx::to_scoped_bson_view(command_builder), + rp_ptr, + mongocxx::to_scoped_bson_view(opts_builder), + reply.out_ptr(), + &error); if (!result) { - throw_exception(reply.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } // @@ -1227,15 +1219,15 @@ cursor collection::_distinct( })); })); - bson_t* reply_bson = bson_new_from_data(fake_db_reply.view().data(), fake_db_reply.view().length()); - if (!reply_bson) { + scoped_bson fake_reply{bson_new_from_data(fake_db_reply.view().data(), fake_db_reply.view().length())}; + if (!fake_reply) { throw bsoncxx::v_noabi::exception{bsoncxx::v_noabi::error_code::k_internal_error}; } bson_t const* error_document; - cursor fake_cursor{ - libmongoc::cursor_new_from_command_reply_with_opts(_get_impl().client_impl->client_t, reply_bson, nullptr)}; + cursor fake_cursor{libmongoc::cursor_new_from_command_reply_with_opts( + _get_impl().client_impl->client_t, fake_reply.inout_ptr(), nullptr)}; if (libmongoc::cursor_error_document(fake_cursor._impl->cursor_t, &error, &error_document)) { if (error_document) { bsoncxx::v_noabi::document::value error_doc{ @@ -1271,8 +1263,8 @@ cursor collection::list_indexes() const { cursor collection::list_indexes(client_session const& session) const { bsoncxx::v_noabi::builder::basic::document options_builder; options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session._get_impl().to_document()}); - libbson::scoped_bson_t options_bson{options_builder.extract()}; - return libmongoc::collection_find_indexes_with_opts(_get_impl().collection_t, options_bson.bson()); + return libmongoc::collection_find_indexes_with_opts( + _get_impl().collection_t, mongocxx::to_scoped_bson_view(options_builder)); } void collection::_drop( @@ -1294,8 +1286,8 @@ void collection::_drop( opts_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{collection_options}); } - scoped_bson_t opts_bson{opts_doc.view()}; - auto result = libmongoc::collection_drop_with_opts(_get_impl().collection_t, opts_bson.bson(), &error); + auto result = + libmongoc::collection_drop_with_opts(_get_impl().collection_t, mongocxx::to_scoped_bson_view(opts_doc), &error); // Throw an exception if the command failed, unless the failure was due to a non-existent collection. if (!result && error.code != MONGOC_ERROR_COLLECTION_DOES_NOT_EXIST) { @@ -1368,7 +1360,6 @@ change_stream collection::_watch(client_session const* session, pipeline const& pipe, options::change_stream const& options) { bsoncxx::v_noabi::builder::basic::document container; container.append(kvp("pipeline", pipe._impl->view_array())); - scoped_bson_t pipeline_bson{container.view()}; bsoncxx::v_noabi::builder::basic::document options_builder; options_builder.append(bsoncxx::v_noabi::builder::concatenate(options.as_bson())); @@ -1376,11 +1367,11 @@ collection::_watch(client_session const* session, pipeline const& pipe, options: options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t options_bson{options_builder.extract()}; - // NOTE: collection_watch copies what it needs so we're safe to destroy our copies. - return change_stream{ - libmongoc::collection_watch(_get_impl().collection_t, pipeline_bson.bson(), options_bson.bson())}; + return change_stream{libmongoc::collection_watch( + _get_impl().collection_t, + mongocxx::to_scoped_bson_view(container), + mongocxx::to_scoped_bson_view(options_builder))}; } index_view collection::indexes() { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/database.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/database.cpp index 88a3040ab3..7fd10b2a6e 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/database.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/database.cpp @@ -25,9 +25,10 @@ #include #include +#include + #include -#include #include #include #include @@ -76,8 +77,6 @@ class collection_names { } // namespace -using namespace libbson; - database::database() noexcept = default; database::database(database&&) noexcept = default; @@ -116,8 +115,6 @@ database::operator bool() const noexcept { cursor database::_aggregate(client_session const* session, pipeline const& pipeline, options::aggregate const& options) { - scoped_bson_t stages(bsoncxx::v_noabi::document::view(pipeline._impl->view_array())); - bsoncxx::v_noabi::builder::basic::document b; options.append(b); @@ -126,15 +123,15 @@ database::_aggregate(client_session const* session, pipeline const& pipeline, op b.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t options_bson(b.view()); - ::mongoc_read_prefs_t const* rp_ptr = nullptr; if (options.read_preference()) { rp_ptr = options.read_preference()->_impl->read_preference_t; } - return cursor(libmongoc::database_aggregate(_get_impl().database_t, stages.bson(), options_bson.bson(), rp_ptr)); + return cursor( + libmongoc::database_aggregate( + _get_impl().database_t, to_scoped_bson_view(pipeline._impl->view_array()), to_scoped_bson_view(b), rp_ptr)); } cursor database::aggregate(pipeline const& pipeline, options::aggregate const& options) { @@ -153,9 +150,7 @@ cursor database::_list_collections(client_session const* session, bsoncxx::v_noa options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t options_bson(options_builder.extract()); - - return libmongoc::database_find_collections_with_opts(_get_impl().database_t, options_bson.bson()); + return libmongoc::database_find_collections_with_opts(_get_impl().database_t, to_scoped_bson_view(options_builder)); } cursor database::list_collections(bsoncxx::v_noabi::document::view_or_value filter) { @@ -176,11 +171,10 @@ std::vector database::_list_collection_names( options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t options_bson(options_builder.extract()); - bson_error_t error; collection_names names( - libmongoc::database_get_collection_names_with_opts(_get_impl().database_t, options_bson.bson(), &error)); + libmongoc::database_get_collection_names_with_opts( + _get_impl().database_t, to_scoped_bson_view(options_builder), &error)); if (!names) { throw_exception(error); @@ -211,8 +205,6 @@ bsoncxx::v_noabi::stdx::string_view database::name() const { bsoncxx::v_noabi::document::value database::_run_command( client_session const* session, bsoncxx::v_noabi::document::view_or_value command) { - libbson::scoped_bson_t command_bson{command}; - libbson::scoped_bson_t reply_bson; bson_error_t error; bsoncxx::v_noabi::builder::basic::document options_builder; @@ -220,15 +212,20 @@ bsoncxx::v_noabi::document::value database::_run_command( options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t options_bson(options_builder.extract()); + scoped_bson reply; auto result = libmongoc::database_command_with_opts( - _get_impl().database_t, command_bson.bson(), nullptr, options_bson.bson(), reply_bson.bson_for_init(), &error); + _get_impl().database_t, + to_scoped_bson_view(command), + nullptr, + to_scoped_bson_view(options_builder), + reply.out_ptr(), + &error); if (!result) { - throw_exception(reply_bson.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } - return reply_bson.steal(); + return from_v1(std::move(reply)); } bsoncxx::v_noabi::document::value database::run_command(bsoncxx::v_noabi::document::view_or_value command) { @@ -244,24 +241,23 @@ bsoncxx::v_noabi::document::value database::run_command( bsoncxx::v_noabi::document::value database::run_command( bsoncxx::v_noabi::document::view_or_value command, uint32_t server_id) { - libbson::scoped_bson_t command_bson{command}; - libbson::scoped_bson_t reply_bson; bson_error_t error; + scoped_bson reply; auto result = libmongoc::client_command_simple_with_server_id( _get_impl().client_impl->client_t, _get_impl().name.c_str(), - command_bson.bson(), + to_scoped_bson_view(command.view()), read_preference()._impl->read_preference_t, server_id, - reply_bson.bson_for_init(), + reply.out_ptr(), &error); if (!result) { - throw_exception(reply_bson.steal(), error); + throw_exception(from_v1(std::move(reply)), error); } - return reply_bson.steal(); + return from_v1(std::move(reply)); } collection database::_create_collection( @@ -282,9 +278,11 @@ collection database::_create_collection( options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - libbson::scoped_bson_t opts_bson{options_builder.view()}; auto result = libmongoc::database_create_collection( - _get_impl().database_t, bsoncxx::v_noabi::string::to_string(name).c_str(), opts_bson.bson(), &error); + _get_impl().database_t, + bsoncxx::v_noabi::string::to_string(name).c_str(), + to_scoped_bson_view(options_builder), + &error); if (!result) { throw_exception(error); @@ -322,9 +320,7 @@ void database::_drop( opts_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - libbson::scoped_bson_t opts_bson{opts_doc.view()}; - - if (!libmongoc::database_drop_with_opts(_get_impl().database_t, opts_bson.bson(), &error)) { + if (!libmongoc::database_drop_with_opts(_get_impl().database_t, to_scoped_bson_view(opts_doc), &error)) { throw_exception(error); } } @@ -409,7 +405,6 @@ change_stream database::_watch(client_session const* session, pipeline const& pipe, options::change_stream const& options) { bsoncxx::v_noabi::builder::basic::document container; container.append(kvp("pipeline", pipe._impl->view_array())); - scoped_bson_t pipeline_bson{container.view()}; bsoncxx::v_noabi::builder::basic::document options_builder; options_builder.append(bsoncxx::v_noabi::builder::concatenate(options.as_bson())); @@ -417,9 +412,8 @@ database::_watch(client_session const* session, pipeline const& pipe, options::c options_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - scoped_bson_t options_bson{options_builder.extract()}; - - return change_stream{libmongoc::database_watch(_get_impl().database_t, pipeline_bson.bson(), options_bson.bson())}; + return change_stream{libmongoc::database_watch( + _get_impl().database_t, to_scoped_bson_view(container), to_scoped_bson_view(options_builder))}; } database::impl const& database::_get_impl() const { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/exception/operation_exception.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/exception/operation_exception.cpp index 3b0f1c5feb..dfa37e7881 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/exception/operation_exception.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/exception/operation_exception.cpp @@ -19,7 +19,8 @@ #include -#include +#include + #include namespace mongocxx { @@ -47,9 +48,7 @@ bool operation_exception::has_error_label(bsoncxx::v_noabi::stdx::string_view la return false; } - libbson::scoped_bson_t error(_raw_server_error->view()); - std::string label_str{label.data(), label.size()}; - return libmongoc::error_has_label(error.bson(), label_str.c_str()); + return libmongoc::error_has_label(to_scoped_bson_view(*_raw_server_error).bson(), std::string{label}.c_str()); } } // namespace v_noabi diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/auto_encryption.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/auto_encryption.cpp index 64cc392adb..9f6a1937a9 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/auto_encryption.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/auto_encryption.cpp @@ -18,7 +18,8 @@ #include #include -#include +#include + #include #include #include @@ -123,8 +124,6 @@ bsoncxx::v_noabi::stdx::optional cons } void* auto_encryption::convert() const { - using libbson::scoped_bson_t; - if (_key_vault_client && _key_vault_pool) { throw exception{ error_code::k_invalid_parameter, "cannot set both key vault client and key vault pool, please choose one"}; @@ -152,23 +151,21 @@ void* auto_encryption::convert() const { } if (_kms_providers) { - scoped_bson_t kms_providers{*_kms_providers}; - libmongoc::auto_encryption_opts_set_kms_providers(mongoc_auto_encrypt_opts, kms_providers.bson()); + libmongoc::auto_encryption_opts_set_kms_providers( + mongoc_auto_encrypt_opts, to_scoped_bson_view(*_kms_providers)); } if (_tls_opts) { - scoped_bson_t tls_opts{*_tls_opts}; - libmongoc::auto_encryption_opts_set_tls_opts(mongoc_auto_encrypt_opts, tls_opts.bson()); + libmongoc::auto_encryption_opts_set_tls_opts(mongoc_auto_encrypt_opts, to_scoped_bson_view(*_tls_opts)); } if (_schema_map) { - scoped_bson_t schema_map{*_schema_map}; - libmongoc::auto_encryption_opts_set_schema_map(mongoc_auto_encrypt_opts, schema_map.bson()); + libmongoc::auto_encryption_opts_set_schema_map(mongoc_auto_encrypt_opts, to_scoped_bson_view(*_schema_map)); } if (_encrypted_fields_map) { - scoped_bson_t encrypted_fields_map{*_encrypted_fields_map}; - libmongoc::auto_encryption_opts_set_encrypted_fields_map(mongoc_auto_encrypt_opts, encrypted_fields_map.bson()); + libmongoc::auto_encryption_opts_set_encrypted_fields_map( + mongoc_auto_encrypt_opts, to_scoped_bson_view(*_encrypted_fields_map)); } if (_bypass) { @@ -180,8 +177,7 @@ void* auto_encryption::convert() const { } if (_extra_options) { - scoped_bson_t extra{*_extra_options}; - libmongoc::auto_encryption_opts_set_extra(mongoc_auto_encrypt_opts, extra.bson()); + libmongoc::auto_encryption_opts_set_extra(mongoc_auto_encrypt_opts, to_scoped_bson_view(*_extra_options)); } return mongoc_auto_encrypt_opts; diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/client_encryption.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/client_encryption.cpp index a0e9d735a3..3925b5a39b 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/client_encryption.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/client_encryption.cpp @@ -15,7 +15,8 @@ #include #include -#include +#include + #include #include @@ -74,13 +75,11 @@ void* client_encryption::convert() const { } if (_kms_providers) { - libbson::scoped_bson_t kms_providers{*_kms_providers}; - libmongoc::client_encryption_opts_set_kms_providers(opts_t, kms_providers.bson()); + libmongoc::client_encryption_opts_set_kms_providers(opts_t, to_scoped_bson_view(*_kms_providers)); } if (_tls_opts) { - libbson::scoped_bson_t tls_opts{*_tls_opts}; - libmongoc::client_encryption_opts_set_tls_opts(opts_t, tls_opts.bson()); + libmongoc::client_encryption_opts_set_tls_opts(opts_t, to_scoped_bson_view(*_tls_opts)); } return opts_t; diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/data_key.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/data_key.cpp index ea95c44153..4a7d5369e3 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/data_key.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/data_key.cpp @@ -14,7 +14,8 @@ #include -#include +#include + #include namespace mongocxx { @@ -44,8 +45,7 @@ void* data_key::convert() const { mongoc_client_encryption_datakey_opts_t* opts_t = libmongoc::client_encryption_datakey_opts_new(); if (_master_key) { - libbson::scoped_bson_t master_key{*_master_key}; - libmongoc::client_encryption_datakey_opts_set_masterkey(opts_t, master_key.bson()); + libmongoc::client_encryption_datakey_opts_set_masterkey(opts_t, to_scoped_bson_view(_master_key->view())); } if (!_key_alt_names.empty()) { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/encrypt.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/encrypt.cpp index a0563a69d7..e11f7dc38a 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/encrypt.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/encrypt.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -81,8 +80,6 @@ bsoncxx::v_noabi::stdx::optional const& encrypt::range_opts() co } void* encrypt::convert() const { - using libbson::scoped_bson_t; - struct encrypt_opts_deleter { void operator()(mongoc_client_encryption_encrypt_opts_t* ptr) noexcept { libmongoc::client_encryption_encrypt_opts_destroy(ptr); diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/rewrap_many_datakey.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/rewrap_many_datakey.cpp index fae719a78e..e880434efc 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/rewrap_many_datakey.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/rewrap_many_datakey.cpp @@ -16,7 +16,6 @@ #include #include -#include #include namespace mongocxx { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.cpp index 8c7d025d6f..31d2033609 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.cpp @@ -18,9 +18,10 @@ #include #include +#include + #include -#include #include #include #include @@ -72,16 +73,12 @@ read_preference& read_preference::mode(read_mode mode) { } read_preference& read_preference::tags(bsoncxx::v_noabi::document::view_or_value tag_set_list) { - libbson::scoped_bson_t scoped_bson_tags(std::move(tag_set_list)); - libmongoc::read_prefs_set_tags(_impl->read_preference_t, scoped_bson_tags.bson()); - + libmongoc::read_prefs_set_tags(_impl->read_preference_t, to_scoped_bson_view(tag_set_list)); return *this; } read_preference& read_preference::tags(bsoncxx::v_noabi::array::view_or_value tag_set_list) { - libbson::scoped_bson_t scoped_bson_tags(bsoncxx::v_noabi::document::view(tag_set_list.view())); - libmongoc::read_prefs_set_tags(_impl->read_preference_t, scoped_bson_tags.bson()); - + libmongoc::read_prefs_set_tags(_impl->read_preference_t, to_scoped_bson_view(tag_set_list)); return *this; } @@ -120,9 +117,8 @@ bsoncxx::v_noabi::stdx::optional read_preference::max_stal } read_preference& read_preference::hedge(bsoncxx::v_noabi::document::view_or_value hedge) { - libbson::scoped_bson_t hedge_bson{std::move(hedge)}; BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_BEGIN - libmongoc::read_prefs_set_hedge(_impl->read_preference_t, hedge_bson.bson()); + libmongoc::read_prefs_set_hedge(_impl->read_preference_t, to_scoped_bson_view(hedge)); BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_END return *this; } diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/result/rewrap_many_datakey.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/result/rewrap_many_datakey.cpp index 2e59de52c8..44c2c48cc1 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/result/rewrap_many_datakey.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/result/rewrap_many_datakey.cpp @@ -15,8 +15,6 @@ #include #include -#include - namespace mongocxx { namespace v_noabi { namespace result { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/scoped_bson.hh b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/scoped_bson.hh new file mode 100644 index 0000000000..90725dedf3 --- /dev/null +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/scoped_bson.hh @@ -0,0 +1,65 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +// + +#include +#include +#include +#include +#include + +namespace mongocxx { + +inline scoped_bson_view to_scoped_bson_view(bsoncxx::v_noabi::builder::basic::document const& v) { + return {bsoncxx::v_noabi::to_v1(v.view())}; +} + +inline scoped_bson_view to_scoped_bson_view(bsoncxx::v_noabi::document::view const& v) { + return {bsoncxx::v_noabi::to_v1(v)}; +} + +inline scoped_bson_view to_scoped_bson_view(bsoncxx::v_noabi::document::value const& v) { + return {bsoncxx::v_noabi::to_v1(v.view())}; +} + +inline scoped_bson_view to_scoped_bson_view(bsoncxx::v_noabi::document::view_or_value const& v) { + return {bsoncxx::v_noabi::to_v1(v.view())}; +} + +inline scoped_bson_view to_scoped_bson_view(bsoncxx::v_noabi::array::view const& v) { + return {bsoncxx::v_noabi::to_v1(v)}; +} + +inline scoped_bson_view to_scoped_bson_view(bsoncxx::v_noabi::array::value const& v) { + return {bsoncxx::v_noabi::to_v1(v.view())}; +} + +inline scoped_bson_view to_scoped_bson_view(bsoncxx::v_noabi::array::view_or_value const& v) { + return {bsoncxx::v_noabi::to_v1(v.view())}; +} + +inline scoped_bson to_scoped_bson(bsoncxx::v_noabi::document::value v) { + return scoped_bson{bsoncxx::v_noabi::to_v1(std::move(v))}; +} + +inline bsoncxx::v_noabi::document::value from_v1(scoped_bson&& v) { + return bsoncxx::v_noabi::from_v1(std::move(v).value()); +} + +} // namespace mongocxx diff --git a/src/mongocxx/test/CMakeLists.txt b/src/mongocxx/test/CMakeLists.txt index 627de5cb43..ace3575102 100644 --- a/src/mongocxx/test/CMakeLists.txt +++ b/src/mongocxx/test/CMakeLists.txt @@ -33,8 +33,8 @@ endif() set(mongocxx_test_sources_private private/numeric_casting.cpp - private/scoped_bson_t.cpp private/scoped_bson_value.cpp + private/scoped_bson.cpp private/write_concern.cpp private/mongoc_version.cpp ) diff --git a/src/mongocxx/test/private/numeric_casting.cpp b/src/mongocxx/test/private/numeric_casting.cpp index dfaaaaf98e..09a5826369 100644 --- a/src/mongocxx/test/private/numeric_casting.cpp +++ b/src/mongocxx/test/private/numeric_casting.cpp @@ -14,7 +14,6 @@ #include -#include #include #include diff --git a/src/mongocxx/test/private/scoped_bson.cpp b/src/mongocxx/test/private/scoped_bson.cpp new file mode 100644 index 0000000000..6bbe1d1428 --- /dev/null +++ b/src/mongocxx/test/private/scoped_bson.cpp @@ -0,0 +1,639 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +// + +#include +#include +#include + +#include +#include + +#include +#include + +namespace mongocxx { + +TEST_CASE("ownership", "[mongocxx][private][scoped_bson_view]") { + scoped_bson source_owner{R"({"x": 1})"}; + scoped_bson target_owner{R"({"y": 2})"}; + + REQUIRE(source_owner.data() != target_owner.data()); + + auto source = source_owner.bson_view(); + auto target = target_owner.bson_view(); + + REQUIRE(target.data() != source.data()); + REQUIRE(target.bson() != source.bson()); + REQUIRE_FALSE(bson_empty0(source.bson())); + REQUIRE_FALSE(bson_empty0(target.bson())); + REQUIRE(source.view() == source_owner.view()); + REQUIRE(target.view() == target_owner.view()); + + auto const source_data = source.data(); + + SECTION("copy") { + auto copy = source; + + REQUIRE(source.data() == source_data); + REQUIRE(source.bson() != nullptr); + REQUIRE(bson_get_data(source.bson()) == source.data()); + + REQUIRE(copy.data() == source_data); + REQUIRE_FALSE(bson_empty0(copy.bson())); + REQUIRE(bson_get_data(copy.bson()) == copy.data()); + REQUIRE(bson_compare(copy.bson(), source.bson()) == 0); + + target = copy; + + REQUIRE(copy.data() == source_data); + REQUIRE(copy.bson() != nullptr); + REQUIRE(bson_get_data(copy.bson()) == copy.data()); + + REQUIRE(target.data() == source_data); + REQUIRE_FALSE(bson_empty0(target.bson())); + REQUIRE(bson_get_data(target.bson()) == target.data()); + REQUIRE(bson_compare(target.bson(), source.bson()) == 0); + } +} + +TEST_CASE("basic", "[mongocxx][private][scoped_bson_view]") { + SECTION("null") { + scoped_bson_view const v{nullptr}; + + CHECK(v.data() == nullptr); + CHECK(v.bson() == nullptr); + CHECK_FALSE(v.view()); + + CHECK(scoped_bson{v.copy()}.data() == nullptr); + + CHECK(v.value().data() == nullptr); + } + + SECTION("empty") { + bsoncxx::v1::document::view const empty; + + scoped_bson_view const v{empty}; + + CHECK(v.data() == empty.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_get_data(v.bson()) == v.data()); + CHECK(v.view() == empty); + + CHECK(v.value().data() == empty.data()); + } + + SECTION("default") { + bsoncxx::v1::document::view const empty; + + scoped_bson_view const v; + + CHECK(v.data() == empty.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_get_data(v.bson()) == v.data()); + CHECK(v.view() == empty); + + CHECK(v.value().data() == empty.data()); + } + + SECTION("value") { + scoped_bson const owner{BCON_NEW("x", "1")}; + auto const v = owner.bson_view(); + + CHECK(v.data() == owner.data()); + REQUIRE_FALSE(v.bson() == nullptr); + CHECK(bson_get_data(v.bson()) == owner.data()); + CHECK(v.view() == owner.view()); + + scoped_bson_view const copy{v.view()}; + + CHECK(copy.data() == v.data()); + REQUIRE_FALSE(copy.bson() == nullptr); + CHECK(bson_get_data(copy.bson()) == copy.data()); + CHECK(copy.view() == v.view()); + + auto const value = copy.value(); + + CHECK(value.data() != v.data()); + CHECK(value.view() == v.view()); + } + + SECTION("bson_t") { + SECTION("null") { + scoped_bson_view const v{nullptr}; + + CHECK(v.data() == nullptr); + CHECK(v.bson() == nullptr); + CHECK_FALSE(v.view()); + } + + SECTION("empty") { + std::uint8_t const data[] = {5, 0, 0, 0, 0}; // {} + scoped_bson_view const x1{bsoncxx::v1::document::view{data, sizeof(data)}}; + + scoped_bson_view const v{x1.bson()}; // bson_t const* + + CHECK(v.data() == x1.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_get_data(v.bson()) == v.data()); + CHECK(v.view() == x1.view()); + } + + SECTION("value") { + std::uint8_t const data[] = {12, 0, 0, 0, 16, 'x', '\0', 1, 0, 0, 0, 0}; // {"x": 1} + scoped_bson_view const x1{bsoncxx::v1::document::view{data, sizeof(data)}}; + + scoped_bson_view const v{x1.bson()}; // bson_t const* + + CHECK(v.data() == x1.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_get_data(v.bson()) == v.data()); + CHECK(v.view() == x1.view()); + + scoped_bson_view const copy{v.bson()}; // bson_t const* + + CHECK(copy.data() == v.data()); + REQUIRE_FALSE(copy.bson() == nullptr); + CHECK(bson_get_data(copy.bson()) == copy.data()); + CHECK(copy.view() == v.view()); + } + } +} + +TEST_CASE("out_ptr", "[mongocxx][private][scoped_bson_view]") { + scoped_bson const x1_owner{R"({"x": 1})"}; + scoped_bson const x2_owner{R"({"x": 2})"}; + + auto const x1 = x1_owner.bson_view(); + auto const x2 = x2_owner.bson_view(); + + SECTION("null") { + scoped_bson_view doc = x1; + + [&](bson_t const** bson_ptr) { + REQUIRE(bson_ptr != nullptr); + CHECK(*bson_ptr == nullptr); + + *bson_ptr = nullptr; + }(doc.out_ptr()); + + CHECK(doc.data() == nullptr); + CHECK(doc.bson() == nullptr); + CHECK_FALSE(doc.view()); + } + + SECTION("empty") { + scoped_bson_view const empty; + + scoped_bson_view doc = x1; + + [&](bson_t const** bson_ptr) { + REQUIRE(bson_ptr != nullptr); + CHECK(*bson_ptr == nullptr); + + *bson_ptr = empty.bson(); + }(doc.out_ptr()); + + CHECK(doc.data() == empty.data()); + REQUIRE(doc.bson() != nullptr); + CHECK(bson_get_data(doc.bson()) == doc.data()); + CHECK(doc.view() == empty.view()); + } + + SECTION("value") { + scoped_bson_view doc = x1; + + [&](bson_t const** bson_ptr) { + REQUIRE(bson_ptr != nullptr); + CHECK(*bson_ptr == nullptr); + + *bson_ptr = x2.bson(); + }(doc.out_ptr()); + + CHECK(doc.data() == x2.data()); + REQUIRE(doc.bson() != nullptr); + CHECK(bson_get_data(doc.bson()) == doc.data()); + CHECK(doc.view() == x2.view()); + } +} + +TEST_CASE("ownership", "[mongocxx][private][scoped_bson]") { + scoped_bson source{BCON_NEW("x", "1")}; + scoped_bson target{BCON_NEW("y", "2")}; + + CHECK(target.data() != source.data()); + + auto const original = source; + auto const source_data = source.data(); + + SECTION("move") { + auto move = std::move(source); + + CHECK(source.data() == nullptr); + CHECK(source.bson() == nullptr); + + CHECK(move.data() == source_data); + REQUIRE(move.bson() != nullptr); + CHECK(bson_get_data(move.bson()) == move.data()); + CHECK(bson_compare(move.bson(), original.bson()) == 0); + + target = std::move(move); + + CHECK(move.data() == nullptr); + CHECK(move.bson() == nullptr); + CHECK(target.data() == source_data); + + CHECK(target.data() == source_data); + REQUIRE(target.bson() != nullptr); + CHECK(bson_get_data(target.bson()) == target.data()); + CHECK(bson_compare(target.bson(), original.bson()) == 0); + + auto const doc = std::move(target).value(); + + CHECK(target.data() == nullptr); + CHECK(target.bson() == nullptr); // Assign-or-destroy-only. + + CHECK(doc.data() == source_data); + CHECK(doc.view() == original.view()); + } + + SECTION("copy") { + auto copy = source; + auto const copy_data = copy.data(); + + CHECK(source.data() == source_data); + REQUIRE(source.bson() != nullptr); + CHECK(bson_get_data(source.bson()) == source.data()); + + CHECK(copy.data() != source_data); + REQUIRE(copy.bson() != nullptr); + CHECK(bson_get_data(copy.bson()) == copy.data()); + CHECK(bson_compare(copy.bson(), source.bson()) == 0); + + target = copy; + + CHECK(copy.data() == copy_data); + REQUIRE(copy.bson() != nullptr); + CHECK(bson_get_data(copy.bson()) == copy.data()); + + CHECK(target.data() != copy_data); + REQUIRE(target.bson() != nullptr); + CHECK(bson_get_data(target.bson()) == target.data()); + CHECK(bson_compare(target.bson(), source.bson()) == 0); + } +} + +TEST_CASE("basic", "[mongocxx][private][scoped_bson]") { + SECTION("null") { + scoped_bson const v{bsoncxx::v1::document::view{nullptr}}; + + CHECK(v.data() == nullptr); + CHECK(v.bson() == nullptr); + CHECK_FALSE(v.view()); + + CHECK(scoped_bson{v.copy()}.data() == nullptr); + } + + SECTION("empty") { + bsoncxx::v1::document::view const empty; + + scoped_bson const v{empty}; + + CHECK(v.data() == empty.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_get_data(v.bson()) == v.data()); + CHECK(v.view() == empty); + CHECK(v.array_view() == bsoncxx::v1::array::view{}); + } + + SECTION("default") { + bsoncxx::v1::document::view const empty; + + scoped_bson const v; + + CHECK(v.data() == empty.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_get_data(v.bson()) == v.data()); + CHECK(v.view() == empty); + CHECK(v.array_view() == bsoncxx::v1::array::view{}); + } + + SECTION("value") { + std::uint8_t const data[] = {12, 0, 0, 0, 16, 'x', '\0', 1, 0, 0, 0, 0}; // {"x": 1} + bsoncxx::v1::document::view const x1{data, sizeof(data)}; + + scoped_bson const v{x1}; + + CHECK(v.data() != x1.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_get_data(v.bson()) == v.data()); + CHECK(v.view() == x1); + + scoped_bson const copy{v.value()}; + + CHECK(copy.data() != v.data()); + REQUIRE_FALSE(copy.bson() == nullptr); + CHECK(bson_get_data(copy.bson()) == copy.data()); + CHECK(copy.view() == v.view()); + } + + SECTION("bson_t") { + SECTION("null") { + scoped_bson v{nullptr}; + + CHECK(v.data() == nullptr); + CHECK(v.bson() == nullptr); + CHECK_FALSE(v.view()); + } + + SECTION("empty") { + std::uint8_t const data[] = {5, 0, 0, 0, 0}; // {} + scoped_bson_view x1{bsoncxx::v1::document::view{data, sizeof(data)}}; + + scoped_bson v{x1.copy()}; // bson_t* + + CHECK(v.data() != x1.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_get_data(v.bson()) == v.data()); + CHECK(v.view() == x1.view()); + } + + SECTION("value") { + std::uint8_t const data[] = {12, 0, 0, 0, 16, 'x', '\0', 1, 0, 0, 0, 0}; // {"x": 1} + scoped_bson_view x1{bsoncxx::v1::document::view{data, sizeof(data)}}; + + scoped_bson v{x1.bson()}; // bson_t const* + + CHECK(v.data() != x1.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_get_data(v.bson()) == v.data()); + CHECK(v.view() == x1.view()); + + scoped_bson const copy{v.copy()}; // bson_t const* + + CHECK(copy.data() != v.data()); + REQUIRE_FALSE(copy.bson() == nullptr); + CHECK(bson_get_data(copy.bson()) == copy.data()); + CHECK(copy.view() == v.view()); + } + } + + SECTION("json") { + std::uint8_t const data[] = {12, 0, 0, 0, 16, 'x', '\0', 1, 0, 0, 0, 0}; // {"x": 1} + bsoncxx::v1::document::view const x1{data, sizeof(data)}; + + CHECK(scoped_bson{R"({"x": 1})"}.view() == x1); + } +} + +TEST_CASE("concat", "[mongocxx][private][scoped_bson]") { + SECTION("invalid") { + SECTION("lhs") { + scoped_bson lhs{nullptr}; + scoped_bson rhs; + + CHECK_THROWS_MATCHES( + lhs += rhs, + std::logic_error, + Catch::Matchers::Message("mongocxx::scoped_bson::operator+=: this->data() == nullptr")); + } + + SECTION("rhs") { + scoped_bson lhs; + scoped_bson rhs{nullptr}; + + CHECK_THROWS_MATCHES( + lhs += rhs, + std::logic_error, + Catch::Matchers::Message("mongocxx::scoped_bson::operator+=: other.data() == nullptr")); + } + + SECTION("concat") { + auto const size = (std::size_t{BSON_MAX_SIZE} / 2u) + 1u; + auto const data = bsoncxx::make_unique_for_overwrite(size); + auto const big_string = bsoncxx::v1::stdx::string_view{data.get(), size}; + + std::memset(data.get(), 'x', size - 1u); + data[size - 1u] = '\0'; + + scoped_bson lhs{BCON_NEW("x", BCON_UTF8(big_string.data()))}; + scoped_bson rhs{BCON_NEW("x", BCON_UTF8(big_string.data()))}; + + REQUIRE(lhs.data() != nullptr); + REQUIRE(rhs.data() != nullptr); + + CHECK_THROWS_MATCHES( + lhs += rhs, + std::logic_error, + Catch::Matchers::Message("mongocxx::scoped_bson::operator+=: bson_concat failed")); + } + } + + SECTION("strong exception safety") { + scoped_bson x1{BCON_NEW("x", "1")}; + scoped_bson x2{BCON_NEW("x", "2")}; + + auto const x1_data = const_cast(x1.data()); + auto const x2_data = const_cast(x2.data()); + + auto const first_byte = x1_data[0]; + + auto const x1_doc = x1.value(); + auto const x2_doc = x2.value(); + + x1_data[0] = 0; // Corrupt embedded length field. + CHECK_THROWS_AS(x1 += x2, std::logic_error); // Self-assignment. + x1_data[0] = first_byte; // Restore embedded length field. + + CHECK(x1.data() == x1_data); // No reallocation. + CHECK(x1.view() == x1_doc); + + CHECK(x2.data() == x2_data); // No reallocation. + CHECK(x2.view() == x2_doc); + } + + SECTION("self") { + bsoncxx::v1::document::view const empty; + + SECTION("empty") { + scoped_bson v; + + v += v; + + CHECK(v.data() == empty.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_compare(v.bson(), scoped_bson_view{empty}.bson()) == 0); + } + + SECTION("value") { + scoped_bson const x1{R"({"x": 1})"}; + scoped_bson const x1x1{R"({"x": 1, "x": 1})"}; + + auto v = x1; + + v += v; + + CHECK(v.data() != x1.data()); + REQUIRE(v.bson() != nullptr); + CHECK(bson_compare(v.bson(), scoped_bson_view{x1x1}.bson()) == 0); + } + } + + SECTION("basic") { + scoped_bson const x1{BCON_NEW("x", "1")}; + scoped_bson const x2{BCON_NEW("x", "2")}; + scoped_bson const x1x2{BCON_NEW("x", "1", "x", "2")}; + + scoped_bson doc; + + CHECK(doc.view().empty()); + + doc += x1; + CHECK(doc.view() == x1.view()); + + doc += x2; + CHECK(doc.view() == x1x2.view()); + } + + SECTION("deleter") { + scoped_bson const x1{R"({"x": 1})"}; + scoped_bson const x2{R"({"x": 2})"}; + scoped_bson const x1x2{R"({"x": 1, "x": 2})"}; + + std::uint8_t data[] = {5, 0, 0, 0, 0}; // {} + scoped_bson doc{bsoncxx::v1::document::value{data, &bsoncxx::v1::document::value::noop_deleter}}; + + doc += x1; // noop_deleter -> bson_free + + CHECK(doc.view() == x1.view()); + + { + auto const deleter_ptr = doc.value().get_deleter().target(); + REQUIRE(deleter_ptr); + CHECK(*deleter_ptr == &bson_free); + } + + doc += x2; // bson_free -> bson_free + + CHECK(doc.view() == x1x2.view()); + + { + auto const deleter_ptr = doc.value().get_deleter().target(); + REQUIRE(deleter_ptr); + CHECK(*deleter_ptr == &bson_free); + } + } +} + +TEST_CASE("out_ptr", "[mongocxx][private][scoped_bson]") { + scoped_bson const x1{R"({"x": 1})"}; + scoped_bson const x2{R"({"x": 2})"}; + + SECTION("empty") { + scoped_bson const empty; + + scoped_bson doc = x1; + + [&](bson_t* bson) { + REQUIRE(bson != nullptr); + REQUIRE(bson_empty(bson)); + + bson_copy_to(empty.bson(), bson); + }(doc.out_ptr()); + + CHECK(doc.data() == empty.data()); + REQUIRE(doc.bson() != nullptr); + CHECK(bson_get_data(doc.bson()) == doc.data()); + CHECK(doc.view() == empty.view()); + } + + SECTION("value") { + scoped_bson doc = x1; + + [&](bson_t* bson) { + REQUIRE(bson != nullptr); + REQUIRE(bson_empty(bson)); + + bson_copy_to(x2.bson(), bson); + }(doc.out_ptr()); + + CHECK(doc.data() != x2.data()); + REQUIRE(doc.bson() != nullptr); + CHECK(bson_get_data(doc.bson()) == doc.data()); + CHECK(doc.view() == x2.view()); + } +} + +TEST_CASE("inout_ptr", "[mongocxx][private][scoped_bson]") { + scoped_bson const x1{R"({"x": 1})"}; + scoped_bson const x2{R"({"x": 2})"}; + + SECTION("empty") { + scoped_bson const empty; + + scoped_bson doc = x1; + + [&](bson_t* bson) { + REQUIRE(bson != nullptr); + CHECK(bson_compare(bson, x1.bson()) == 0); + + bson_destroy(bson); + bson_copy_to(empty.bson(), bson); + }(doc.inout_ptr()); + + CHECK(doc.data() == empty.data()); + REQUIRE(doc.bson() != nullptr); + CHECK(bson_get_data(doc.bson()) == doc.data()); + CHECK(doc.view() == empty.view()); + } + + SECTION("value") { + scoped_bson doc = x1; + + [&](bson_t* bson) { + REQUIRE(bson != nullptr); + CHECK(bson_compare(bson, x1.bson()) == 0); + + bson_destroy(bson); + bson_copy_to(x2.bson(), bson); + }(doc.inout_ptr()); + + CHECK(doc.data() != x2.data()); + REQUIRE(doc.bson() != nullptr); + CHECK(bson_get_data(doc.bson()) == doc.data()); + CHECK(doc.view() == x2.view()); + } + + SECTION("stolen") { + scoped_bson doc = x1; + + [&](bson_t* bson) { + REQUIRE(bson != nullptr); + CHECK(bson_compare(bson, x1.bson()) == 0); + + bson_t tmp; + bson_steal(&tmp, bson); + bson_destroy(&tmp); + }(doc.inout_ptr()); + + CHECK(doc.data() == nullptr); + REQUIRE(doc.bson() == nullptr); + CHECK_FALSE(doc.view()); + } +} + +} // namespace mongocxx diff --git a/src/mongocxx/test/private/scoped_bson_t.cpp b/src/mongocxx/test/private/scoped_bson_t.cpp deleted file mode 100644 index a21cc4382f..0000000000 --- a/src/mongocxx/test/private/scoped_bson_t.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2009-present MongoDB, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include - -#include - -namespace { -using namespace bsoncxx; -using namespace mongocxx; -using namespace mongocxx::libbson; - -using bsoncxx::builder::basic::kvp; -using bsoncxx::builder::basic::make_document; - -TEST_CASE("scoped_bson_t", "[private]") { - SECTION("Can be constructed") { - document::value val = make_document(kvp("a", 1)); - document::view view = val.view(); - document::view empty_view; - - SECTION("from a view") { - scoped_bson_t bson{view}; - REQUIRE(bson.view() == view); - } - - SECTION("from a value") { - document::value copy{val}; - scoped_bson_t bson{std::move(copy)}; - REQUIRE(bson.view() == view); - } - - SECTION("from a temporary value") { - scoped_bson_t bson{make_document(kvp("a", 1))}; - REQUIRE(bson.view() == view); - } - - SECTION("from a view_or_value") { - document::view_or_value variant{val}; - scoped_bson_t bson{variant}; - REQUIRE(bson.view() == view); - } - - SECTION("from an empty optional view_or_value") { - bsoncxx::stdx::optional empty; - scoped_bson_t bson{empty}; - REQUIRE(bson.view() == empty_view); - } - - SECTION("from an engaged optional view_or_value") { - document::view_or_value variant{val}; - bsoncxx::stdx::optional engaged{variant}; - scoped_bson_t bson{engaged}; - REQUIRE(bson.view() == view); - } - } - - SECTION("Can be initialized") { - auto val = make_document(kvp("a", 1)); - auto view = val.view(); - document::view empty_view; - - SECTION("from a view") { - scoped_bson_t bson; - bson.init_from_static(view); - REQUIRE(bson.view() == view); - } - - SECTION("from a value") { - scoped_bson_t bson; - document::value copy{val}; - bson.init_from_static(std::move(copy)); - REQUIRE(bson.view() == view); - } - - SECTION("from a temporary value") { - scoped_bson_t bson; - bson.init_from_static(make_document(kvp("a", 1))); - REQUIRE(bson.view() == view); - } - - SECTION("from a view_or_value") { - scoped_bson_t bson; - document::view_or_value variant{val}; - bson.init_from_static(variant); - REQUIRE(bson.view() == view); - } - - SECTION("from an empty optional view_or_value") { - scoped_bson_t bson; - bsoncxx::stdx::optional empty; - bson.init_from_static(empty); - REQUIRE(bson.view() == empty_view); - } - - SECTION("from an engaged optional view_or_value") { - scoped_bson_t bson; - document::view_or_value variant{val}; - bsoncxx::stdx::optional engaged{variant}; - bson.init_from_static(engaged); - REQUIRE(bson.view() == view); - } - } -} -} // namespace diff --git a/src/mongocxx/test/private/scoped_bson_value.cpp b/src/mongocxx/test/private/scoped_bson_value.cpp index 60e5b0e1e2..65bf99e1a9 100644 --- a/src/mongocxx/test/private/scoped_bson_value.cpp +++ b/src/mongocxx/test/private/scoped_bson_value.cpp @@ -23,8 +23,6 @@ #include -#include - #include namespace { diff --git a/src/mongocxx/test/v_noabi/change_streams.cpp b/src/mongocxx/test/v_noabi/change_streams.cpp index 56670a34f4..ccdc8828a6 100644 --- a/src/mongocxx/test/v_noabi/change_streams.cpp +++ b/src/mongocxx/test/v_noabi/change_streams.cpp @@ -30,9 +30,9 @@ #include #include -#include +#include -#include +#include #include @@ -79,7 +79,7 @@ bsoncxx::document::value doc(std::string key, T val) { // Phrased as a lambda instead of function because c++11 doesn't have decltype(auto) and the // return-type is haunting. auto const gen_next = [](bool has_next) { - static mongocxx::libbson::scoped_bson_t next_bson{make_document(kvp("some", "doc"))}; + static scoped_bson next_bson{to_scoped_bson(make_document(kvp("some", "doc")))}; return [=](mongoc_change_stream_t*, bson_t const** bson) mutable -> bool { if (has_next) { *bson = next_bson.bson(); diff --git a/src/mongocxx/test/v_noabi/client_side_encryption.cpp b/src/mongocxx/test/v_noabi/client_side_encryption.cpp index 74f2ef9e55..4a4a0c4a71 100644 --- a/src/mongocxx/test/v_noabi/client_side_encryption.cpp +++ b/src/mongocxx/test/v_noabi/client_side_encryption.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -43,9 +44,9 @@ #include #include -#include +#include -#include +#include #include @@ -2651,12 +2652,9 @@ TEST_CASE("Custom Key Material Test", "[client_side_encryption]") { bsoncxx::types::b_binary id_bin{bsoncxx::binary_sub_type::k_uuid, static_cast(id.size()), id.data()}; auto key_doc = make_document(kvp("_id", id_bin)); - mongocxx::libbson::scoped_bson_t bson_doc; - bson_doc.init_from_static(doc); - mongocxx::libbson::scoped_bson_t doc_without_id; - bson_copy_to_excluding_noinit(bson_doc.bson(), doc_without_id.bson_for_init(), "_id", nullptr); - - bsoncxx::document::value new_doc(doc_without_id.steal()); + scoped_bson doc_without_id; + bson_copy_to_excluding_noinit(to_scoped_bson_view(doc), doc_without_id.out_ptr(), "_id", nullptr); + bsoncxx::document::value new_doc{from_v1(std::move(doc_without_id))}; bsoncxx::builder::basic::document builder; builder.append(concatenate(key_doc.view())); diff --git a/src/mongocxx/test/v_noabi/collection.cpp b/src/mongocxx/test/v_noabi/collection.cpp index 87c0f911b6..64ce4d5103 100644 --- a/src/mongocxx/test/v_noabi/collection.cpp +++ b/src/mongocxx/test/v_noabi/collection.cpp @@ -40,7 +40,6 @@ #include -#include #include #include diff --git a/src/mongocxx/test/v_noabi/collection_mocked.cpp b/src/mongocxx/test/v_noabi/collection_mocked.cpp index 87813e4422..0d0ddbb9e6 100644 --- a/src/mongocxx/test/v_noabi/collection_mocked.cpp +++ b/src/mongocxx/test/v_noabi/collection_mocked.cpp @@ -32,10 +32,11 @@ #include #include +#include + #include #include -#include #include #include @@ -299,8 +300,7 @@ TEST_CASE("Collection", "[collection]") { opts.hint(index_hint); // set our expected_opts so we check against that - bsoncxx::document::value doc = make_document(kvp("hint", index_hint.to_value())); - libbson::scoped_bson_t cmd_opts{std::move(doc)}; + scoped_bson const cmd_opts{to_scoped_bson(make_document(kvp("hint", index_hint.to_value())))}; expected_opts = cmd_opts.bson(); REQUIRE_NOTHROW(mongo_coll.count_documents(filter_doc.view(), opts)); diff --git a/src/mongocxx/test/v_noabi/database.cpp b/src/mongocxx/test/v_noabi/database.cpp index 62f9b9466f..7bacf7c895 100644 --- a/src/mongocxx/test/v_noabi/database.cpp +++ b/src/mongocxx/test/v_noabi/database.cpp @@ -28,7 +28,8 @@ #include #include -#include +#include + #include #include @@ -282,7 +283,6 @@ TEST_CASE("A database", "[database]") { bool called = false; bsoncxx::document::value doc = make_document(kvp("foo", 5)); - libbson::scoped_bson_t bson_doc{doc.view()}; database_command_with_opts->interpose([&](mongoc_database_t*, bson_t const*, @@ -291,7 +291,7 @@ TEST_CASE("A database", "[database]") { bson_t* reply, bson_error_t*) { called = true; - ::bson_copy_to(bson_doc.bson(), reply); + ::bson_copy_to(to_scoped_bson_view(doc), reply); return true; });