#include "mongoc/mongoc-opts-helpers-private.h"
#include "mongoc/mongoc-opts-private.h"
#include "mongoc/mongoc-error.h"
#include "mongoc/mongoc-util-private.h"
#include "mongoc/mongoc-client-private.h"

/**************************************************
 *
 * Generated by build/generate-opts.py.
 *
 * DO NOT EDIT THIS FILE.
 *
 *************************************************/
/* clang-format off */


bool
_mongoc_insert_one_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_insert_one_opts_t *mongoc_insert_one_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_insert_one_opts->crud.writeConcern = NULL;
   mongoc_insert_one_opts->crud.write_concern_owned = false;
   mongoc_insert_one_opts->crud.client_session = NULL;
   mongoc_insert_one_opts->crud.validate = _mongoc_default_insert_vflags;
   mongoc_insert_one_opts->bypass = false;
   bson_init (&mongoc_insert_one_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_insert_one_opts->crud.writeConcern,
               error)) {
            return false;
         }

         mongoc_insert_one_opts->crud.write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_insert_one_opts->crud.client_session,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_insert_one_opts->crud.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_insert_one_opts->bypass,
               error)) {
            return false;
         }
      }
      else {
         /* unrecognized values are copied to "extra" */
         if (!BSON_APPEND_VALUE (
               &mongoc_insert_one_opts->extra,
               bson_iter_key (&iter),
               bson_iter_value (&iter))) {
            bson_set_error (error,
                            MONGOC_ERROR_BSON,
                            MONGOC_ERROR_BSON_INVALID,
                            "Invalid 'opts' parameter.");
            return false;
         }
      }
   }

   return true;
}

void
_mongoc_insert_one_opts_cleanup (mongoc_insert_one_opts_t *mongoc_insert_one_opts)
{
   if (mongoc_insert_one_opts->crud.write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_insert_one_opts->crud.writeConcern);
   }
   bson_destroy (&mongoc_insert_one_opts->extra);
}

bool
_mongoc_insert_many_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_insert_many_opts_t *mongoc_insert_many_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_insert_many_opts->crud.writeConcern = NULL;
   mongoc_insert_many_opts->crud.write_concern_owned = false;
   mongoc_insert_many_opts->crud.client_session = NULL;
   mongoc_insert_many_opts->crud.validate = _mongoc_default_insert_vflags;
   mongoc_insert_many_opts->ordered = true;
   mongoc_insert_many_opts->bypass = false;
   bson_init (&mongoc_insert_many_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_insert_many_opts->crud.writeConcern,
               error)) {
            return false;
         }

         mongoc_insert_many_opts->crud.write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_insert_many_opts->crud.client_session,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_insert_many_opts->crud.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "ordered")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_insert_many_opts->ordered,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_insert_many_opts->bypass,
               error)) {
            return false;
         }
      }
      else {
         /* unrecognized values are copied to "extra" */
         if (!BSON_APPEND_VALUE (
               &mongoc_insert_many_opts->extra,
               bson_iter_key (&iter),
               bson_iter_value (&iter))) {
            bson_set_error (error,
                            MONGOC_ERROR_BSON,
                            MONGOC_ERROR_BSON_INVALID,
                            "Invalid 'opts' parameter.");
            return false;
         }
      }
   }

   return true;
}

void
_mongoc_insert_many_opts_cleanup (mongoc_insert_many_opts_t *mongoc_insert_many_opts)
{
   if (mongoc_insert_many_opts->crud.write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_insert_many_opts->crud.writeConcern);
   }
   bson_destroy (&mongoc_insert_many_opts->extra);
}

bool
_mongoc_delete_one_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_delete_one_opts_t *mongoc_delete_one_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_delete_one_opts->crud.writeConcern = NULL;
   mongoc_delete_one_opts->crud.write_concern_owned = false;
   mongoc_delete_one_opts->crud.client_session = NULL;
   mongoc_delete_one_opts->crud.validate = BSON_VALIDATE_NONE;
   bson_init (&mongoc_delete_one_opts->collation);
   bson_init (&mongoc_delete_one_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_delete_one_opts->crud.writeConcern,
               error)) {
            return false;
         }

         mongoc_delete_one_opts->crud.write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_delete_one_opts->crud.client_session,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_delete_one_opts->crud.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_delete_one_opts->collation,
               error)) {
            return false;
         }
      }
      else {
         /* unrecognized values are copied to "extra" */
         if (!BSON_APPEND_VALUE (
               &mongoc_delete_one_opts->extra,
               bson_iter_key (&iter),
               bson_iter_value (&iter))) {
            bson_set_error (error,
                            MONGOC_ERROR_BSON,
                            MONGOC_ERROR_BSON_INVALID,
                            "Invalid 'opts' parameter.");
            return false;
         }
      }
   }

   return true;
}

