/*
 * 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.
 */


#ifndef BSON_H
#define BSON_H

#define BSON_INSIDE

#include <bson/bson-bcon.h>              // IWYU pragma: export
#include <bson/bson-clock.h>             // IWYU pragma: export
#include <bson/bson-context.h>           // IWYU pragma: export
#include <bson/bson-decimal128.h>        // IWYU pragma: export
#include <bson/bson-iter.h>              // IWYU pragma: export
#include <bson/bson-json.h>              // IWYU pragma: export
#include <bson/bson-keys.h>              // IWYU pragma: export
#include <bson/bson-oid.h>               // IWYU pragma: export
#include <bson/bson-reader.h>            // IWYU pragma: export
#include <bson/bson-string.h>            // IWYU pragma: export
#include <bson/bson-types.h>             // IWYU pragma: export
#include <bson/bson-utf8.h>              // IWYU pragma: export
#include <bson/bson-value.h>             // IWYU pragma: export
#include <bson/bson-vector.h>            // IWYU pragma: export
#include <bson/bson-version-functions.h> // IWYU pragma: export
#include <bson/bson-writer.h>            // IWYU pragma: export
#include <bson/bson_t.h>                 // IWYU pragma: export
#include <bson/compat.h>                 // IWYU pragma: export
#include <bson/config.h>                 // IWYU pragma: export
#include <bson/error.h>                  // IWYU pragma: export
#include <bson/macros.h>                 // IWYU pragma: export
#include <bson/memory.h>                 // IWYU pragma: export
#include <bson/version.h>                // IWYU pragma: export

#include <string.h>
#include <time.h>

#undef BSON_INSIDE


BSON_BEGIN_DECLS


/**
 * bson_empty:
 * @b: a bson_t.
 *
 * Checks to see if @b is an empty BSON document. An empty BSON document is
 * a 5 byte document which contains the length (4 bytes) and a single NUL
 * byte indicating end of fields.
 */
#define bson_empty(b) (((b)->len == 5) || !bson_get_data((b))[4])


/**
 * bson_empty0:
 *
 * Like bson_empty() but treats NULL the same as an empty bson_t document.
 */
#define bson_empty0(b) (!(b) || bson_empty(b))


/**
 * bson_clear:
 *
 * Easily free a bson document and set it to NULL. Use like:
 *
 * bson_t *doc = bson_new();
 * bson_clear (&doc);
 * BSON_ASSERT (doc == NULL);
 */
#define bson_clear(bptr)        \
   do {                         \
      if (*(bptr)) {            \
         bson_destroy(*(bptr)); \
         *(bptr) = NULL;        \
      }                         \
   } while (0)


/**
 * BSON_MAX_SIZE:
 *
 * The maximum size in bytes of a BSON document.
 */
#define BSON_MAX_SIZE ((size_t)((1U << 31) - 1))


#define BSON_APPEND_ARRAY(b, key, val) bson_append_array(b, key, (int)strlen(key), val)

#define BSON_APPEND_ARRAY_BEGIN(b, key, child) bson_append_array_begin(b, key, (int)strlen(key), child)

#define BSON_APPEND_BINARY(b, key, subtype, val, len) bson_append_binary(b, key, (int)strlen(key), subtype, val, len)

#define BSON_APPEND_BOOL(b, key, val) bson_append_bool(b, key, (int)strlen(key), val)

#define BSON_APPEND_CODE(b, key, val) bson_append_code(b, key, (int)strlen(key), val)

#define BSON_APPEND_CODE_WITH_SCOPE(b, key, val, scope) \
   bson_append_code_with_scope(b, key, (int)strlen(key), val, scope)

#define BSON_APPEND_DBPOINTER(b, key, coll, oid) bson_append_dbpointer(b, key, (int)strlen(key), coll, oid)

#define BSON_APPEND_DOCUMENT_BEGIN(b, key, child) bson_append_document_begin(b, key, (int)strlen(key), child)

#define BSON_APPEND_DOUBLE(b, key, val) bson_append_double(b, key, (int)strlen(key), val)

#define BSON_APPEND_DOCUMENT(b, key, val) bson_append_document(b, key, (int)strlen(key), val)

#define BSON_APPEND_INT32(b, key, val) bson_append_int32(b, key, (int)strlen(key), val)

#define BSON_APPEND_INT64(b, key, val) bson_append_int64(b, key, (int)strlen(key), val)

#define BSON_APPEND_MINKEY(b, key) bson_append_minkey(b, key, (int)strlen(key))

#define BSON_APPEND_DECIMAL128(b, key, val) bson_append_decimal128(b, key, (int)strlen(key), val)

#define BSON_APPEND_MAXKEY(b, key) bson_append_maxkey(b, key, (int)strlen(key))

#define BSON_APPEND_NULL(b, key) bson_append_null(b, key, (int)strlen(key))

#define BSON_APPEND_OID(b, key, val) bson_append_oid(b, key, (int)strlen(key), val)

#define BSON_APPEND_REGEX(b, key, val, opt) bson_append_regex(b, key, (int)strlen(key), val, opt)