void
_mongoc_delete_one_opts_cleanup (mongoc_delete_one_opts_t *mongoc_delete_one_opts)
{
   if (mongoc_delete_one_opts->crud.write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_delete_one_opts->crud.writeConcern);
   }
   bson_destroy (&mongoc_delete_one_opts->collation);
   bson_destroy (&mongoc_delete_one_opts->extra);
}

bool
_mongoc_delete_many_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_delete_many_opts_t *mongoc_delete_many_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_delete_many_opts->crud.writeConcern = NULL;
   mongoc_delete_many_opts->crud.write_concern_owned = false;
   mongoc_delete_many_opts->crud.client_session = NULL;
   mongoc_delete_many_opts->crud.validate = BSON_VALIDATE_NONE;
   bson_init (&mongoc_delete_many_opts->collation);
   bson_init (&mongoc_delete_many_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_delete_many_opts->crud.writeConcern,
               error)) {
            return false;
         }

         mongoc_delete_many_opts->crud.write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_delete_many_opts->crud.client_session,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_delete_many_opts->crud.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_delete_many_opts->collation,
               error)) {
            return false;
         }
      }
      else {
         /* unrecognized values are copied to "extra" */
         if (!BSON_APPEND_VALUE (
               &mongoc_delete_many_opts->extra,
               bson_iter_key (&iter),
               bson_iter_value (&iter))) {
            bson_set_error (error,
                            MONGOC_ERROR_BSON,
                            MONGOC_ERROR_BSON_INVALID,
                            "Invalid 'opts' parameter.");
            return false;
         }
      }
   }

   return true;
}

void
_mongoc_delete_many_opts_cleanup (mongoc_delete_many_opts_t *mongoc_delete_many_opts)
{
   if (mongoc_delete_many_opts->crud.write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_delete_many_opts->crud.writeConcern);
   }
   bson_destroy (&mongoc_delete_many_opts->collation);
   bson_destroy (&mongoc_delete_many_opts->extra);
}

bool
_mongoc_update_one_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_update_one_opts_t *mongoc_update_one_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_update_one_opts->update.crud.writeConcern = NULL;
   mongoc_update_one_opts->update.crud.write_concern_owned = false;
   mongoc_update_one_opts->update.crud.client_session = NULL;
   mongoc_update_one_opts->update.crud.validate = _mongoc_default_update_vflags;
   mongoc_update_one_opts->update.bypass = false;
   bson_init (&mongoc_update_one_opts->update.collation);
   mongoc_update_one_opts->update.upsert = false;
   bson_init (&mongoc_update_one_opts->arrayFilters);
   bson_init (&mongoc_update_one_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_update_one_opts->update.crud.writeConcern,
               error)) {
            return false;
         }

         mongoc_update_one_opts->update.crud.write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_update_one_opts->update.crud.client_session,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_update_one_opts->update.crud.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_update_one_opts->update.bypass,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_update_one_opts->update.collation,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "upsert")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_update_one_opts->update.upsert,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) {
         if (!_mongoc_convert_array (
               client,
               &iter,
               &mongoc_update_one_opts->arrayFilters,
               error)) {
            return false;
         }
      }
      else {
         /* unrecognized values are copied to "extra" */
         if (!BSON_APPEND_VALUE (
               &mongoc_update_one_opts->extra,
               bson_iter_key (&iter),
               bson_iter_value (&iter))) {
            bson_set_error (error,
                            MONGOC_ERROR_BSON,
                            MONGOC_ERROR_BSON_INVALID,
                            "Invalid 'opts' parameter.");
            return false;
         }
      }
   }

   return true;
}

void
_mongoc_update_one_opts_cleanup (mongoc_update_one_opts_t *mongoc_update_one_opts)
{
   if (mongoc_update_one_opts->update.crud.write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_update_one_opts->update.crud.writeConcern);
   }
   bson_destroy (&mongoc_update_one_opts->update.collation);
   bson_destroy (&mongoc_update_one_opts->arrayFilters);
   bson_destroy (&mongoc_update_one_opts->extra);
}