#define BSON_APPEND_UTF8(b, key, val) bson_append_utf8(b, key, (int)strlen(key), val, (int)strlen(val))

#define BSON_APPEND_SYMBOL(b, key, val) bson_append_symbol(b, key, (int)strlen(key), val, (int)strlen(val))

#define BSON_APPEND_TIME_T(b, key, val) bson_append_time_t(b, key, (int)strlen(key), val)

#define BSON_APPEND_TIMEVAL(b, key, val) bson_append_timeval(b, key, (int)strlen(key), val)

#define BSON_APPEND_DATE_TIME(b, key, val) bson_append_date_time(b, key, (int)strlen(key), val)

#define BSON_APPEND_TIMESTAMP(b, key, val, inc) bson_append_timestamp(b, key, (int)strlen(key), val, inc)

#define BSON_APPEND_UNDEFINED(b, key) bson_append_undefined(b, key, (int)strlen(key))

#define BSON_APPEND_VALUE(b, key, val) bson_append_value(b, key, (int)strlen(key), (val))


/**
 * bson_new:
 *
 * Allocates a new bson_t structure. Call the various bson_append_*()
 * functions to add fields to the bson. You can iterate the bson_t at any
 * time using a bson_iter_t and bson_iter_init().
 *
 * Returns: A newly allocated bson_t that should be freed with bson_destroy().
 */
BSON_EXPORT(bson_t *) bson_new(void);


BSON_EXPORT(bson_t *)
bson_new_from_json(const uint8_t *data, ssize_t len, bson_error_t *error);


BSON_EXPORT(bool)
bson_init_from_json(bson_t *bson, const char *data, ssize_t len, bson_error_t *error);


/**
 * bson_init_static:
 * @b: A pointer to a bson_t.
 * @data: The data buffer to use.
 * @length: The length of @data.
 *
 * Initializes a bson_t using @data and @length. This is ideal if you would
 * like to use a stack allocation for your bson and do not need to grow the
 * buffer. @data must be valid for the life of @b.
 *
 * Returns: true if initialized successfully; otherwise false.
 */
BSON_EXPORT(bool)
bson_init_static(bson_t *b, const uint8_t *data, size_t length);


/**
 * bson_init:
 * @b: A pointer to a bson_t.
 *
 * Initializes a bson_t for use. This function is useful to those that want a
 * stack allocated bson_t. The usefulness of a stack allocated bson_t is
 * marginal as the target buffer for content will still require heap
 * allocations. It can help reduce heap fragmentation on allocators that do
 * not employ SLAB/magazine semantics.
 *
 * You must call bson_destroy() with @b to release resources when you are done
 * using @b.
 */
BSON_EXPORT(void)
bson_init(bson_t *b);


/**
 * bson_reinit:
 * @b: (inout): A bson_t.
 *
 * This is equivalent to calling bson_destroy() and bson_init() on a #bson_t.
 * However, it will try to persist the existing malloc'd buffer if one exists.
 * This is useful in cases where you want to reduce malloc overhead while
 * building many documents.
 */
BSON_EXPORT(void)
bson_reinit(bson_t *b);


/**
 * bson_new_from_data:
 * @data: A buffer containing a serialized bson document.
 * @length: The length of the document in bytes.
 *
 * Creates a new bson_t structure using the data provided. @data should contain
 * at least @length bytes that can be copied into the new bson_t structure.
 *
 * Returns: A newly allocated bson_t that should be freed with bson_destroy().
 *   If the first four bytes (little-endian) of data do not match @length,
 *   then NULL will be returned.
 */
BSON_EXPORT(bson_t *)
bson_new_from_data(const uint8_t *data, size_t length);


/**
 * bson_new_from_buffer:
 * @buf: A pointer to a buffer containing a serialized bson document.
 * @buf_len: The length of the buffer in bytes.
 * @realloc_fun: a realloc like function
 * @realloc_fun_ctx: a context for the realloc function
 *
 * Creates a new bson_t structure using the data provided. @buf should contain
 * a bson document, or null pointer should be passed for new allocations.
 *
 * Returns: A newly allocated bson_t that should be freed with bson_destroy().
 *          The underlying buffer will be used and not be freed in destroy.
 */
BSON_EXPORT(bson_t *)
bson_new_from_buffer(uint8_t **buf, size_t *buf_len, bson_realloc_func realloc_func, void *realloc_func_ctx);


/**
 * bson_sized_new:
 * @size: A size_t containing the number of bytes to allocate.
 *
 * This will allocate a new bson_t with enough bytes to hold a buffer
 * sized @size. @size must be smaller than INT_MAX bytes.
 *
 * Returns: A newly allocated bson_t that should be freed with bson_destroy().
 */
BSON_EXPORT(bson_t *)
bson_sized_new(size_t size);


/**
 * bson_copy:
 * @bson: A bson_t.
 *
 * Copies @bson into a newly allocated bson_t. You must call bson_destroy()
 * when you are done with the resulting value to free its resources.
 *
 * Returns: A newly allocated bson_t that should be free'd with bson_destroy()
 */