bool
_mongoc_update_many_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_update_many_opts_t *mongoc_update_many_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_update_many_opts->update.crud.writeConcern = NULL;
   mongoc_update_many_opts->update.crud.write_concern_owned = false;
   mongoc_update_many_opts->update.crud.client_session = NULL;
   mongoc_update_many_opts->update.crud.validate = _mongoc_default_update_vflags;
   mongoc_update_many_opts->update.bypass = false;
   bson_init (&mongoc_update_many_opts->update.collation);
   mongoc_update_many_opts->update.upsert = false;
   bson_init (&mongoc_update_many_opts->arrayFilters);
   bson_init (&mongoc_update_many_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_update_many_opts->update.crud.writeConcern,
               error)) {
            return false;
         }

         mongoc_update_many_opts->update.crud.write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_update_many_opts->update.crud.client_session,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_update_many_opts->update.crud.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_update_many_opts->update.bypass,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_update_many_opts->update.collation,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "upsert")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_update_many_opts->update.upsert,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) {
         if (!_mongoc_convert_array (
               client,
               &iter,
               &mongoc_update_many_opts->arrayFilters,
               error)) {
            return false;
         }
      }
      else {
         /* unrecognized values are copied to "extra" */
         if (!BSON_APPEND_VALUE (
               &mongoc_update_many_opts->extra,
               bson_iter_key (&iter),
               bson_iter_value (&iter))) {
            bson_set_error (error,
                            MONGOC_ERROR_BSON,
                            MONGOC_ERROR_BSON_INVALID,
                            "Invalid 'opts' parameter.");
            return false;
         }
      }
   }

   return true;
}

void
_mongoc_update_many_opts_cleanup (mongoc_update_many_opts_t *mongoc_update_many_opts)
{
   if (mongoc_update_many_opts->update.crud.write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_update_many_opts->update.crud.writeConcern);
   }
   bson_destroy (&mongoc_update_many_opts->update.collation);
   bson_destroy (&mongoc_update_many_opts->arrayFilters);
   bson_destroy (&mongoc_update_many_opts->extra);
}

bool
_mongoc_replace_one_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_replace_one_opts_t *mongoc_replace_one_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_replace_one_opts->update.crud.writeConcern = NULL;
   mongoc_replace_one_opts->update.crud.write_concern_owned = false;
   mongoc_replace_one_opts->update.crud.client_session = NULL;
   mongoc_replace_one_opts->update.crud.validate = _mongoc_default_replace_vflags;
   mongoc_replace_one_opts->update.bypass = false;
   bson_init (&mongoc_replace_one_opts->update.collation);
   mongoc_replace_one_opts->update.upsert = false;
   bson_init (&mongoc_replace_one_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_replace_one_opts->update.crud.writeConcern,
               error)) {
            return false;
         }

         mongoc_replace_one_opts->update.crud.write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_replace_one_opts->update.crud.client_session,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_replace_one_opts->update.crud.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_replace_one_opts->update.bypass,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_replace_one_opts->update.collation,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "upsert")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_replace_one_opts->update.upsert,
               error)) {
            return false;
         }
      }
      else {
         /* unrecognized values are copied to "extra" */
         if (!BSON_APPEND_VALUE (
               &mongoc_replace_one_opts->extra,
               bson_iter_key (&iter),
               bson_iter_value (&iter))) {
            bson_set_error (error,
                            MONGOC_ERROR_BSON,
                            MONGOC_ERROR_BSON_INVALID,
                            "Invalid 'opts' parameter.");
            return false;
         }
      }
   }

   return true;
}

void
_mongoc_replace_one_opts_cleanup (mongoc_replace_one_opts_t *mongoc_replace_one_opts)
{
   if (mongoc_replace_one_opts->update.crud.write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_replace_one_opts->update.crud.writeConcern);
   }
   bson_destroy (&mongoc_replace_one_opts->update.collation);
   bson_destroy (&mongoc_replace_one_opts->extra);
}