BSON_EXPORT(bson_t *)
bson_copy(const bson_t *bson);


/**
 * bson_copy_to:
 * @src: The source bson_t.
 * @dst: The destination bson_t.
 *
 * Initializes @dst and copies the content from @src into @dst.
 */
BSON_EXPORT(void)
bson_copy_to(const bson_t *src, bson_t *dst);

/**
 * bson_copy_to_excluding_noinit:
 * @src: A bson_t.
 * @dst: A bson_t to initialize and copy into.
 * @first_exclude: First field name to exclude.
 *
 * Does not call bson_init() on the dst.
 */
BSON_EXPORT(void)
bson_copy_to_excluding_noinit(const bson_t *src, bson_t *dst, const char *first_exclude, ...) BSON_GNUC_NULL_TERMINATED;

BSON_EXPORT(void)
bson_copy_to_excluding_noinit_va(const bson_t *src, bson_t *dst, const char *first_exclude, va_list args);


/**
 * bson_destroy:
 * @bson: A bson_t.
 *
 * Frees the resources associated with @bson.
 */
BSON_EXPORT(void)
bson_destroy(bson_t *bson);

BSON_EXPORT(uint8_t *)
bson_reserve_buffer(bson_t *bson, uint32_t total_size);

BSON_EXPORT(bool)
bson_steal(bson_t *dst, bson_t *src);


/**
 * bson_destroy_with_steal:
 * @bson: A #bson_t.
 * @steal: If ownership of the data buffer should be transferred to caller.
 * @length: (out): location for the length of the buffer.
 *
 * Destroys @bson similar to calling bson_destroy() except that the underlying
 * buffer will be returned and ownership transferred to the caller if @steal
 * is non-zero.
 *
 * If length is non-NULL, the length of @bson will be stored in @length.
 *
 * It is a programming error to call this function with any bson that has
 * been initialized static, or is being used to create a subdocument with
 * functions such as bson_append_document_begin() or bson_append_array_begin().
 *
 * Returns: a buffer owned by the caller if @steal is true. Otherwise NULL.
 *    If there was an error, NULL is returned.
 */
BSON_EXPORT(uint8_t *)
bson_destroy_with_steal(bson_t *bson, bool steal, uint32_t *length);


/**
 * bson_get_data:
 * @bson: A bson_t.
 *
 * Fetched the data buffer for @bson of @bson->len bytes in length.
 *
 * Returns: A buffer that should not be modified or freed.
 */
BSON_EXPORT(const uint8_t *)
bson_get_data(const bson_t *bson);


/**
 * bson_count_keys:
 * @bson: A bson_t.
 *
 * Counts the number of elements found in @bson.
 */
BSON_EXPORT(uint32_t)
bson_count_keys(const bson_t *bson);


/**
 * bson_has_field:
 * @bson: A bson_t.
 * @key: The key to lookup.
 *
 * Checks to see if @bson contains a field named @key.
 *
 * This function is case-sensitive.
 *
 * Returns: true if @key exists in @bson; otherwise false.
 */
BSON_EXPORT(bool)
bson_has_field(const bson_t *bson, const char *key);


/**
 * bson_compare:
 * @bson: A bson_t.
 * @other: A bson_t.
 *
 * Compares @bson to @other in a qsort() style comparison.
 * See qsort() for information on how this function works.
 *
 * Returns: Less than zero, zero, or greater than zero.
 */
BSON_EXPORT(int)
bson_compare(const bson_t *bson, const bson_t *other);

/*
 * bson_equal:
 * @bson: A bson_t.
 * @other: A bson_t.
 *
 * Checks to see if @bson and @other are equal.
 *
 * Returns: true if equal; otherwise false.
 */
BSON_EXPORT(bool)
bson_equal(const bson_t *bson, const bson_t *other);


/**
 * bson_validate:
 * @bson: A bson_t.
 * @offset: A location for the error offset.
 *
 * Validates a BSON document by walking through the document and inspecting
 * the fields for valid content.
 *
 * Returns: true if @bson is valid; otherwise false and @offset is set.
 */
BSON_EXPORT(bool)
bson_validate(const bson_t *bson, bson_validate_flags_t flags, size_t *offset);


/**
 * bson_validate_with_error:
 * @bson: A bson_t.
 * @error: A location for the error info.
 *
 * Validates a BSON document by walking through the document and inspecting
 * the fields for valid content.
 *
 * Returns: true if @bson is valid; otherwise false and @error is filled out.
 */
BSON_EXPORT(bool)
bson_validate_with_error(const bson_t *bson, bson_validate_flags_t flags, bson_error_t *error);


/**
 * bson_validate_with_error_and_offset:
 * @bson: A bson_t.
 * @offset: A location for the error offset.
 * @error: A location for the error info.
 *
 * Validates a BSON document by walking through the document and inspecting
 * the fields for valid content.
 *
 * Returns: true if @bson is valid; otherwise false, @offset is set
 * and @error is filled out.
 */
BSON_EXPORT(bool)
bson_validate_with_error_and_offset(const bson_t *bson,
                                    bson_validate_flags_t flags,
                                    size_t *offset,
                                    bson_error_t *error);


/**
 * bson_as_json_with_opts:
 * @bson: A bson_t.
 * @length: A location for the string length, or NULL.
 * @opts: A bson_t_json_opts_t defining options for the conversion
 *
 * Creates a new string containing @bson in the selected JSON format,
 * conforming to the MongoDB Extended JSON Spec:
 *
 * github.com/mongodb/specifications/blob/master/source/extended-json.rst
 *
 * The caller is responsible for freeing the resulting string. If @length is
 * non-NULL, then the length of the resulting string will be placed in @length.
 *
 * See https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ for
 * more information on extended JSON.
 *
 * Returns: A newly allocated string that should be freed with bson_free().
 */
BSON_EXPORT(char *)
bson_as_json_with_opts(const bson_t *bson, size_t *length, const bson_json_opts_t *opts);


/**
 * bson_as_canonical_extended_json:
 * @bson: A bson_t.
 * @length: A location for the string length, or NULL.
 *
 * Creates a new string containing @bson in canonical extended JSON format,
 * conforming to the MongoDB Extended JSON Spec:
 *
 * github.com/mongodb/specifications/blob/master/source/extended-json.rst
 *
 * The caller is responsible for freeing the resulting string. If @length is
 * non-NULL, then the length of the resulting string will be placed in @length.
 *
 * See https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ for
 * more information on extended JSON.
 *
 * Returns: A newly allocated string that should be freed with bson_free().
 */
BSON_EXPORT(char *)
bson_as_canonical_extended_json(const bson_t *bson, size_t *length);


/**
 * bson_as_legacy_extended_json:
 * @bson: A bson_t.
 * @length: A location for the string length, or NULL.
 *
 * Creates a new string containing @bson in libbson's legacy JSON format.
 * Superseded by bson_as_canonical_extended_json and
 * bson_as_relaxed_extended_json. The caller is
 * responsible for freeing the resulting string. If @length is non-NULL, then
 * the length of the resulting string will be placed in @length.
 *
 * Returns: A newly allocated string that should be freed with bson_free().
 */

BSON_EXPORT(char *)
bson_as_legacy_extended_json(const bson_t *bson, size_t *length);


/**
 * bson_as_relaxed_extended_json:
 * @bson: A bson_t.
 * @length: A location for the string length, or NULL.
 *
 * Creates a new string containing @bson in relaxed extended JSON format,
 * conforming to the MongoDB Extended JSON Spec:
 *
 * github.com/mongodb/specifications/blob/master/source/extended-json.rst
 *
 * The caller is responsible for freeing the resulting string. If @length is
 * non-NULL, then the length of the resulting string will be placed in @length.
 *
 * See https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ for
 * more information on extended JSON.
 *
 * Returns: A newly allocated string that should be freed with bson_free().
 */
BSON_EXPORT(char *)
bson_as_relaxed_extended_json(const bson_t *bson, size_t *length);


/* like bson_as_legacy_extended_json() but for outermost arrays. */
BSON_EXPORT(char *)
bson_array_as_legacy_extended_json(const bson_t *bson, size_t *length);


/* like bson_as_relaxed_extended_json() but for outermost arrays. */
BSON_EXPORT(char *)
bson_array_as_relaxed_extended_json(const bson_t *bson, size_t *length);


/* like bson_as_canonical_extended_json() but for outermost arrays. */
BSON_EXPORT(char *)
bson_array_as_canonical_extended_json(const bson_t *bson, size_t *length);

// bson_array_builder_t defines an API for building arrays.
// BSON arrays require sequential numeric keys "0", "1", "2", ...
typedef struct _bson_array_builder_t bson_array_builder_t;

// bson_array_builder_new may be used to build a top-level BSON array. Example:
// `[1,2,3]`.
// To append an array field to a document (Example: `{ "field": [1,2,3] }`), use
// `bson_append_array_builder_begin`.
BSON_EXPORT(bson_array_builder_t *) bson_array_builder_new(void);

// bson_array_builder_build initializes and moves BSON data to `out`.
// `bab` may be reused and will start appending a new array at index "0".
BSON_EXPORT(bool)
bson_array_builder_build(bson_array_builder_t *bab, bson_t *out);

BSON_EXPORT(void)
bson_array_builder_destroy(bson_array_builder_t *bab);

BSON_EXPORT(bool)
bson_append_value(bson_t *bson, const char *key, int key_length, const bson_value_t *value);

#define BSON_APPEND_VALUE(b, key, val) bson_append_value(b, key, (int)strlen(key), (val))

BSON_EXPORT(bool)
bson_array_builder_append_value(bson_array_builder_t *bab, const bson_value_t *value);