bool
_mongoc_bulk_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_bulk_opts_t *mongoc_bulk_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_bulk_opts->writeConcern = NULL;
   mongoc_bulk_opts->write_concern_owned = false;
   mongoc_bulk_opts->ordered = true;
   mongoc_bulk_opts->client_session = NULL;
   bson_init (&mongoc_bulk_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_bulk_opts->writeConcern,
               error)) {
            return false;
         }

         mongoc_bulk_opts->write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "ordered")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_bulk_opts->ordered,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_bulk_opts->client_session,
               error)) {
            return false;
         }
      }
      else {
         bson_set_error (error,
                         MONGOC_ERROR_COMMAND,
                         MONGOC_ERROR_COMMAND_INVALID_ARG,
                         "Invalid option '%s'",
                         bson_iter_key (&iter));
         return false;
      }
   }

   return true;
}

void
_mongoc_bulk_opts_cleanup (mongoc_bulk_opts_t *mongoc_bulk_opts)
{
   if (mongoc_bulk_opts->write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_bulk_opts->writeConcern);
   }
   bson_destroy (&mongoc_bulk_opts->extra);
}

bool
_mongoc_bulk_insert_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_bulk_insert_opts_t *mongoc_bulk_insert_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_bulk_insert_opts->validate = _mongoc_default_insert_vflags;
   bson_init (&mongoc_bulk_insert_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_bulk_insert_opts->validate,
               error)) {
            return false;
         }
      }
      else {
         bson_set_error (error,
                         MONGOC_ERROR_COMMAND,
                         MONGOC_ERROR_COMMAND_INVALID_ARG,
                         "Invalid option '%s'",
                         bson_iter_key (&iter));
         return false;
      }
   }

   return true;
}

void
_mongoc_bulk_insert_opts_cleanup (mongoc_bulk_insert_opts_t *mongoc_bulk_insert_opts)
{
   bson_destroy (&mongoc_bulk_insert_opts->extra);
}

bool
_mongoc_bulk_update_one_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_bulk_update_one_opts_t *mongoc_bulk_update_one_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_bulk_update_one_opts->update.validate = _mongoc_default_update_vflags;
   bson_init (&mongoc_bulk_update_one_opts->update.collation);
   mongoc_bulk_update_one_opts->update.upsert = false;
   mongoc_bulk_update_one_opts->update.multi = false;
   bson_init (&mongoc_bulk_update_one_opts->arrayFilters);
   bson_init (&mongoc_bulk_update_one_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_bulk_update_one_opts->update.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_bulk_update_one_opts->update.collation,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "upsert")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_bulk_update_one_opts->update.upsert,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "multi")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_bulk_update_one_opts->update.multi,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) {
         if (!_mongoc_convert_array (
               client,
               &iter,
               &mongoc_bulk_update_one_opts->arrayFilters,
               error)) {
            return false;
         }
      }
      else {
         bson_set_error (error,
                         MONGOC_ERROR_COMMAND,
                         MONGOC_ERROR_COMMAND_INVALID_ARG,
                         "Invalid option '%s'",
                         bson_iter_key (&iter));
         return false;
      }
   }

   return true;
}

void
_mongoc_bulk_update_one_opts_cleanup (mongoc_bulk_update_one_opts_t *mongoc_bulk_update_one_opts)
{
   bson_destroy (&mongoc_bulk_update_one_opts->update.collation);
   bson_destroy (&mongoc_bulk_update_one_opts->arrayFilters);
   bson_destroy (&mongoc_bulk_update_one_opts->extra);
}

bool
_mongoc_bulk_update_many_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_bulk_update_many_opts_t *mongoc_bulk_update_many_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_bulk_update_many_opts->update.validate = _mongoc_default_update_vflags;
   bson_init (&mongoc_bulk_update_many_opts->update.collation);
   mongoc_bulk_update_many_opts->update.upsert = false;
   mongoc_bulk_update_many_opts->update.multi = true;
   bson_init (&mongoc_bulk_update_many_opts->arrayFilters);
   bson_init (&mongoc_bulk_update_many_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_bulk_update_many_opts->update.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_bulk_update_many_opts->update.collation,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "upsert")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_bulk_update_many_opts->update.upsert,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "multi")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_bulk_update_many_opts->update.multi,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) {
         if (!_mongoc_convert_array (
               client,
               &iter,
               &mongoc_bulk_update_many_opts->arrayFilters,
               error)) {
            return false;
         }
      }
      else {
         bson_set_error (error,
                         MONGOC_ERROR_COMMAND,
                         MONGOC_ERROR_COMMAND_INVALID_ARG,
                         "Invalid option '%s'",
                         bson_iter_key (&iter));
         return false;
      }
   }

   return true;
}