/**
 * bson_append_array:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @array: A bson_t containing the array.
 *
 * Appends a BSON array to @bson. BSON arrays are like documents where the
 * key is the string version of the index. For example, the first item of the
 * array would have the key "0". The second item would have the index "1".
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_array(bson_t *bson, const char *key, int key_length, const bson_t *array);

#define BSON_APPEND_ARRAY(b, key, val) bson_append_array(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_array(bson_array_builder_t *bab, const bson_t *array);

/**
 * bson_append_array_from_vector:
 * @bson: A bson_t that will be modified.
 * @key: The key for the field.
 * @iter: A bson_iter_t pointing to any supported vector in another bson_t.
 *
 * If @iter points to a supported vector type, converts the vector to a BSON array appended to @bson.
 *
 * Returns: true if successful; false if append would overflow max size or @iter does not point to a vector in a
 * supported format.
 */
BSON_EXPORT(bool)
bson_append_array_from_vector(bson_t *bson, const char *key, int key_length, const bson_iter_t *iter);

#define BSON_APPEND_ARRAY_FROM_VECTOR(b, key, iter) bson_append_array_from_vector(b, key, (int)strlen(key), iter)

BSON_EXPORT(bool)
bson_array_builder_append_array_from_vector(bson_array_builder_t *bab, const bson_iter_t *iter);

/**
 * bson_append_binary:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @key_length: Optional length of 'key' in bytes, or -1 to use strlen(key).
 * @subtype: The bson_subtype_t of the binary item.
 * @binary: The binary buffer to append.
 * @length: The length of @binary.
 *
 * Appends a binary buffer to the BSON document.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_binary(
   bson_t *bson, const char *key, int key_length, bson_subtype_t subtype, const uint8_t *binary, uint32_t length);

#define BSON_APPEND_BINARY(b, key, subtype, val, len) bson_append_binary(b, key, (int)strlen(key), subtype, val, len)

BSON_EXPORT(bool)
bson_array_builder_append_binary(bson_array_builder_t *bab,
                                 bson_subtype_t subtype,
                                 const uint8_t *binary,
                                 uint32_t length);

/**
 * bson_append_binary_uninit:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @key_length: Optional length of 'key' in bytes, or -1 to use strlen(key).
 * @binary: Output parameter, pointer for the binary data within bson_t to be written.
 * @length: Length of the binary field to allocate, in bytes.
 *
 * Returns: true if successful; false if append would overflow max size.
 */

BSON_EXPORT(bool)
bson_append_binary_uninit(
   bson_t *bson, const char *key, int key_length, bson_subtype_t subtype, uint8_t **binary, uint32_t length);

#define BSON_APPEND_BINARY_UNINIT(b, key, subtype, val, len) \
   bson_append_binary_uninit(b, key, (int)strlen(key), subtype, val, len)

BSON_EXPORT(bool)
bson_array_builder_append_binary_uninit(bson_array_builder_t *bab,
                                        bson_subtype_t subtype,
                                        uint8_t **binary,
                                        uint32_t length);

/**
 * bson_append_bool:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @value: The boolean value.
 *
 * Appends a new field to @bson of type BSON_TYPE_BOOL.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_bool(bson_t *bson, const char *key, int key_length, bool value);

#define BSON_APPEND_BOOL(b, key, val) bson_append_bool(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_bool(bson_array_builder_t *bab, bool value);

/**
 * bson_append_code:
 * @bson: A bson_t.
 * @key: The key for the document.
 * @javascript: JavaScript code to be executed.
 *
 * Appends a field of type BSON_TYPE_CODE to the BSON document. @javascript
 * should contain a script in javascript to be executed.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_code(bson_t *bson, const char *key, int key_length, const char *javascript);

#define BSON_APPEND_CODE(b, key, val) bson_append_code(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_code(bson_array_builder_t *bab, const char *javascript);

/**
 * bson_append_code_with_scope:
 * @bson: A bson_t.
 * @key: The key for the document.
 * @javascript: JavaScript code to be executed.
 * @scope: A bson_t containing the scope for @javascript.
 *
 * Appends a field of type BSON_TYPE_CODEWSCOPE to the BSON document.
 * @javascript should contain a script in javascript to be executed.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_code_with_scope(bson_t *bson, const char *key, int key_length, const char *javascript, const bson_t *scope);

#define BSON_APPEND_CODE_WITH_SCOPE(b, key, val, scope) \
   bson_append_code_with_scope(b, key, (int)strlen(key), val, scope)

BSON_EXPORT(bool)
bson_array_builder_append_code_with_scope(bson_array_builder_t *bab, const char *javascript, const bson_t *scope);

/**
 * bson_append_dbpointer:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @collection: The collection name.
 * @oid: The oid to the reference.
 *
 * Appends a new field of type BSON_TYPE_DBPOINTER. This datum type is
 * deprecated in the BSON spec and should not be used in new code.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_dbpointer(bson_t *bson, const char *key, int key_length, const char *collection, const bson_oid_t *oid);

#define BSON_APPEND_DBPOINTER(b, key, coll, oid) bson_append_dbpointer(b, key, (int)strlen(key), coll, oid)

BSON_EXPORT(bool)
bson_array_builder_append_dbpointer(bson_array_builder_t *bab, const char *collection, const bson_oid_t *oid);

/**
 * bson_append_double:
 * @bson: A bson_t.
 * @key: The key for the field.
 *
 * Appends a new field to @bson of the type BSON_TYPE_DOUBLE.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_double(bson_t *bson, const char *key, int key_length, double value);

#define BSON_APPEND_DOUBLE(b, key, val) bson_append_double(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_double(bson_array_builder_t *bab, double value);

/**
 * bson_append_document:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @value: A bson_t containing the subdocument.
 *
 * Appends a new field to @bson of the type BSON_TYPE_DOCUMENT.
 * The documents contents will be copied into @bson.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_document(bson_t *bson, const char *key, int key_length, const bson_t *value);

#define BSON_APPEND_DOCUMENT(b, key, val) bson_append_document(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_document(bson_array_builder_t *bab, const bson_t *value);

/**
 * bson_append_document_begin:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @key_length: The length of @key in bytes not including NUL or -1
 *    if @key_length is NUL terminated.
 * @child: A location to an uninitialized bson_t.
 *
 * Appends a new field named @key to @bson. The field is, however,
 * incomplete.  @child will be initialized so that you may add fields to the
 * child document.  Child will use a memory buffer owned by @bson and
 * therefore grow the parent buffer as additional space is used. This allows
 * a single malloc'd buffer to be used when building documents which can help
 * reduce memory fragmentation.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_document_begin(bson_t *bson, const char *key, int key_length, bson_t *child);

#define BSON_APPEND_DOCUMENT_BEGIN(b, key, child) bson_append_document_begin(b, key, (int)strlen(key), child)

BSON_EXPORT(bool)
bson_array_builder_append_document_begin(bson_array_builder_t *bab, bson_t *child);

/**
 * bson_append_document_end:
 * @bson: A bson_t.
 * @child: A bson_t supplied to bson_append_document_begin().
 *
 * Finishes the appending of a document to a @bson. @child is considered
 * disposed after this call and should not be used any further.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_document_end(bson_t *bson, bson_t *child);

BSON_EXPORT(bool)
bson_array_builder_append_document_end(bson_array_builder_t *bab, bson_t *child);


/**
 * bson_append_array_begin:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @key_length: The length of @key in bytes not including NUL or -1
 *    if @key_length is NUL terminated.
 * @child: A location to an uninitialized bson_t.
 *
 * Appends a new field named @key to @bson. The field is, however,
 * incomplete. @child will be initialized so that you may add fields to the
 * child array. Child will use a memory buffer owned by @bson and
 * therefore grow the parent buffer as additional space is used. This allows
 * a single malloc'd buffer to be used when building arrays which can help
 * reduce memory fragmentation.
 *
 * The type of @child will be BSON_TYPE_ARRAY and therefore the keys inside
 * of it MUST be "0", "1", etc.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_array_begin(bson_t *bson, const char *key, int key_length, bson_t *child);

#define BSON_APPEND_ARRAY_BEGIN(b, key, child) bson_append_array_begin(b, key, (int)strlen(key), child)

/**
 * bson_append_array_end:
 * @bson: A bson_t.
 * @child: A bson_t supplied to bson_append_array_begin().
 *
 * Finishes the appending of a array to a @bson. @child is considered
 * disposed after this call and should not be used any further.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_array_end(bson_t *bson, bson_t *child);


/**
 * bson_append_int32:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @value: The int32_t 32-bit integer value.
 *
 * Appends a new field of type BSON_TYPE_INT32 to @bson.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_int32(bson_t *bson, const char *key, int key_length, int32_t value);

#define BSON_APPEND_INT32(b, key, val) bson_append_int32(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_int32(bson_array_builder_t *bab, int32_t value);

/**
 * bson_append_int64:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @value: The int64_t 64-bit integer value.
 *
 * Appends a new field of type BSON_TYPE_INT64 to @bson.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_int64(bson_t *bson, const char *key, int key_length, int64_t value);

#define BSON_APPEND_INT64(b, key, val) bson_append_int64(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_int64(bson_array_builder_t *bab, int64_t value);

/**
 * bson_append_decimal128:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @value: The bson_decimal128_t decimal128 value.
 *
 * Appends a new field of type BSON_TYPE_DECIMAL128 to @bson.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_decimal128(bson_t *bson, const char *key, int key_length, const bson_decimal128_t *value);

#define BSON_APPEND_DECIMAL128(b, key, val) bson_append_decimal128(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_decimal128(bson_array_builder_t *bab, const bson_decimal128_t *value);

/**
 * bson_append_iter:
 * @bson: A bson_t to append to.
 * @key: The key name or %NULL to take current key from @iter.
 * @key_length: The key length or -1 to use strlen().
 * @iter: The iter located on the position of the element to append.
 *
 * Appends a new field to @bson that is equivalent to the field currently
 * pointed to by @iter.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_iter(bson_t *bson, const char *key, int key_length, const bson_iter_t *iter);

#define BSON_APPEND_ITER(b, key, val) bson_append_iter(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_iter(bson_array_builder_t *bab, const bson_iter_t *iter);

/**
 * bson_append_minkey:
 * @bson: A bson_t.
 * @key: The key for the field.
 *
 * Appends a new field of type BSON_TYPE_MINKEY to @bson. This is a special
 * type that compares lower than all other possible BSON element values.
 *
 * See http://bsonspec.org for more information on this type.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_minkey(bson_t *bson, const char *key, int key_length);

#define BSON_APPEND_MINKEY(b, key) bson_append_minkey(b, key, (int)strlen(key))

BSON_EXPORT(bool)
bson_array_builder_append_minkey(bson_array_builder_t *bab);

/**
 * bson_append_maxkey:
 * @bson: A bson_t.
 * @key: The key for the field.
 *
 * Appends a new field of type BSON_TYPE_MAXKEY to @bson. This is a special
 * type that compares higher than all other possible BSON element values.
 *
 * See http://bsonspec.org for more information on this type.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_maxkey(bson_t *bson, const char *key, int key_length);

#define BSON_APPEND_MAXKEY(b, key) bson_append_maxkey(b, key, (int)strlen(key))

BSON_EXPORT(bool)
bson_array_builder_append_maxkey(bson_array_builder_t *bab);

/**
 * bson_append_null:
 * @bson: A bson_t.
 * @key: The key for the field.
 *
 * Appends a new field to @bson with NULL for the value.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_null(bson_t *bson, const char *key, int key_length);

#define BSON_APPEND_NULL(b, key) bson_append_null(b, key, (int)strlen(key))

BSON_EXPORT(bool)
bson_array_builder_append_null(bson_array_builder_t *bab);

/**
 * bson_append_oid:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @oid: bson_oid_t.
 *
 * Appends a new field to the @bson of type BSON_TYPE_OID using the contents of
 * @oid.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_oid(bson_t *bson, const char *key, int key_length, const bson_oid_t *oid);

#define BSON_APPEND_OID(b, key, val) bson_append_oid(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_oid(bson_array_builder_t *bab, const bson_oid_t *oid);

/**
 * bson_append_regex:
 * @bson: A bson_t.
 * @key: The key of the field.
 * @regex: The regex to append to the bson.
 * @options: Options for @regex.
 *
 * Appends a new field to @bson of type BSON_TYPE_REGEX. @regex should
 * be the regex string. @options should contain the options for the regex.
 *
 * Valid options for @options are:
 *
 *   'i' for case-insensitive.
 *   'm' for multiple matching.
 *   'x' for verbose mode.
 *   'l' to make \w and \W locale dependent.
 *   's' for dotall mode ('.' matches everything)
 *   'u' to make \w and \W match unicode.
 *
 * For more detailed information about BSON regex elements, see bsonspec.org.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_regex(bson_t *bson, const char *key, int key_length, const char *regex, const char *options);

#define BSON_APPEND_REGEX(b, key, val, opt) bson_append_regex(b, key, (int)strlen(key), val, opt)

BSON_EXPORT(bool)
bson_array_builder_append_regex(bson_array_builder_t *bab, const char *regex, const char *options);

/**
 * bson_append_regex:
 * @bson: A bson_t.
 * @key: The key of the field.
 * @key_length: The length of the key string.
 * @regex: The regex to append to the bson.
 * @regex_length: The length of the regex string.
 * @options: Options for @regex.
 *
 * Appends a new field to @bson of type BSON_TYPE_REGEX. @regex should
 * be the regex string. @options should contain the options for the regex.
 *
 * Valid options for @options are:
 *
 *   'i' for case-insensitive.
 *   'm' for multiple matching.
 *   'x' for verbose mode.
 *   'l' to make \w and \W locale dependent.
 *   's' for dotall mode ('.' matches everything)
 *   'u' to make \w and \W match unicode.
 *
 * For more detailed information about BSON regex elements, see bsonspec.org.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_regex_w_len(
   bson_t *bson, const char *key, int key_length, const char *regex, int regex_length, const char *options);

BSON_EXPORT(bool)
bson_array_builder_append_regex_w_len(bson_array_builder_t *bab,
                                      const char *regex,
                                      int regex_length,
                                      const char *options);

/**
 * bson_append_utf8:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @value: A UTF-8 encoded string.
 * @length: The length of @value or -1 if it is NUL terminated.
 *
 * Appends a new field to @bson using @key as the key and @value as the UTF-8
 * encoded value.
 *
 * It is the callers responsibility to ensure @value is valid UTF-8. You can
 * use bson_utf8_validate() to perform this check.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_utf8(bson_t *bson, const char *key, int key_length, const char *value, int length);

#define BSON_APPEND_UTF8(b, key, val) bson_append_utf8(b, key, (int)strlen(key), val, (int)strlen(val))

BSON_EXPORT(bool)
bson_array_builder_append_utf8(bson_array_builder_t *bab, const char *value, int length);

/**
 * bson_append_symbol:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @value: The symbol as a string.
 * @length: The length of @value or -1 if NUL-terminated.
 *
 * Appends a new field to @bson of type BSON_TYPE_SYMBOL. This BSON type is
 * deprecated and should not be used in new code.
 *
 * See http://bsonspec.org for more information on this type.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_symbol(bson_t *bson, const char *key, int key_length, const char *value, int length);

#define BSON_APPEND_SYMBOL(b, key, val) bson_append_symbol(b, key, (int)strlen(key), val, (int)strlen(val))

BSON_EXPORT(bool)
bson_array_builder_append_symbol(bson_array_builder_t *bab, const char *value, int length);

/**
 * bson_append_time_t:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @value: A time_t.
 *
 * Appends a BSON_TYPE_DATE_TIME field to @bson using the time_t @value for the
 * number of seconds since UNIX epoch in UTC.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_time_t(bson_t *bson, const char *key, int key_length, time_t value);

#define BSON_APPEND_TIME_T(b, key, val) bson_append_time_t(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_time_t(bson_array_builder_t *bab, time_t value);

/**
 * bson_append_timeval:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @value: A struct timeval containing the date and time.
 *
 * Appends a BSON_TYPE_DATE_TIME field to @bson using the struct timeval
 * provided. The time is persisted in milliseconds since the UNIX epoch in UTC.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_timeval(bson_t *bson, const char *key, int key_length, struct timeval *value);

#define BSON_APPEND_TIMEVAL(b, key, val) bson_append_timeval(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_timeval(bson_array_builder_t *bab, struct timeval *value);

/**
 * bson_append_date_time:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @key_length: The length of @key in bytes or -1 if \0 terminated.
 * @value: The number of milliseconds elapsed since UNIX epoch.
 *
 * Appends a new field to @bson of type BSON_TYPE_DATE_TIME.
 *
 * Returns: true if successful; otherwise false.
 */