void
_mongoc_bulk_update_many_opts_cleanup (mongoc_bulk_update_many_opts_t *mongoc_bulk_update_many_opts)
{
   bson_destroy (&mongoc_bulk_update_many_opts->update.collation);
   bson_destroy (&mongoc_bulk_update_many_opts->arrayFilters);
   bson_destroy (&mongoc_bulk_update_many_opts->extra);
}

bool
_mongoc_bulk_replace_one_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_bulk_replace_one_opts_t *mongoc_bulk_replace_one_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_bulk_replace_one_opts->update.validate = _mongoc_default_replace_vflags;
   bson_init (&mongoc_bulk_replace_one_opts->update.collation);
   mongoc_bulk_replace_one_opts->update.upsert = false;
   mongoc_bulk_replace_one_opts->update.multi = false;
   bson_init (&mongoc_bulk_replace_one_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "validate")) {
         if (!_mongoc_convert_validate_flags (
               client,
               &iter,
               &mongoc_bulk_replace_one_opts->update.validate,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_bulk_replace_one_opts->update.collation,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "upsert")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_bulk_replace_one_opts->update.upsert,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "multi")) {
         if (!_mongoc_convert_bool (
               client,
               &iter,
               &mongoc_bulk_replace_one_opts->update.multi,
               error)) {
            return false;
         }
      }
      else {
         bson_set_error (error,
                         MONGOC_ERROR_COMMAND,
                         MONGOC_ERROR_COMMAND_INVALID_ARG,
                         "Invalid option '%s'",
                         bson_iter_key (&iter));
         return false;
      }
   }

   return true;
}

void
_mongoc_bulk_replace_one_opts_cleanup (mongoc_bulk_replace_one_opts_t *mongoc_bulk_replace_one_opts)
{
   bson_destroy (&mongoc_bulk_replace_one_opts->update.collation);
   bson_destroy (&mongoc_bulk_replace_one_opts->extra);
}

bool
_mongoc_bulk_remove_one_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_bulk_remove_one_opts_t *mongoc_bulk_remove_one_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   bson_init (&mongoc_bulk_remove_one_opts->remove.collation);
   mongoc_bulk_remove_one_opts->remove.limit = 1;
   bson_init (&mongoc_bulk_remove_one_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_bulk_remove_one_opts->remove.collation,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "limit")) {
         if (!_mongoc_convert_int32_t (
               client,
               &iter,
               &mongoc_bulk_remove_one_opts->remove.limit,
               error)) {
            return false;
         }
      }
      else {
         bson_set_error (error,
                         MONGOC_ERROR_COMMAND,
                         MONGOC_ERROR_COMMAND_INVALID_ARG,
                         "Invalid option '%s'",
                         bson_iter_key (&iter));
         return false;
      }
   }

   return true;
}

void
_mongoc_bulk_remove_one_opts_cleanup (mongoc_bulk_remove_one_opts_t *mongoc_bulk_remove_one_opts)
{
   bson_destroy (&mongoc_bulk_remove_one_opts->remove.collation);
   bson_destroy (&mongoc_bulk_remove_one_opts->extra);
}

bool
_mongoc_bulk_remove_many_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_bulk_remove_many_opts_t *mongoc_bulk_remove_many_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   bson_init (&mongoc_bulk_remove_many_opts->remove.collation);
   mongoc_bulk_remove_many_opts->remove.limit = 0;
   bson_init (&mongoc_bulk_remove_many_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_bulk_remove_many_opts->remove.collation,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "limit")) {
         if (!_mongoc_convert_int32_t (
               client,
               &iter,
               &mongoc_bulk_remove_many_opts->remove.limit,
               error)) {
            return false;
         }
      }
      else {
         bson_set_error (error,
                         MONGOC_ERROR_COMMAND,
                         MONGOC_ERROR_COMMAND_INVALID_ARG,
                         "Invalid option '%s'",
                         bson_iter_key (&iter));
         return false;
      }
   }

   return true;
}