BSON_EXPORT(bool)
bson_append_date_time(bson_t *bson, const char *key, int key_length, int64_t value);

#define BSON_APPEND_DATE_TIME(b, key, val) bson_append_date_time(b, key, (int)strlen(key), val)

BSON_EXPORT(bool)
bson_array_builder_append_date_time(bson_array_builder_t *bab, int64_t value);

/**
 * bson_append_now_utc:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @key_length: The length of @key or -1 if it is NULL terminated.
 *
 * Appends a BSON_TYPE_DATE_TIME field to @bson using the current time in UTC
 * as the field value.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_now_utc(bson_t *bson, const char *key, int key_length);

#define BSON_APPEND_NOW_UTC(b, key) bson_append_now_utc(b, key, (int)strlen(key))

BSON_EXPORT(bool)
bson_array_builder_append_now_utc(bson_array_builder_t *bab);

/**
 * bson_append_timestamp:
 * @bson: A bson_t.
 * @key: The key for the field.
 * @timestamp: 4 byte timestamp.
 * @increment: 4 byte increment for timestamp.
 *
 * Appends a field of type BSON_TYPE_TIMESTAMP to @bson. This is a special type
 * used by MongoDB replication and sharding. If you need generic time and date
 * fields use bson_append_time_t() or bson_append_timeval().
 *
 * Setting @increment and @timestamp to zero has special semantics. See
 * http://bsonspec.org for more information on this field type.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_timestamp(bson_t *bson, const char *key, int key_length, uint32_t timestamp, uint32_t increment);

#define BSON_APPEND_TIMESTAMP(b, key, val, inc) bson_append_timestamp(b, key, (int)strlen(key), val, inc)

BSON_EXPORT(bool)
bson_array_builder_append_timestamp(bson_array_builder_t *bab, uint32_t timestamp, uint32_t increment);

/**
 * bson_append_undefined:
 * @bson: A bson_t.
 * @key: The key for the field.
 *
 * Appends a field of type BSON_TYPE_UNDEFINED. This type is deprecated in the
 * spec and should not be used for new code. However, it is provided for those
 * needing to interact with legacy systems.
 *
 * Returns: true if successful; false if append would overflow max size.
 */
BSON_EXPORT(bool)
bson_append_undefined(bson_t *bson, const char *key, int key_length);

#define BSON_APPEND_UNDEFINED(b, key) bson_append_undefined(b, key, (int)strlen(key))

BSON_EXPORT(bool)
bson_array_builder_append_undefined(bson_array_builder_t *bab);

BSON_EXPORT(bool)
bson_concat(bson_t *dst, const bson_t *src);

BSON_EXPORT(bool)
bson_append_array_builder_begin(bson_t *bson, const char *key, int key_length, bson_array_builder_t **child);

#define BSON_APPEND_ARRAY_BUILDER_BEGIN(b, key, child) bson_append_array_builder_begin(b, key, (int)strlen(key), child)

BSON_EXPORT(bool)
bson_array_builder_append_array_builder_begin(bson_array_builder_t *bab, bson_array_builder_t **child);

BSON_EXPORT(bool)
bson_append_array_builder_end(bson_t *bson, bson_array_builder_t *child);

BSON_EXPORT(bool)
bson_array_builder_append_array_builder_end(bson_array_builder_t *bab, bson_array_builder_t *child);


BSON_END_DECLS


#endif /* BSON_H */