void
_mongoc_bulk_remove_many_opts_cleanup (mongoc_bulk_remove_many_opts_t *mongoc_bulk_remove_many_opts)
{
   bson_destroy (&mongoc_bulk_remove_many_opts->remove.collation);
   bson_destroy (&mongoc_bulk_remove_many_opts->extra);
}

bool
_mongoc_create_index_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_create_index_opts_t *mongoc_create_index_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   mongoc_create_index_opts->writeConcern = NULL;
   mongoc_create_index_opts->write_concern_owned = false;
   mongoc_create_index_opts->client_session = NULL;
   bson_init (&mongoc_create_index_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_create_index_opts->writeConcern,
               error)) {
            return false;
         }

         mongoc_create_index_opts->write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_create_index_opts->client_session,
               error)) {
            return false;
         }
      }
      else {
         /* unrecognized values are copied to "extra" */
         if (!BSON_APPEND_VALUE (
               &mongoc_create_index_opts->extra,
               bson_iter_key (&iter),
               bson_iter_value (&iter))) {
            bson_set_error (error,
                            MONGOC_ERROR_BSON,
                            MONGOC_ERROR_BSON_INVALID,
                            "Invalid 'opts' parameter.");
            return false;
         }
      }
   }

   return true;
}

void
_mongoc_create_index_opts_cleanup (mongoc_create_index_opts_t *mongoc_create_index_opts)
{
   if (mongoc_create_index_opts->write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_create_index_opts->writeConcern);
   }
   bson_destroy (&mongoc_create_index_opts->extra);
}

bool
_mongoc_read_write_opts_parse (
   mongoc_client_t *client,
   const bson_t *opts,
   mongoc_read_write_opts_t *mongoc_read_write_opts,
   bson_error_t *error)
{
   bson_iter_t iter;

   bson_init (&mongoc_read_write_opts->readConcern);
   mongoc_read_write_opts->writeConcern = NULL;
   mongoc_read_write_opts->write_concern_owned = false;
   mongoc_read_write_opts->client_session = NULL;
   bson_init (&mongoc_read_write_opts->collation);
   mongoc_read_write_opts->serverId = 0;
   bson_init (&mongoc_read_write_opts->extra);

   if (!opts) {
      return true;
   }

   if (!bson_iter_init (&iter, opts)) {
      bson_set_error (error,
                      MONGOC_ERROR_BSON,
                      MONGOC_ERROR_BSON_INVALID,
                      "Invalid 'opts' parameter.");
      return false;
   }

   while (bson_iter_next (&iter)) {
      if (!strcmp (bson_iter_key (&iter), "readConcern")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_read_write_opts->readConcern,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "writeConcern")) {
         if (!_mongoc_convert_write_concern (
               client,
               &iter,
               &mongoc_read_write_opts->writeConcern,
               error)) {
            return false;
         }

         mongoc_read_write_opts->write_concern_owned = true;
      }
      else if (!strcmp (bson_iter_key (&iter), "sessionId")) {
         if (!_mongoc_convert_session_id (
               client,
               &iter,
               &mongoc_read_write_opts->client_session,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "collation")) {
         if (!_mongoc_convert_document (
               client,
               &iter,
               &mongoc_read_write_opts->collation,
               error)) {
            return false;
         }
      }
      else if (!strcmp (bson_iter_key (&iter), "serverId")) {
         if (!_mongoc_convert_server_id (
               client,
               &iter,
               &mongoc_read_write_opts->serverId,
               error)) {
            return false;
         }
      }
      else {
         /* unrecognized values are copied to "extra" */
         if (!BSON_APPEND_VALUE (
               &mongoc_read_write_opts->extra,
               bson_iter_key (&iter),
               bson_iter_value (&iter))) {
            bson_set_error (error,
                            MONGOC_ERROR_BSON,
                            MONGOC_ERROR_BSON_INVALID,
                            "Invalid 'opts' parameter.");
            return false;
         }
      }
   }

   return true;
}

void
_mongoc_read_write_opts_cleanup (mongoc_read_write_opts_t *mongoc_read_write_opts)
{
   bson_destroy (&mongoc_read_write_opts->readConcern);
   if (mongoc_read_write_opts->write_concern_owned) {
      mongoc_write_concern_destroy (mongoc_read_write_opts->writeConcern);
   }
   bson_destroy (&mongoc_read_write_opts->collation);
   bson_destroy (&mongoc_read_write_opts->extra);
}
