BSON_REFERENCE(3)

๐Ÿ’– BSON_REFERENCE(3) ๐Ÿ’–

Okay bestie, this is the libbson manual page โ€” yes, the BSON_REFERENCE(3) one โ€” and itโ€™s giving โ€œC library but make it readable.โ€ Buckle up, weโ€™re doing this together. ๐Ÿซถ

๐ŸŒˆ LIBBSON - API ๐ŸŒˆ

A Cross Platform BSON Library for C

This site documents the API. For tutorials, guides, and explainers, see MongoDB C Driver.

โœจ Introduction โœจ

libbson literally builds, parses, and iterates BSON documents โ€” the native data format of MongoDB. It also converts BSON to and from JSON, and provides a platform compatibility layer for the MongoDB C Driver. Obsessed. ๐Ÿฆ‹

๐Ÿงš API Reference ๐Ÿงš

๐Ÿ’– bson_t ๐Ÿ’–

BSON Document Abstraction

๐ŸŒธ Synopsis ๐ŸŒธ

#include <bson/bson.h>

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

/**
 * bson_empty0:
 *
 * Like bson_empty() but treats NULL the same as an empty bson_t document.
 */
#define bson_empty0(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) /* ... */

/**
 * BSON_MAX_SIZE:
 *
 * The maximum size in bytes of a BSON document.
 */
#define BSON_MAX_SIZE /* ... */

#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_BINARY_UNINIT(b, key, subtype, val, len) \
   bson_append_binary_uninit (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))

typedef struct {
   uint32_t flags;       /* Internal flags for the bson_t. */
   uint32_t len;         /* Length of BSON data. */
   uint8_t padding[120]; /* Padding for stack allocation. */
} bson_t;

๐Ÿ’ซ Description ๐Ÿ’ซ

The bson_t structure represents a BSON document. This structure manages the underlying BSON encoded buffer. For mutable documents, it can append new data to the document. ๐Ÿ’…

๐Ÿ”ฅ Performance Notes ๐Ÿ”ฅ

The bson_t structure attempts to use an inline allocation within the structure to speed up performance of small documents. When this internal buffer has been exhausted, a heap allocated buffer will be dynamically allocated. Therefore, it is essential to call bson_destroy() on allocated documents. No cap, that cleanup call is not optional. ๐Ÿงš

๐Ÿซถ Duplicate Keys ๐Ÿซถ

The BSON specification allows BSON documents to have duplicate keys. Documents are stored as an ordered list of key-value pairs. A bson_t may contain duplicate keys. Applications should refrain from generating such documents, because MongoDB server behavior is undefined when a BSON document contains duplicate keys. That โ€œundefinedโ€ is doing a lot of heavy lifting, so donโ€™t test it. ๐Ÿ˜ญ

๐ŸŽ€ Example ๐ŸŽ€

static void
create_on_heap (void)
{
   bson_t *b = bson_new ();

   BSON_APPEND_INT32 (b, "foo", 123);
   BSON_APPEND_UTF8 (b, "bar", "foo");
   BSON_APPEND_DOUBLE (b, "baz", 1.23f);

   bson_destroy (b);
}

๐Ÿฆ‹ bson_t lifetimes ๐Ÿฆ‹

A bson_t may contain its data directly or may contain pointers to heap-allocated memory. Overwriting an existing bson_t or allowing a stack-allocated bson_t to go out of scope may cause a memory leak. A bson_t should always be destroyed with bson_destroy(). Periodt. ๐Ÿ’œ

๐Ÿ‘‘ bson_t out parameters ๐Ÿ‘‘

A bson_t pointer used as an out parameter must point to valid overwritable storage for a new bson_t which must be one of:

  1. Uninitialized storage for a bson_t.
  2. A zero-initialized bson_t object.
  3. A bson_t object initialized with BSON_INITIALIZER.
  4. A bson_t object not created with bson_new() that was destroyed with bson_destroy().

This can be on the stack:

bson_t stack_doc = BSON_INITIALIZER;
example_get_doc (&stack_doc);
bson_destroy (&stack_doc);

Or on the heap:

bson_t *heap_doc = bson_malloc (sizeof (bson_t));
example_get_doc (heap_doc);
bson_destroy (heap_doc);
bson_free (heap_doc);

Omitting bson_destroy() in either case may cause memory leaks.

WARNING: Passing a bson_t pointer obtained from bson_new() as an out parameter will result in a leak of the bson_t struct.
bson_t *heap_doc = bson_new ();
example_get_doc (heap_doc);
bson_destroy (heap_doc); // Leaks the `bson_t` struct!

๐Ÿ’… bson_array_builder_t ๐Ÿ’…

typedef struct _bson_array_builder_t bson_array_builder_t;

bson_array_builder_t may be used to build BSON arrays. bson_array_builder_t internally tracks and uses the array index as a key ("0", "1", "2", ...) when appending elements. Itโ€™s giving organized. ๐Ÿ“

๐ŸŒˆ Appending an array value ๐ŸŒˆ

typedef struct _bson_array_builder_t bson_array_builder_t;

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

bool
bson_append_array_builder_end (bson_t *bson, 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_append_array_builder_begin may be used to append an array as a value. Example:

bson_t parent = BSON_INITIALIZER;
bson_array_builder_t *bab;

bson_append_array_builder_begin(&parent, "foo", 3, &bab);
bson_array_builder_append_int32(bab, 9);
bson_array_builder_append_int32(bab, 8);
bson_array_builder_append_int32(bab, 7);
bson_append_array_builder_end(&parent, bab);

char *str = bson_as_relaxed_extended_json(&parent, NULL);
printf("%s\n", str); // Prints: { "foo" : [ 9, 8, 7 ] }
bson_free(str);

bson_destroy(&parent);

๐Ÿง Creating a top-level array ๐Ÿง

bson_array_builder_t * bson_array_builder_new (void);

bool
bson_array_builder_build (bson_array_builder_t *bab, bson_t *out);

void
bson_array_builder_destroy (bson_array_builder_t *bab);

bson_array_builder_new and bson_array_builder_build may be used to build a top-level BSON array. bson_array_builder_build initializes and moves BSON data to out. The bson_array_builder_t may be reused and will start appending a new array at index "0":

Example:

bson_t out;
bson_array_builder_t *bab = bson_array_builder_new();

bson_array_builder_append_int32(bab, 9);
bson_array_builder_append_int32(bab, 8);
bson_array_builder_append_int32(bab, 7);
bson_array_builder_build(bab, &out);

char *str = bson_array_as_relaxed_extended_json(&out, NULL);
printf("%s\n", str); // Prints: [ 9, 8, 7 ]
bson_free(str);

bson_array_builder_destroy(bab);

๐Ÿ“ Appending values to an array ๐Ÿ“

bson_array_builder_append_* functions are provided to append values to a BSON array. The bson_array_builder_append_* functions internally use bson_append_* and provide the array index as a key:

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

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

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

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

bool
bson_array_builder_append_bool (bson_array_builder_t *bab, bool value);

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

okay bestie, we're still deep in bson_array_builder_t land and there areโ€ฆ a LOT of append girlies left to meet. deep breath. full roster, signatures and all, no skips: ๐Ÿ’–

  • bson_array_builder_append_code_with_scope โ€” bool bson_array_builder_append_code_with_scope (bson_array_builder_t *bab, const char *javascript, const bson_t *scope); โ€” code with scope, bestie: the javascript plus the bson_t scope it lives with. โœจ
  • bson_array_builder_append_dbpointer โ€” bool bson_array_builder_append_dbpointer (bson_array_builder_t *bab, const char *collection, const bson_oid_t *oid); โ€” drops in a DBPointer built from a collection name and an oid. ๐ŸŽ€
  • bson_array_builder_append_double โ€” bool bson_array_builder_append_double (bson_array_builder_t *bab, double value); โ€” one double, zero drama. ๐Ÿ’…
  • bson_array_builder_append_document โ€” bool bson_array_builder_append_document (bson_array_builder_t *bab, const bson_t *value); โ€” slides a whole bson_t document in as one element. ๐Ÿฆ‹
  • bson_array_builder_append_document_begin โ€” bool bson_array_builder_append_document_begin (bson_array_builder_t *bab, bson_t *child); โ€” opens a nested document and hands you the child to fill in. ๐ŸŒธ
  • bson_array_builder_append_document_end โ€” bool bson_array_builder_append_document_end (bson_array_builder_t *bab, bson_t *child); โ€” closes that child document back up. ๐Ÿซถ
  • bson_array_builder_append_int32 โ€” bool bson_array_builder_append_int32 (bson_array_builder_t *bab, int32_t value); โ€” an int32_t. iconic, tiny. ๐Ÿ˜ญ
  • bson_array_builder_append_int64 โ€” bool bson_array_builder_append_int64 (bson_array_builder_t *bab, int64_t value); โ€” the int64_t upgrade, same energy. ๐Ÿ”ฅ
  • bson_array_builder_append_decimal128 โ€” bool bson_array_builder_append_decimal128 (bson_array_builder_t *bab, const bson_decimal128_t *value); โ€” appends a bson_decimal128_t (yes, that struct comes later on this page, keep reading ๐Ÿ’œ).
  • bson_array_builder_append_iter โ€” bool bson_array_builder_append_iter (bson_array_builder_t *bab, const bson_iter_t *iter); โ€” takes a bson_iter_t and appends from it. ๐Ÿ‘‘
  • bson_array_builder_append_minkey โ€” bool bson_array_builder_append_minkey (bson_array_builder_t *bab); โ€” MinKey, no args, no notes. โญ
  • bson_array_builder_append_maxkey โ€” bool bson_array_builder_append_maxkey (bson_array_builder_t *bab); โ€” MaxKey. the other end of the universe. ๐ŸŒˆ
  • bson_array_builder_append_null โ€” bool bson_array_builder_append_null (bson_array_builder_t *bab); โ€” null. that's it. that's the whole function. ๐Ÿ’€
  • bson_array_builder_append_oid โ€” bool bson_array_builder_append_oid (bson_array_builder_t *bab, const bson_oid_t *oid); โ€” an bson_oid_t, no cap. ๐Ÿ™ˆ
  • bson_array_builder_append_regex โ€” bool bson_array_builder_append_regex (bson_array_builder_t *bab, const char *regex, const char *options); โ€” a regex with its options string. ๐Ÿ“
  • bson_array_builder_append_regex_w_len โ€” bool bson_array_builder_append_regex_w_len (bson_array_builder_t *bab, const char *regex, int regex_length, const char *options); โ€” same thing but you pass regex_length yourself, main character energy. ๐Ÿงš
  • bson_array_builder_append_utf8 โ€” bool bson_array_builder_append_utf8 (bson_array_builder_t *bab, const char *value, int length); โ€” a UTF-8 string with an explicit length. โœจ
  • bson_array_builder_append_symbol โ€” bool bson_array_builder_append_symbol (bson_array_builder_t *bab, const char *value, int length); โ€” a symbol, length and all. ๐Ÿ’–
  • bson_array_builder_append_time_t โ€” bool bson_array_builder_append_time_t (bson_array_builder_t *bab, time_t value); โ€” from a time_t. ๐ŸŒธ
  • bson_array_builder_append_timeval โ€” bool bson_array_builder_append_timeval (bson_array_builder_t *bab, struct timeval *value); โ€” from a struct timeval *. ๐ŸŽ€
  • bson_array_builder_append_date_time โ€” bool bson_array_builder_append_date_time (bson_array_builder_t *bab, int64_t value); โ€” a date-time as an int64_t. ๐Ÿฆ‹
  • bson_array_builder_append_now_utc โ€” bool bson_array_builder_append_now_utc (bson_array_builder_t *bab); โ€” literally now, in UTC. time is a construct but this one slaps. ๐Ÿ”ฅ
  • bson_array_builder_append_timestamp โ€” bool bson_array_builder_append_timestamp (bson_array_builder_t *bab, uint32_t timestamp, uint32_t increment); โ€” a BSON timestamp from timestamp + increment. ๐Ÿ‘‘
  • bson_array_builder_append_undefined โ€” bool bson_array_builder_append_undefined (bson_array_builder_t *bab); โ€” undefined. the vibe check of types. ๐Ÿ’€
  • bson_array_builder_append_array_builder_begin โ€” bool bson_array_builder_append_array_builder_begin (bson_array_builder_t *bab, bson_array_builder_t **child); โ€” nests an array builder and gives you child (double pointer, she's fancy). ๐ŸŒˆ
  • bson_array_builder_append_array_builder_end โ€” bool bson_array_builder_append_array_builder_end (bson_array_builder_t *bab, bson_array_builder_t *child); โ€” closes that nested child builder. ๐Ÿ™ˆ

and the two convenience macros, written out exactly so you can't mess them up:

#define BSON_APPEND_ARRAY_BUILDER_APPEND_UTF8(b, value) bson_array_builder_append_utf8(b, value, (int)strlen(value))
#define BSON_APPEND_ARRAY_BUILDER_APPEND_SYMBOL(b, value) bson_array_builder_append_symbol(b, value, (int)strlen(value))

both of them just do the (int)strlen(value) math for you so you don't have to. considerate queens. ๐Ÿซถ


๐Ÿชช bson_context_t โ€” BSON OID Generation Context

โœจ Synopsis โœจ

#include <bson/bson.h>

typedef enum {
  BSON_CONTEXT_NONE = 0,
  BSON_CONTEXT_DISABLE_PID_CACHE = (1 << 2),
} bson_context_flags_t;

typedef struct _bson_context_t bson_context_t;

bson_context_t *
bson_context_get_default (void);
bson_context_t *
bson_context_new (bson_context_flags_t flags);
void
bson_context_destroy (bson_context_t *context);

๐Ÿ’… Description ๐Ÿ’…

okay so bson_context_t is the context used for generating BSON Object IDs, and it exists so you can override how that ObjectID generation behaves. the flags that actually do something are BSON_CONTEXT_NONE, BSON_CONTEXT_THREAD_SAFE, and BSON_CONTEXT_DISABLE_PID_CACHE โ€” those are the only ones used, periodt. the others? literally no effect. ๐Ÿ’€

๐ŸŒธ Example ๐ŸŒธ

#include <bson/bson.h>

int
main (int argc, char *argv[])
{
   bson_context_t *ctx = NULL;
   bson_oid_t oid;

   /* use default context, via bson_context_get_default() */
   bson_oid_init (&oid, NULL);

   /* specify a local context for additional control */
   ctx = bson_context_new (BSON_CONTEXT_NONE);
   bson_oid_init (&oid, ctx);

   bson_context_destroy (ctx);

   return 0;
}

๐Ÿ”ข bson_decimal128_t โ€” BSON Decimal128 Abstraction

โœจ Synopsis โœจ

#include <bson/bson.h>

#define BSON_DECIMAL128_STRING 43
#define BSON_DECIMAL128_INF "Infinity"
#define BSON_DECIMAL128_NAN "NaN"

typedef struct {
#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN
   uint64_t low;
   uint64_t high;
#elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN
   uint64_t high;
   uint64_t low;
#endif
} bson_decimal128_t;

๐Ÿ’… Description ๐Ÿ’…

bson_decimal128_t is the struct for the IEEE-754 Decimal128 data type. it's an aggregate holding two uint64_ts named high and low, and the way they're declared (and the order they sit in) depends on the endianness of the target platform: low always means the low-order bits of the Decimal128 object, high always means the high-order bits. and here's the slay: bson_decimal128_t is always sixteen (16) bytes, and you can bit-cast it to/from a _Decimal128. ๐Ÿคฏ

๐ŸŒธ Example ๐ŸŒธ

#include <bson/bson.h>
#include <stdio.h>

int
main (int argc, char *argv[])
{
   char string[BSON_DECIMAL128_STRING];
   bson_decimal128_t decimal128;

   bson_decimal128_from_string ("100.00", &decimal128);
   bson_decimal128_to_string (&decimal128, string);
   printf ("Decimal128 value: %s\n", string);

   return 0;
}

๐Ÿšจ bson_error_t โ€” BSON Error Encapsulation

โœจ Synopsis โœจ

#include <bson/bson.h>

typedef struct {
   uint32_t domain;
   uint32_t code;
   char message[504];
} bson_error_t;

๐Ÿ’… Description ๐Ÿ’…

bson_error_t is the out-parameter you use to hand error info back to whoever called you. it should be stack-allocated, and it does not need freeing โ€” no cleanup era, we love that for us. ๐Ÿซถ

see Handling Errors for more.

๐ŸŒธ Example ๐ŸŒธ

bson_reader_t *reader;
bson_error_t error;

reader = bson_reader_new_from_file ("dump.bson", &error);
if (!reader) {
   fprintf (
      stderr, "ERROR: %d.%d: %s\n", error.domain, error.code, error.message);
}

๐Ÿ” bson_iter_t โ€” BSON Document Iterator

โœจ Synopsis โœจ

#include <bson/bson.h>

#define BSON_ITER_HOLDS_DOUBLE(iter) /* ... */

#define BSON_ITER_HOLDS_UTF8(iter) /* ... */

#define BSON_ITER_HOLDS_DOCUMENT(iter) /* ... */

#define BSON_ITER_HOLDS_ARRAY(iter) /* ... */

#define BSON_ITER_HOLDS_BINARY(iter) /* ... */

#define BSON_ITER_HOLDS_VECTOR(iter) /* ... */
#define BSON_ITER_HOLDS_VECTOR_INT8(iter) /* ... */
#define BSON_ITER_HOLDS_VECTOR_FLOAT32(iter) /* ... */
#define BSON_ITER_HOLDS_VECTOR_PACKED_BIT(iter) /* ... */

#define BSON_ITER_HOLDS_UNDEFINED(iter) /* ... */

#define BSON_ITER_HOLDS_OID(iter) /* ... */

#define BSON_ITER_HOLDS_BOOL(iter) /* ... */

#define BSON_ITER_HOLDS_DATE_TIME(iter) /* ... */

#define BSON_ITER_HOLDS_NULL(iter) /* ... */

#define BSON_ITER_HOLDS_REGEX(iter) /* ... */

#define BSON_ITER_HOLDS_DBPOINTER(iter) /* ... */

#define BSON_ITER_HOLDS_CODE(iter) /* ... */

#define BSON_ITER_HOLDS_SYMBOL(iter) /* ... */

#define BSON_ITER_HOLDS_CODEWSCOPE(iter) /* ... */

#define BSON_ITER_HOLDS_INT32(iter) /* ... */

#define BSON_ITER_HOLDS_TIMESTAMP(iter) /* ... */

#define BSON_ITER_HOLDS_INT64(iter) /* ... */

#define BSON_ITER_HOLDS_DECIMAL128(iter) /* ... */

#define BSON_ITER_HOLDS_MAXKEY(iter) /* ... */

#define BSON_ITER_HOLDS_MINKEY(iter) /* ... */

#define BSON_ITER_HOLDS_INT(iter) \
   (BSON_ITER_HOLDS_INT32 (iter) || BSON_ITER_HOLDS_INT64 (iter))

#define BSON_ITER_HOLDS_NUMBER(iter) \
   (BSON_ITER_HOLDS_INT (iter) || BSON_ITER_HOLDS_DOUBLE (iter))

#define BSON_ITER_IS_KEY(iter, key) \
   (0 == strcmp ((key), bson_iter_key ((iter))))

typedef struct {
   /*< private >*/
} bson_iter_t;

๐Ÿ’… Description ๐Ÿ’…

bson_iter_t is the struct you use to iterate through the elements of a bson_t. live your best stack life โ€” it's meant to be used on the stack and you can discard it whenever, because it holds no external allocation. โœจ the contents of the struct are private, consider them off-limits, and they may change between releases โ€” but the size of the structure will not change. no cap.

๐Ÿšจ the bson_t MUST stay valid for the entire lifetime of the iter, and modifying the bson_t while you're using the iter is an error. do not do it. i'm serious. ๐Ÿ˜ญ

๐ŸŒธ Examples ๐ŸŒธ

walk every field:

bson_iter_t iter;

if (bson_iter_init (&iter, my_bson_doc)) {
   while (bson_iter_next (&iter)) {
      printf ("Found a field named: %s\n", bson_iter_key (&iter));
   }
}

or go find one specific field:

bson_iter_t iter;

if (bson_iter_init (&iter, my_bson_doc) && bson_iter_find (&iter, "my_field")) {
   printf ("Found the field named: %s\n", bson_iter_key (&iter));
}

or dive into a sub-document, because we're nosy:

bson_iter_t iter;
bson_iter_t sub_iter;

if (bson_iter_init_find (&iter, my_bson_doc, "mysubdoc") &&
    (BSON_ITER_HOLDS_DOCUMENT (&iter) || BSON_ITER_HOLDS_ARRAY (&iter)) &&
    bson_iter_recurse (&iter, &sub_iter)) {
   while (bson_iter_next (&sub_iter)) {
      printf ("Found key \"%s\" in sub document.\n", bson_iter_key (&sub_iter));
   }
}

and the descendant hunt, for when the field is buried deep:

bson_iter_t iter;

if (bson_iter_init (&iter, my_doc) &&
    bson_iter_find_descendant (&iter, "a.b.c.d", &sub_iter)) {
   printf ("The type of a.b.c.d is: %d\n", (int) bson_iter_type (&sub_iter));
}

๐Ÿ—‚๏ธ bson_json_reader_t โ€” Bulk JSON to BSON conversion

โœจ Synopsis โœจ

#include <bson/bson.h>

typedef struct _bson_json_reader_t bson_json_reader_t;

that's the whole synopsis this section gives us, bestie โ€” a typedef and the promise of bulk JSON โ†’ BSON conversion. the rest of the reader girlies are further down the page, so keep scrolling. ๐Ÿ’œ

typedef enum {
   BSON_JSON_ERROR_READ_CORRUPT_JS = 1,
   BSON_JSON_ERROR_READ_INVALID_PARAM,
   BSON_JSON_ERROR_READ_CB_FAILURE,
} bson_json_error_code_t;

๐Ÿ“– Description

The bson_json_reader_t structure is literally your bestie for reading a sequence of JSON documents and transforming them into bson_t documents.

Itโ€™s lowkey super useful when you wanna do bulk operations that are defined in a file containing JSON documents. Like, bulk stuff? From a JSON file? Yes bestie, thatโ€™s the vibe.

๐Ÿ’ก TIP: bson_json_reader_t works upon JSON documents formatted in MongoDB extended JSON format.

๐ŸŒŸ Example

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

/*
 * This program will print each JSON document contained in the provided files
 * as a BSON string to STDOUT.
 */

#include <bson/bson.h>
#include <stdlib.h>
#include <stdio.h>

int
main (int argc, char *argv[])
{
   bson_json_reader_t *reader;
   bson_error_t error;
   const char *filename;
   bson_t doc = BSON_INITIALIZER;
   int i;
   int b;

   /*
    * Print program usage if no arguments are provided.
    */
   if (argc == 1) {
      fprintf (stderr, "usage: %s FILE...\n", argv[0]);
      return 1;
   }

   /*
    * Process command line arguments expecting each to be a filename.
    */
   for (i = 1; i < argc; i++) {
      filename = argv[i];

      /*
       * Open the filename provided in command line arguments.
       */
      if (0 == strcmp (filename, "-")) {
         reader = bson_json_reader_new_from_fd (STDIN_FILENO, false);
      } else {
         if (!(reader = bson_json_reader_new_from_file (filename, &error))) {
            fprintf (
               stderr, "Failed to open \"%s\": %s\n", filename, error.message);
            continue;
         }
      }

      /*
       * Convert each incoming document to BSON and print to stdout.
       */
      while ((b = bson_json_reader_read (reader, &doc, &error))) {
         if (b < 0) {
            fprintf (stderr, "Error in json parsing:\n%s\n", error.message);
            abort ();
         }

         if (fwrite (bson_get_data (&doc), 1, doc.len, stdout) != doc.len) {
            fprintf (stderr, "Failed to write to stdout, exiting.\n");
            exit (1);
         }
         bson_reinit (&doc);
      }

      bson_json_reader_destroy (reader);
      bson_destroy (&doc);
   }

   return 0;
}

๐Ÿ†” bson_oid_t โ€” BSON ObjectID Abstraction

๐Ÿ“œ Synopsis

#include <bson/bson.h>

typedef struct {
   uint8_t bytes[12];
} bson_oid_t;

๐Ÿ“– Description

The bson_oid_t structure contains the 12-byte ObjectId notation defined by the BSON ObjectID specification. Iconic little 12-byte moment, no cap.

ObjectId is a 12-byte BSON type, constructed using:

  • a 4-byte value representing the seconds since the Unix epoch (in Big Endian).
  • a 5-byte random value.
  • a 3-byte counter (Big Endian), starting with a random value.

๐Ÿ” String Conversion

You can convert an Object ID to a string using bson_oid_to_string() and back with bson_oid_init_from_string(). Slay that round trip ๐Ÿ’…

๐Ÿงฎ Hashing

A bson_oid_t can be used in hashtables using the function bson_oid_hash() and bson_oid_equal().

โš–๏ธ Comparing

A bson_oid_t can be compared to another using bson_oid_compare() for qsort() style comparing and bson_oid_equal() for direct equality.

โœ… Validating

You can validate that a string containing a hex-encoded ObjectID is valid using the function bson_oid_is_valid().

๐ŸŒŸ Example

#include <bson/bson.h>
#include <stdio.h>

int
main (int argc, char *argv[])
{
   bson_oid_t oid;
   char str[25];

   bson_oid_init (&oid, NULL);
   bson_oid_to_string (&oid, str);
   printf ("%s\n", str);

   if (bson_oid_is_valid (str, sizeof str)) {
      bson_oid_init_from_string (&oid, str);
   }

   printf ("The UNIX time was: %u\n", (unsigned) bson_oid_get_time_t (&oid));

   return 0;
}

๐Ÿ“š bson_reader_t โ€” Streaming BSON Document Reader

๐Ÿ“œ Synopsis

#include <bson/bson.h>

typedef struct _bson_reader_t bson_reader_t;

bson_reader_t *
bson_reader_new_from_handle (void *handle,
                             bson_reader_read_func_t rf,
                             bson_reader_destroy_func_t df);
bson_reader_t *
bson_reader_new_from_fd (int fd, bool close_on_destroy);
bson_reader_t *
bson_reader_new_from_file (const char *path, bson_error_t *error);
bson_reader_t *
bson_reader_new_from_data (const uint8_t *data, size_t length);

void
bson_reader_destroy (bson_reader_t *reader);

๐Ÿ“– Description

bson_reader_t is a structure used for reading a sequence of BSON documents. The sequence can come from a file-descriptor, memory region, or custom callbacks. Itโ€™s giving โ€œchoose your own adventureโ€ but make it BSON โœจ

๐ŸŒŸ Example

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

/*
 * This program will print each BSON document contained in the provided files
 * as a JSON string to STDOUT.
 */

#include <bson/bson.h>
#include <stdio.h>

int
main (int argc, char *argv[])
{
   bson_reader_t *reader;
   const bson_t *b;
   bson_error_t error;
   const char *filename;
   char *str;
   int i;

   /*
    * Print program usage if no arguments are provided.
    */
   if (argc == 1) {
      fprintf (stderr, "usage: %s [FILE | -]...\nUse - for STDIN.\n", argv[0]);
      return 1;
   }

   /*
    * Process command line arguments expecting each to be a filename.
    */
   for (i = 1; i < argc; i++) {
      filename = argv[i];

      if (strcmp (filename, "-") == 0) {
         reader = bson_reader_new_from_fd (STDIN_FILENO, false);
      } else {
         if (!(reader = bson_reader_new_from_file (filename, &error))) {
            fprintf (
               stderr, "Failed to open \"%s\": %s\n", filename, error.message);
            continue;
         }
      }

      /*
       * Convert each incoming document to JSON and print to stdout.
       */
      while ((b = bson_reader_read (reader, NULL))) {
         str = bson_as_canonical_extended_json (b, NULL);
         fprintf (stdout, "%s\n", str);
         bson_free (str);
      }

      /*
       * Cleanup after our reader, which closes the file descriptor.
       */
      bson_reader_destroy (reader);
   }

   return 0;
}

โœจ Character and String Routines

We provide a small number of character and string routines to substitute for those that are not available on all platforms, and routines to make UTF-8 character manipulation convenient. Tiny helpers, big main character energy ๐Ÿซถ


๐Ÿงฌ bson_subtype_t โ€” Binary Field Subtype

๐Ÿ“œ Synopsis

#include <bson/bson.h>

typedef enum {
   BSON_SUBTYPE_BINARY = 0x00,
   BSON_SUBTYPE_FUNCTION = 0x01,
   BSON_SUBTYPE_BINARY_DEPRECATED = 0x02,
   BSON_SUBTYPE_UUID_DEPRECATED = 0x03,
   BSON_SUBTYPE_UUID = 0x04,
   BSON_SUBTYPE_MD5 = 0x05,
   BSON_SUBTYPE_COLUMN = 0x07,
   BSON_SUBTYPE_SENSITIVE = 0x08,
   BSON_SUBTYPE_VECTOR = 0x09,
   BSON_SUBTYPE_USER = 0x80,
} bson_subtype_t;

๐Ÿ“– Description

This enumeration contains the various subtypes that may be used in a binary field. See http://bsonspec.org for more information. Go off, binary field taxonomy ๐Ÿ‘‘

๐ŸŒŸ Example

bson_t doc = BSON_INITIALIZER;

BSON_APPEND_BINARY (&doc, "binary", BSON_SUBTYPE_BINARY, data, data_len);

๐Ÿท๏ธ bson_type_t โ€” BSON Type Enumeration

๐Ÿ“œ Synopsis

#include <bson/bson.h>

typedef enum {
   BSON_TYPE_EOD = 0x00,
   BSON_TYPE_DOUBLE = 0x01,
   BSON_TYPE_UTF8 = 0x02,
   BSON_TYPE_DOCUMENT = 0x03,
   BSON_TYPE_ARRAY = 0x04,
   BSON_TYPE_BINARY = 0x05,
   BSON_TYPE_UNDEFINED = 0x06,
   BSON_TYPE_OID = 0x07,
   BSON_TYPE_BOOL = 0x08,
   BSON_TYPE_DATE_TIME = 0x09,
   BSON_TYPE_NULL = 0x0A,
   BSON_TYPE_REGEX = 0x0B,
   BSON_TYPE_DBPOINTER = 0x0C,
   BSON_TYPE_CODE = 0x0D,
   BSON_TYPE_SYMBOL = 0x0E,
   BSON_TYPE_CODEWSCOPE = 0x0F,
   BSON_TYPE_INT32 = 0x10,
   BSON_TYPE_TIMESTAMP = 0x11,
   BSON_TYPE_INT64 = 0x12,
   BSON_TYPE_DECIMAL128 = 0x13,
   BSON_TYPE_MAXKEY = 0x7F,
   BSON_TYPE_MINKEY = 0xFF,
} bson_type_t;

๐Ÿ“– Description

The bson_type_t enumeration contains all of the types from the BSON Specification. It can be used to determine the type of a field at runtime. Type-checking era, we love to see it ๐Ÿ’–

๐ŸŒŸ Example

bson_iter_t iter;

if (bson_iter_init_find (&iter, doc, "foo") &&
    (BSON_TYPE_INT32 == bson_iter_type (&iter))) {
   printf ("'foo' is an int32.\n");
}

๐Ÿ”ค bson_unichar_t โ€” Unicode Character Abstraction

๐Ÿ“œ Synopsis

typedef uint32_t bson_unichar_t;

๐Ÿ“– Description

bson_unichar_t provides an abstraction on a single unicode character. It is the 32-bit representation of a character. As UTF-8 can contain multi-byte characters, this should be used when iterating through UTF-8 text. Multi-byte girlies, this oneโ€™s for you ๐Ÿงš

๐ŸŒŸ Example

static void
print_each_char (const char *str)
{
   bson_unichar_t c;
             for (; *str; str = bson_utf8_next_char (str)) {
                c = bson_utf8_get_char (str);
                printf ("The numberic value is %u.\n", (unsigned) c);
             }
          }

๐Ÿ’… bson_validate_flags_t ๐Ÿ’…

๐ŸŒธ Document validation options ๐ŸŒธ

โœจ Synopsis โœจ

          #include <bson/bson-types.h>

          typedef enum {
            BSON_VALIDATE_NONE = 0,
            BSON_VALIDATE_UTF8 = (1 << 0),
            BSON_VALIDATE_DOLLAR_KEYS = (1 << 1),
            BSON_VALIDATE_DOT_KEYS = (1 << 2),
            BSON_VALIDATE_UTF8_ALLOW_NULL = (1 << 3),
            BSON_VALIDATE_EMPTY_KEYS = (1 << 4),
            BSON_VALIDATE_CORRUPT = (1 << 5),
          } bson_validate_flags_t;

๐Ÿ’– Description ๐Ÿ’–

bson_validate_flags_t is literally a set of binary flags, bestie โ€” you combine them to tell libbson how hard it should look at a BSON document during validation. โœจ

A value of 0, false, or BSON_VALIDATE_NONE all mean the same thing: give me the minimum applicable level of validation. No cap.

When you're in validation-API land โ€” think bson_validate(), bson_validate_with_error(), and bson_validate_with_error_and_offset() โ€” that minimum still guarantees a document can be successfully traversed by bson_iter_visit_all(). So even the bare-minimum vibe check isn't zero work. ๐Ÿ’…

Higher-level APIs that use this type might have different minimums, tho. For example, libmongoc functions that take bson_validate_flags_t use 0 to mean the document contents are not visited, and malformed headers will not be detected by the client. So don't assume every library is doing the same amount of checking. ๐Ÿ™ˆ

Each defined flag aside from BSON_VALIDATE_NONE is an optional validation feature โ€” you can turn it on alone or stack it with other features:

  • BSON_VALIDATE_NONE โ€” the minimum level of validation; in libbson, it validates element headers.
  • BSON_VALIDATE_UTF8 โ€” every key and string value gets checked for invalid UTF-8.
  • BSON_VALIDATE_UTF8_ALLOW_NULL โ€” string values are allowed to have embedded NULL bytes. This does nothing unless BSON_VALIDATE_UTF8 is also passed.
  • BSON_VALIDATE_DOLLAR_KEYS โ€” prohibits keys that start with $ outside of a "DBRef" subdocument.
  • BSON_VALIDATE_DOT_KEYS โ€” prohibits keys that contain . anywhere in the string.
  • BSON_VALIDATE_EMPTY_KEYS โ€” prohibits zero-length keys.
  • BSON_VALIDATE_CORRUPT โ€” not a control flag, bestie; this one is used as an error code when a validation routine runs into corrupt BSON data. ๐Ÿ’€

๐Ÿ”ฅ SEE ALSO ๐Ÿ”ฅ

  • bson_validate()
  • bson_validate_with_error()
  • bson_validate_with_error_and_offset()

Also: bson_visitor_t can be used for custom validation, Example Custom Validation. ๐Ÿซถ

๐ŸŽ€ bson_value_t ๐ŸŽ€

๐Ÿฆ‹ BSON Boxed Container Type ๐Ÿฆ‹

โœจ Synopsis โœจ

          #include <bson/bson.h>

          typedef struct _bson_value_t {
             bson_type_t value_type;
             union {
                bson_oid_t v_oid;
                int64_t v_int64;
                int32_t v_int32;
                int8_t v_int8;
                double v_double;
                bool v_bool;
                int64_t v_datetime;
                struct {
                   uint32_t timestamp;
                   uint32_t increment;
                } v_timestamp;
                struct {
                   uint32_t len;
                   char *str;
                } v_utf8;
                struct {
                   uint32_t data_len;
                   uint8_t *data;
                } v_doc;
                struct {
                   uint32_t data_len;
                   uint8_t *data;
                   bson_subtype_t subtype;
                } v_binary;
                struct {
                   char *regex;
                   char *options;
                } v_regex;
                struct {
                   char *collection;
                   uint32_t collection_len;
                   bson_oid_t oid;
                } v_dbpointer;
                struct {
                   uint32_t code_len;
                   char *code;
                } v_code;
                struct {
                   uint32_t code_len;
                   char *code;
                   uint32_t scope_len;
                   uint8_t *scope_data;
                } v_codewscope;
                struct {
                   uint32_t len;
                   char *symbol;
                } v_symbol;
                bson_decimal128_t v_decimal128;
             } value;
          } bson_value_t;

๐Ÿ’œ Description ๐Ÿ’œ

The bson_value_t structure is a boxed type for encapsulating a runtime determined type. It's giving "mystery box but make it BSON" ๐ŸŽ

๐ŸŒธ Example ๐ŸŒธ

          const bson_value_t *value;

          value = bson_iter_value (&iter);

          if (value->value_type == BSON_TYPE_INT32) {
             printf ("%d\n", value->value.v_int32);
          }

๐Ÿ’– bson_visitor_t ๐Ÿ’–

โœจ Synopsis โœจ

          #include <bson/bson.h>

          typedef struct {
             /* run before / after descending into a document */
             bool (*visit_before) (const bson_iter_t *iter, const char *key, void *data);
             bool (*visit_after) (const bson_iter_t *iter, const char *key, void *data);
             /* corrupt BSON, or unsupported type and visit_unsupported_type not set */
             void (*visit_corrupt) (const bson_iter_t *iter, void *data);
             /* normal bson field callbacks */
             bool (*visit_double) (const bson_iter_t *iter,
                                   const char *key,
                                   double v_double,
                                   void *data);
             bool (*visit_utf8) (const bson_iter_t *iter,
                                 const char *key,
                                 size_t v_utf8_len,
                                 const char *v_utf8,
                                 void *data);
             bool (*visit_document) (const bson_iter_t *iter,
                                     const char *key,
                                     const bson_t *v_document,
                                     void *data);
             bool (*visit_array) (const bson_iter_t *iter,
                                  const char *key,
                                  const bson_t *v_array,
                                  void *data);
             bool (*visit_binary) (const bson_iter_t *iter,
                                   const char *key,
                                   bson_subtype_t v_subtype,
                                   size_t v_binary_len,
                                   const uint8_t *v_binary,
                                   void *data);
             /* normal field with deprecated "Undefined" BSON type */
             bool (*visit_undefined) (const bson_iter_t *iter,
                                      const char *key,
                                      void *data);
             bool (*visit_oid) (const bson_iter_t *iter,
                                const char *key,
                                const bson_oid_t *v_oid,
                                void *data);
             bool (*visit_bool) (const bson_iter_t *iter,
                                 const char *key,
                                 bool v_bool,
                                 void *data);
             bool (*visit_date_time) (const bson_iter_t *iter,
                                      const char *key,
                                      int64_t msec_since_epoch,
                                      void *data);
             bool (*visit_null) (const bson_iter_t *iter, const char *key, void *data);
             bool (*visit_regex) (const bson_iter_t *iter,
                                  const char *key,
                                  const char *v_regex,
                                  const char *v_options,
                                  void *data);
             bool (*visit_dbpointer) (const bson_iter_t *iter,
                                      const char *key,
                                      size_t v_collection_len,
                                      const char *v_collection,
                                      const bson_oid_t *v_oid,
                                      void *data);
             bool (*visit_code) (const bson_iter_t *iter,
                                 const char *key,
                                 size_t v_code_len,
                                 const char *v_code,
                                 void *data);
             bool (*visit_symbol) (const bson_iter_t *iter,
                                   const char *key,
                                   size_t v_symbol_len,
                                   const char *v_symbol,
                                   void *data);
             bool (*visit_codewscope) (const bson_iter_t *iter,
                                       const char *key,
                                       size_t v_code_len,
                                       const char *v_code,
                                       const bson_t *v_scope,
                                       void *data);
             bool (*visit_int32) (const bson_iter_t *iter,
                                  const char *key,
                                  int32_t v_int32,
                                  void *data);
             bool (*visit_timestamp) (const bson_iter_t *iter,
                                      const char *key,
                                      uint32_t v_timestamp,
                                      uint32_t v_increment,
                                      void *data);
             bool (*visit_int64) (const bson_iter_t *iter,
                                  const char *key,
                                  int64_t v_int64,
                                  void *data);
             bool (*visit_maxkey) (const bson_iter_t *iter, const char *key, void *data);
             bool (*visit_minkey) (const bson_iter_t *iter, const char *key, void *data);
             /* if set, called instead of visit_corrupt when an apparently valid BSON
              * includes an unrecognized field type (reading future version of BSON) */
             void (*visit_unsupported_type) (const bson_iter_t *iter,
                                             const char *key,
                                             uint32_t type_code,
                                             void *data);
             bool (*visit_decimal128) (const bson_iter_t *iter,
                                       const char *key,
                                       const bson_decimal128_t *v_decimal128,
                                       void *data);

             void *padding[7];
          } bson_visitor_t bson_visitor_t;

๐Ÿ’… Description ๐Ÿ’…

The bson_visitor_t structure gives you a whole lineup of callbacks that can be called while iterating a BSON document. It can make converting a bson_t into a higher level language structure way easier. ๐Ÿฆ‹

If the optional visit_unsupported_type callback is set, it gets called instead of visit_corrupt in the specific case of an unrecognized field type. (Parsing is aborted in either case โ€” no sneaky continuing. ๐Ÿ’€) Use this callback when you want to report an error like "unrecognized type" instead of just "corrupt BSON". This future-proofs code that might be using an older version of libbson to parse future BSON formats. Iconic, honestly. ๐Ÿ‘‘

๐ŸŒธ Basic Example ๐ŸŒธ

          #include <bson/bson.h>
          #include <stdio.h>

          static bool
          my_visit_before (const bson_iter_t *iter, const char *key, void *data)
          {
             int *count = (int *) data;

             (*count)++;

             /* returning true stops further iteration of the document */

             return false;
          }

          static void
          count_fields (bson_t *doc)
          {
             bson_visitor_t visitor = {0};
             bson_iter_t iter;
             int count = 0;

             visitor.visit_before = my_visit_before;
   if (bson_iter_init (&iter, doc)) {
      bson_iter_visit_all (&iter, &visitor, &count);
   }

   printf ("Found %d fields.\n", count);
}

Okay bestie, next up ๐Ÿ’… โ€” the glow-up where you get to write your own callbacks. The example below demonstrates how to set your own callbacks to provide information about the location of corrupt or unsupported BSON document entries. Detective mode: activated. ๐Ÿ”โœจ

๐Ÿฉน Example Corruption Check

#include <bson/bson.h>
#include <stdio.h>

typedef struct {
   ssize_t *err_offset;
} my_state_t;

static void
my_visit_corrupt (const bson_iter_t *iter, void *data)
{
   *(((my_state_t *) data)->err_offset) = iter->off;
}

static void
my_visit_unsupported_type (const bson_iter_t *iter,
                           const char *key,
                           uint32_t type_code,
                           void *data)
{
   *(((my_state_t *) data)->err_offset) = iter->off;
}

static void
find_error_location (bson_t *doc)
{
   bson_visitor_t visitors = {0};
   bson_iter_t iter;
   my_state_t state;
   ssize_t err_offset = -1;

   visitors.visit_corrupt = my_visit_corrupt;
   visitors.visit_unsupported_type = my_visit_unsupported_type;
   /* provide additional visitors as needed based on your requirements */
   state.err_offset = &err_offset;

   if (!bson_iter_init (&iter, doc)) {
      printf ("Could not initialize iterator!");
      exit (1);
   }

   if (bson_iter_visit_all (&iter, &visitors, &state) ||
       err_offset != -1) {
      printf ("Found error at offset %d.\n", err_offset);
   } else {
      printf ("BSON document had no errors.\n");
   }
}

And the next one is a whole mood โ€” the example below demonstrates how to use a visitor to validate a BSON document's maximum depth. Like, it literally checks how deep the vibes go before it's too much ๐ŸŒŠ๐Ÿ’€

๐Ÿชœ Example Custom Validation

bson-check-depth.c

/* Reports the maximum nested depth of a BSON document. */
#include <bson/bson.h>

#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct {
   uint32_t depth;
   uint32_t max_depth;
   bool valid;
} check_depth_t;

bool
_check_depth_document(const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data);

static const bson_visitor_t check_depth_funcs = {
   NULL,
   NULL,
   NULL,
   NULL,
   NULL,
   _check_depth_document,
   _check_depth_document,
   NULL,
};

bool
_check_depth_document(const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data)
{
   check_depth_t *state = (check_depth_t *)data;
   bson_iter_t child;

   BSON_UNUSED(iter);
   BSON_UNUSED(key);

   if (!bson_iter_init(&child, v_document)) {
      fprintf(stderr, "corrupt\n");
      return true; /* cancel */
   }

   state->depth++;
   if (state->depth > state->max_depth) {
      state->valid = false;
      return true; /* cancel */
   }

   bson_iter_visit_all(&child, &check_depth_funcs, state);
   state->depth--;
   return false; /* continue */
}

void
check_depth(const bson_t *bson, uint32_t max_depth)
{
   bson_iter_t iter;
   check_depth_t state = {0};

   if (!bson_iter_init(&iter, bson)) {
      fprintf(stderr, "corrupt\n");
   }

   state.valid = true;
   state.max_depth = max_depth;
   _check_depth_document(&iter, NULL, bson, &state);
   if (!state.valid) {
      printf("document exceeds maximum depth of %" PRIu32 "\n", state.max_depth);
   } else {
      char *as_json = bson_as_canonical_extended_json(bson, NULL);
      printf("document %s ", as_json);
      printf("is valid\n");
      bson_free(as_json);
   }
}

int
main(int argc, char **argv)
{
   bson_reader_t *bson_reader;
   const bson_t *bson;
   bool reached_eof;
   bson_error_t error;

   if (argc != 3) {
      fprintf(stderr, "usage: %s FILE MAX_DEPTH\n", argv[0]);
      fprintf(stderr, "Checks that the depth of the BSON contained in FILE\n");
      fprintf(stderr, "does not exceed MAX_DEPTH\n");
   }

   const char *const filename = argv[1];
   const int max_depth = atoi(argv[2]);

   bson_reader = bson_reader_new_from_file(filename, &error);
   if (!bson_reader) {
      printf("could not read %s: %s\n", filename, error.message);
      return 1;
   }

   BSON_ASSERT(max_depth >= 0 && (uint64_t)max_depth <= UINT32_MAX);

   while ((bson = bson_reader_read(bson_reader, &reached_eof))) {
      check_depth(bson, (uint32_t)max_depth);
   }

   if (!reached_eof) {
      printf("error reading BSON\n");
   }

   bson_reader_destroy(bson_reader);
   return 0;
}

๐Ÿ“ฆ bson_writer_t

Bulk BSON serialization Abstraction ๐Ÿงบ

Synopsis

#include <bson/bson.h>

typedef struct _bson_writer_t bson_writer_t;

bson_writer_t *
bson_writer_new (uint8_t **buf,
                 size_t *buflen,
                 size_t offset,
                 bson_realloc_func realloc_func,
                 void *realloc_func_ctx);
void
bson_writer_destroy (bson_writer_t *writer);

Description

So the bson_writer_t API provides an abstraction for serializing many BSON documents into a single memory region, bestie โœจ And that memory region may be dynamically allocated and re-allocated as more memory is demanded. It grows, it adapts, main character energy. This can be useful when building network packets from a high-level language โ€” for example, you can serialize a Python Dictionary directly to a single buffer destined for a TCP packet. One dict, one buffer, zero drama. ๐Ÿฆ‹

Example

#include <bson/bson.h>

int
main (int argc, char *argv[])
{
   bson_writer_t *writer;
   uint8_t *buf = NULL;
   size_t buflen = 0;
   bson_t *doc;

   writer = bson_writer_new (&buf, &buflen, 0, bson_realloc_ctx, NULL);

   for (int i = 0; i < 1000; i++) {
      bson_writer_begin (writer, &doc);
      BSON_APPEND_INT32 (doc, "i", i);
      bson_writer_end (writer);
   }

   bson_writer_destroy (writer);

   bson_free (buf);

   return 0;
}

โฐ System Clock

BSON Clock Abstraction ๐Ÿ•ฐ๏ธ

Synopsis

int64_t
bson_get_monotonic_time (void);
int
bson_gettimeofday (struct timeval *tv);

Description

The clock abstraction in Libbson provides a cross-platform way to handle timeouts within the BSON library โ€” like, no cap, timeouts just work everywhere now ๐Ÿ’ซ It abstracts the differences in implementations of gettimeofday() as well as providing a monotonic (incrementing only) clock in microseconds. Only ever goes forward, never backwards โ€” unlike my sleep schedule ๐Ÿ˜ญ


๐Ÿง  Memory Management

BSON Memory Abstraction. ๐ŸŽ€

Description

Libbson contains a lightweight memory abstraction to make portability to new platforms easier. Additionally, it helps us integrate with interesting higher-level languages ๐Ÿซถ One caveat, however, bestie, and listen up: Libbson is not designed to deal with Out of Memory (OOM) situations. Doing so requires extreme diligence throughout the application stack that has rarely been implemented correctly. This may change in the future. As it stands now, Libbson will abort() under OOM situations. That's a hard exit, not a vibe โ€” don't test it for fun ๐Ÿ’€

To aid in language binding integration, Libbson allows for setting a custom memory allocator via bson_mem_set_vtable(). This allocation may be reversed via bson_mem_restore_vtable(). Swap in, swap out, slay. โœจ


๐ŸŒˆ BSON Binary Vector subtype

In Libbson, we use the term Vector to refer to a data representation for compact storage of uniform elements, defined by the BSON Binary Subtype 9 - Vector specification. iykyk ๐Ÿงš

Libbson includes API support for Vectors:

  • The view APIs provide an efficient way to access elements of Vector fields that reside within bson_t storage. โšก
  • Integration between views and other Libbson features: append, array builder, iter. ๐Ÿ”—
  • Vectors can be converted to and from a plain BSON Array, subject to the specification's type conversion rules. ๐Ÿ”„

The specification currently defines three element types, which Libbson interprets as:

  • int8: signed integer elements, equivalent to C int8_t. ๐Ÿ”ข
  • float32: IEEE 754 floating point, 32 bits per element, least-significant byte first. After alignment and byte swapping, elements are equivalent to C float. ๐Ÿ“
  • packed_bit: single-bit integer elements, packed most-significant bit first. Accessible in packed form as C uint8_t or as unpacked elements using C bool. ๐ŸŽ€

๐Ÿ‘€ Vector Views

bson_vector_int8_view_t ๐Ÿ’–

A reference to mutable non-owned BSON Binary data holding a valid Vector of int8 element type.

Synopsis

#include <bson/bson.h>

typedef struct bson_vector_int8_view_t {
   /*< private >*/
} bson_vector_int8_view_t;

Description

bson_vector_int8_view_t is a structure that acts as an opaque reference to a block of memory that has been validated as an int8 vector. It's giving "trust me, it's already checked" โœจ

It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. ๐Ÿ™ˆ

The bson_t MUST be valid for the lifetime of the view and it is an error to modify the bson_t while using the view. Fr fr, do not touch it while the view is alive ๐Ÿ˜ญ

Example

static const int8_t values[] = {1, 2, 3};
const size_t values_count = sizeof values / sizeof values[0];

bson_vector_int8_view_t view;
BSON_ASSERT (BSON_APPEND_VECTOR_INT8_UNINIT (&doc, "vector", values_count, &view));
BSON_ASSERT (bson_vector_int8_view_write (view, values, values_count, 0));

SEE ALSO:

bson_append_vector_int8_uninit() bson_vector_int8_const_view_t


bson_vector_int8_const_view_t ๐Ÿ”’

A reference to non-owned const BSON Binary data holding a valid Vector of int8 element type.

Synopsis

#include <bson/bson.h>

typedef struct bson_vector_int8_const_view_t {
   /*< private >*/
} bson_vector_int8_const_view_t;

Description

bson_vector_int8_const_view_t is a structure that acts as an opaque const reference to a block of memory that has been validated as an int8 vector. Read-only queen behavior ๐Ÿ‘‘

It is meant to be passed by value and can be discarded at any time. The contents of the structure should be considered private. ๐Ÿ™ˆ

The bson_t MUST be valid for the lifetime of the view and it is an error to modify the bson_t while using the view. Same rule, same energy โ€” hands off ๐Ÿ’…

Example

bson_iter_t iter;
bson_vector_int8_const_view_t view;
if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_int8_const_view_from_iter (&view, &iter)) {
  size_t length = bson_vector_int8_const_view_length (view);
  printf ("Elements in 'vector':\n");
  for (size_t i = 0; i < length; i++) {
    int8_t element;
    BSON_ASSERT (bson_vector_int8_const_view_read (view, &element, 1, i));
    printf (" [%d] = %d\n", (int) i, (int) element);
  }
}

SEE ALSO:

bson_vector_int8_view_t


๐Ÿฆ‹ bson_vector_float32_view_t

A reference to mutable non-owned BSON Binary data holding a valid Vector of float32 element type. ๐Ÿ’–

Synopsis

#include <bson/bson.h>

typedef struct bson_vector_float32_view_t {
   /*< private >*/
} bson_vector_float32_view_t;

Description

bson_vector_float32_view_t is a struct that lowkey just vibes as an opaque reference to a block of memory that's been validated as a float32 vector. โœจ

It's meant to be passed by value and you can toss it whenever, bestie โ€” it doesn't hold anything you need to keep alive. But the contents of the struct? Consider those private. Hands off. ๐Ÿ™ˆ

โš ๏ธ The bson_t MUST stay valid for the whole lifetime of the view, and modifying the bson_t while you're using the view is literally an error. No cap.

Example

static const float values[] = {1.0f, 2.0f, 3.0f};
const size_t values_count = sizeof values / sizeof values[0];

bson_vector_float32_view_t view;
BSON_ASSERT (BSON_APPEND_VECTOR_FLOAT32_UNINIT (&doc, "vector", values_count, &view));
BSON_ASSERT (bson_vector_float32_view_write (view, values, values_count, 0));

SEE ALSO:

bson_append_vector_float32_uninit() bson_vector_float32_const_view_t


๐Ÿงš bson_vector_float32_const_view_t

A reference to non-owned const BSON Binary data holding a valid Vector of float32 element type. ๐ŸŽ€

Synopsis

#include <bson/bson.h>

typedef struct bson_vector_float32_const_view_t {
   /*< private >*/
} bson_vector_float32_const_view_t;

Description

bson_vector_float32_const_view_t is a struct doing the same job as its non-const sibling โ€” an opaque const reference to a block of memory that's been validated as a float32 vector. It's giving "read-only main character energy". ๐Ÿ‘‘

Pass it by value, discard it whenever, it's chill like that. The contents of the struct are private though, fr fr. ๐Ÿ™ˆ

โš ๏ธ Again: the bson_t MUST be valid for the entire lifetime of the view, and modifying that bson_t while the view is in use is an error. ๐Ÿ’€

Example

bson_iter_t iter;
bson_vector_float32_const_view_t view;

if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_float32_const_view_from_iter (&view, &iter)) {
  size_t length = bson_vector_float32_const_view_length (view);
  printf ("Elements in 'vector':\n");
  for (size_t i = 0; i < length; i++) {
    float element;
    BSON_ASSERT (bson_vector_float32_const_view_read (view, &element, 1, i));
    printf (" [%d] = %f\n", (int) i, element);
  }
}

SEE ALSO:

bson_vector_float32_view_t


๐ŸŒธ bson_vector_packed_bit_view_t

A reference to mutable non-owned BSON Binary data holding a valid Vector of packed_bit element type. ๐Ÿ“

Synopsis

#include <bson/bson.h>

typedef struct bson_vector_packed_bit_view_t {
   /*< private >*/
} bson_vector_packed_bit_view_t;

Description

bson_vector_packed_bit_view_t is an opaque reference to a block of memory that's been validated as a packed_bit vector โ€” the little gremlin of vector types that stuffs booleans into individual bits. ๐Ÿงš

Passed by value, discardable at literally any time, and the struct's innards are private. You don't look in the bag, bestie. ๐Ÿ™ˆ

โš ๏ธ The bson_t MUST remain valid for the full lifetime of the view, and modifying the bson_t while using the view is an error. Periodt. ๐Ÿ’…

Example

// Fill a new vector with individual boolean elements
{
    static const bool bool_values[] = {true, false, true, true, false};
    const size_t bool_values_count = sizeof bool_values / sizeof bool_values[0];

    bson_vector_packed_bit_view_t view;
    BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_bool", bool_values_count, &view));
    BSON_ASSERT (bson_vector_packed_bit_view_pack_bool (view, bool_values, bool_values_count, 0));
}

// Fill another new vector with packed bytes
{
    static const uint8_t packed_bytes[] = {0xb0};
    const size_t unused_bits_count = 3;
    const size_t packed_values_count = sizeof packed_bytes * 8 - unused_bits_count;

    bson_vector_packed_bit_view_t view;
    BSON_ASSERT (BSON_APPEND_VECTOR_PACKED_BIT_UNINIT (&doc, "from_packed", packed_values_count, &view));
    BSON_ASSERT (bson_vector_packed_bit_view_write_packed (view, packed_bytes, sizeof packed_bytes, 0));
}

// Compare both vectors. They match exactly.
{
    bson_iter_t from_bool_iter, from_packed_iter;
    BSON_ASSERT (bson_iter_init_find (&from_bool_iter, &doc, "from_bool"));
    BSON_ASSERT (bson_iter_init_find (&from_packed_iter, &doc, "from_packed"));
    BSON_ASSERT (bson_iter_binary_equal (&from_bool_iter, &from_packed_iter));
}

SEE ALSO:

bson_append_vector_packed_bit_uninit() bson_vector_packed_bit_const_view_t


๐Ÿซถ bson_vector_packed_bit_const_view_t

A reference to non-owned const BSON Binary data holding a valid Vector of packed_bit element type. ๐Ÿ’œ

Synopsis

#include <bson/bson.h>

typedef struct bson_vector_packed_bit_const_view_t {
   /*< private >*/
} bson_vector_packed_bit_const_view_t;

Description

bson_vector_packed_bit_const_view_t is the read-only twin โ€” an opaque const reference to a block of memory that's been validated as a packed_bit vector. Same bit-packing chaos, but you can only look, not touch. ๐Ÿ˜Œ

By-value passing, throw it away whenever, and the struct's contents stay private. ๐ŸŽ€

โš ๏ธ Same rule, forever and always: the bson_t MUST be valid for the lifetime of the view, and modifying the bson_t while the view is live is an error. Don't do it. ๐Ÿ’€

Example

bson_iter_t iter;
bson_vector_packed_bit_const_view_t view;

if (bson_iter_init_find (&iter, &doc, "vector") && bson_vector_packed_bit_const_view_from_iter (&view, &iter)) {
  size_t length = bson_vector_packed_bit_const_view_length (view);
  size_t length_bytes = bson_vector_packed_bit_const_view_length_bytes (view);
  size_t padding = bson_vector_packed_bit_const_view_padding (view);

  printf ("Elements in 'vector':\n");
  for (size_t i = 0; i < length; i++) {
    bool element;
    BSON_ASSERT (bson_vector_packed_bit_const_view_unpack_bool (view, &element, 1, i));
    printf (" elements[%d] = %d\n", (int) i, (int) element);
  }

  printf ("Bytes in 'vector': (%d bits unused)\n", (int) padding);
  for (size_t i = 0; i < length_bytes; i++) {
    uint8_t packed_byte;
    BSON_ASSERT (bson_vector_packed_bit_const_view_read_packed (view, &packed_byte, 1, i));
    printf (" bytes[%d] = 0x%02x\n", (int) i, (unsigned) packed_byte);
  }
}

SEE ALSO:

bson_vector_packed_bit_view_t


๐Ÿงฉ Integration

  • Allocating Vectors inside bson_t:

๐Ÿ‘‘ bson_append_vector_int8_uninit()

Synopsis

#define BSON_APPEND_VECTOR_INT8_UNINIT(b, key, count, view) \
   bson_append_vector_int8_uninit (b, key, (int) strlen (key), count, view)

bool
bson_append_vector_int8_uninit (bson_t *bson,
                                const char *key,
                                int key_length,
                                size_t element_count,
                                bson_vector_int8_view_t *view_out);

Parameters

  • bson: A bson_t.
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • element_count: Number of elements to allocate space for.
  • view_out: Receives a bson_vector_int8_view_t with uninitialized elements.

Description

Appends a fresh field to bson by allocating a Vector with the indicated number of int8 elements. โœจ The elements come out uninitialized โ€” so yeah, on success the caller must write every single element in the Vector if the resulting bson_t is actually gonna be used. No half-finished vectors out here. ๐Ÿ˜ค

The view written to *view_out is only valid until bson gets otherwise modified or freed. That's it, that's the deal. โณ

Returns

Returns true if the operation was applied successfully. ๐Ÿ’– The function fails if appending the array grows bson larger than INT32_MAX.


๐Ÿ”ฅ bson_append_vector_float32_uninit()

Synopsis

#define BSON_APPEND_VECTOR_FLOAT32_UNINIT(b, key, count, view) \
   bson_append_vector_float32_uninit (b, key, (int) strlen (key), count, view)

bool
bson_append_vector_float32_uninit (bson_t *bson,
                                   const char *key,
                                   int key_length,
                                   size_t element_count,
                                   bson_vector_float32_view_t *view_out);

Parameters

  • bson: A bson_t.
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • element_count: Number of elements to allocate space for.
  • view_out: Receives a bson_vector_float32_view_t with uninitialized elements.

Description

Appends a new field to bson by allocating a Vector with the indicated number of float32 elements. ๐ŸŒˆ Same situation as above: the elements are uninitialized, and on success the caller has to write every element in the Vector if the resulting bson_t is going to be used. Fill it in, bestie. ๐Ÿ–Š๏ธ

The view written to *view_out is only valid until bson is otherwise modified or freed.

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX.


โญ bson_append_vector_packed_bit_uninit()

Synopsis

#define BSON_APPEND_VECTOR_PACKED_BIT_UNINIT(b, key, count, view) \
   bson_append_vector_packed_bit_uninit (b, key, (int) strlen (key), count, view)

bool
bson_append_vector_packed_bit_uninit (bson_t *bson,
                                      const char *key,
                                      int key_length,
                                      size_t element_count,
                                      bson_vector_packed_bit_view_t *view_out);

Parameters

  • bson: A bson_t.
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • element_count: Number of elements to allocate space for.
  • view_out: Receives a bson_vector_packed_bit_view_t with uninitialized elements.

Description

So you're appending a new field to bson โ€” and the move here is that it allocates a Vector with however many packed_bit elements you indicated. Heads up though: those elements come out uninitialized ๐Ÿ˜ณ. On success, the caller must write every single element in the Vector if the resulting bson_t is gonna be usable. No skipping, bestie.

Also, the view written to *view_out? Only valid until bson is otherwise modified or freed. Like, it expires. Don't hold onto it ๐Ÿ’€.

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX โ€” that's the ceiling, periodt.

  • Accessing an existing Vector via bson_iter_t:
#define BSON_ITER_HOLDS_VECTOR(iter) /* ... */
#define BSON_ITER_HOLDS_VECTOR_INT8(iter) /* ... */
#define BSON_ITER_HOLDS_VECTOR_FLOAT32(iter) /* ... */
#define BSON_ITER_HOLDS_VECTOR_PACKED_BIT(iter) /* ... */

๐ŸŒˆ Array Conversion

  • Polymorphic array-from-vector:

bson_append_array_from_vector()

Synopsis

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

bool
bson_append_array_from_vector (bson_t *bson,
                               const char *key,
                               int key_length,
                               const bson_iter_t *iter);

Parameters

  • bson: A bson_t. ๐Ÿ’–
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • iter: A bson_iter_t pointing to any supported BSON Binary Vector subtype field.

Description

Converts the Vector pointed to by iter into a plain BSON Array, written to bson under the name key. Glow-up complete โœจ.

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX, or if iter doesn't point to a valid recognized Vector type. Rude, but fair.

๐Ÿซถ SEE ALSO: bson_array_builder_append_vector_elements()

  • Type specific array-from-vector:

bson_append_array_from_vector_int8()

Synopsis

#define BSON_APPEND_ARRAY_FROM_VECTOR_INT8(b, key, view) \
   bson_append_array_from_vector_int8 (b, key, (int) strlen (key), view)

bool
bson_append_array_from_vector_int8 (bson_t *bson,
                                    const char *key,
                                    int key_length,
                                    bson_vector_int8_const_view_t view);

Parameters

  • bson: A bson_t.
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • view: A bson_vector_int8_const_view_t pointing to validated int8 BSON Binary Vector subtype data.

Description

Converts the Vector pointed to by view into a plain BSON Array, written to bson under the name key.

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX.

๐ŸŒธ SEE ALSO: bson_array_builder_append_vector_int8_elements()

bson_append_array_from_vector_float32()

Synopsis

#define BSON_APPEND_ARRAY_FROM_VECTOR_FLOAT32(b, key, view) \
   bson_append_array_from_vector_float32 (b, key, (int) strlen (key), view)

bool
bson_append_array_from_vector_float32 (bson_t *bson,
                                       const char *key,
                                       int key_length,
                                       bson_vector_float32_const_view_t view);

Parameters

  • bson: A bson_t.
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • view: A bson_vector_float32_const_view_t pointing to validated float32 BSON Binary Vector subtype data.

Description

Converts the Vector pointed to by view into a plain BSON Array, written to bson under the name key.

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX.

๐Ÿฆ‹ SEE ALSO: bson_array_builder_append_vector_float32_elements()

bson_append_array_from_vector_packed_bit()

Synopsis

#define BSON_APPEND_ARRAY_FROM_VECTOR_PACKED_BIT(b, key, view) \
   bson_append_array_from_vector_packed_bit (b, key, (int) strlen (key), view)

bool
bson_append_array_from_vector_packed_bit (bson_t *bson,
                                          const char *key,
                                          int key_length,
                                          bson_vector_packed_bit_const_view_t view);

Parameters

  • bson: A bson_t.
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • view: A bson_vector_packed_bit_const_view_t pointing to validated packed_bit BSON Binary Vector subtype data.

Description

Converts the Vector pointed to by view into a plain BSON Array, written to bson under the name key.

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX.

๐ŸŽ€ SEE ALSO: bson_array_builder_append_vector_packed_bit_elements()

  • Using bson_array_builder_t for array-from-vector:

bson_array_builder_append_vector_int8_elements()

Synopsis

bool
bson_array_builder_append_vector_int8_elements (bson_array_builder_t *builder,
                                                bson_vector_int8_const_view_t view);

Parameters

  • builder: A valid bson_array_builder_t.
  • view: A bson_vector_int8_const_view_t pointing to validated int8 BSON Binary Vector subtype data.

Description

Converts the Vector pointed to by view into elements of a plain BSON Array, written to builder. Every element will be losslessly extended from int8_t to int32_t โ€” no data lost, we love a clean upgrade ๐Ÿ’….

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX.

๐Ÿ’œ SEE ALSO: bson_append_array_from_vector(), bson_array_builder_append_vector_elements()

bson_array_builder_append_vector_float32_elements()

Synopsis

bool
bson_array_builder_append_vector_float32_elements (bson_array_builder_t *builder,
                                                   bson_vector_float32_const_view_t view);

Parameters

  • builder: A valid bson_array_builder_t.
  • view: A bson_vector_float32_const_view_t pointing to validated float32 BSON Binary Vector subtype data.

Description

Converts the Vector pointed to by view into elements of a plain BSON Array, written to builder. Every element will be converted from float to double precision. Precision maxxing ๐Ÿงš.

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX.

โญ SEE ALSO: bson_append_array_from_vector(), bson_array_builder_append_vector_elements()

bson_array_builder_append_vector_packed_bit_elements()

Synopsis

bool
bson_array_builder_append_vector_packed_bit_elements (bson_array_builder_t *builder,
                                                      bson_vector_packed_bit_const_view_t view);

Parameters

  • builder: A valid bson_array_builder_t.
  • view: A bson_vector_packed_bit_const_view_t pointing to validated packed_bit BSON Binary Vector subtype data.

Description

Converts the Vector pointed to by view into elements of a plain BSON Array, written to builder. Every element will be 0 or 1 written as a BSON_TYPE_INT32. Binary behavior, literally ๐Ÿ“.

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX.

๐Ÿ”ฅ SEE ALSO: bson_append_array_from_vector(), bson_array_builder_append_vector_elements()

bson_array_builder_append_vector_elements()

Synopsis

bool
bson_array_builder_append_vector_elements (bson_array_builder_t *builder,
                                           const bson_iter_t *iter);

Parameters

  • builder: A valid bson_array_builder_t.
  • iter: A bson_iter_t pointing to any supported BSON Binary Vector subtype field.

Description

Converts the Vector pointed to by iter into elements of a plain BSON Array, written to builder. This conversion is polymorphic: a converted element type will be chosen based on the type of the input Vector. For details, see the type-specific versions of this function. One function, many vibes ๐ŸŒˆ.

Returns

Returns true if the operation was applied successfully. The function fails if appending the array grows bson larger than INT32_MAX, or if iter doesn't point to a valid recognized Vector type.

๐Ÿ‘‘ SEE ALSO: bson_append_array_from_vector(), bson_array_builder_append_vector_int8_elements(), bson_array_builder_append_vector_float32_elements(), bson_array_builder_append_vector_packed_bit_elements()

  • Type specific vector-from-array:

bson_append_vector_int8_from_array()

Synopsis

#define BSON_APPEND_VECTOR_INT8_FROM_ARRAY(b, key, iter, err) \
   bson_append_vector_int8_from_array (b, key, (int) strlen (key), iter, err)

bool
bson_append_vector_int8_from_array (bson_t *bson,
                                    const char *key,
                                    int key_length,
                                    const bson_iter_t *iter,
                                    bson_error_t *error);

Parameters

  • bson: A bson_t.
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • iter: A bson_iter_t referencing array elements that will be converted.
  • error: Optional bson_error_t for detail about conversion failures. It's optional, but bestie, you want the tea when something breaks ๐Ÿ™ˆ.

Description

Appends a new field to bson by converting an Array to a Vector of int8 elements.

For the conversion to succeed, every item in the Array must be an integer (BSON_TYPE_INT32 or BSON_TYPE_INT64) in the range INT8_MIN (-128) through INT8_MAX (127) inclusive. If any element has an incorrect type or an out-of-range value, the conversion fails with an error message providing details, and no changes are made to bson โ€” all-or-nothing, no half-finished fits ๐Ÿ˜ญ.

The provided iter must be positioned just prior to the first element of the BSON Array. If your input is a bare BSON Array, set up iter using bson_iter_init(). If the input is within a document field, use bson_iter_recurse(). Position matters, no cap ๐Ÿ’€.

okay so the return value tea first, then we get into the good stuff ๐Ÿ’–

Returns

Returns true if the operation was applied successfully. On error, returns false and writes additional error information to error without modifying bson. The error will have a domain of BSON_ERROR_VECTOR and a code from bson_vector_error_code_t.


๐Ÿ’… bson_append_vector_float32_from_array()

Synopsis

#define BSON_APPEND_VECTOR_FLOAT32_FROM_ARRAY(b, key, iter, err) \
   bson_append_vector_float32_from_array (b, key, (int) strlen (key), iter, err)

bool
bson_append_vector_float32_from_array (bson_t *bson,
                                       const char *key,
                                       int key_length,
                                       const bson_iter_t *iter,
                                       bson_error_t *error);

Parameters

  • bson: A bson_t.
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • iter: A bson_iter_t referencing array elements that will be converted.
  • error: Optional bson_error_t for detail about conversion failures.

Description

Appends a new field to bson by converting an Array to a Vector of float32 elements. ๐Ÿฆ‹

For the conversion to succeed, every item in the Array must be double-precision floating point number. (BSON_TYPE_DOUBLE) no cap, all of them, every single one.

The provided iter must be positioned just prior to the first element of the BSON Array. If your input is a bare BSON Array, set up iter using bson_iter_init(). If the input is within a document field, use bson_iter_recurse(). ๐Ÿ“

Returns

Returns true if the operation was applied successfully. On error, returns false and writes additional error information to error without modifying bson. The error will have a domain of BSON_ERROR_VECTOR and a code from bson_vector_error_code_t.


๐ŸŽ€ bson_append_vector_packed_bit_from_array()

Synopsis

#define BSON_APPEND_VECTOR_PACKED_BIT_FROM_ARRAY(b, key, iter, err) \
   bson_append_vector_packed_bit_from_array (b, key, (int) strlen (key), iter, err)

bool
bson_append_vector_packed_bit_from_array (bson_t *bson,
                                          const char *key,
                                          int key_length,
                                          const bson_iter_t *iter,
                                          bson_error_t *error);

Parameters

  • bson: A bson_t.
  • key: An ASCII C string containing the name of the field.
  • key_length: The length of key in bytes, or -1 to determine the length with strlen().
  • iter: A bson_iter_t referencing array elements that will be converted.
  • error: Optional bson_error_t for detail about conversion failures.

Description

Appends a new field to bson by converting an Array to a Vector of packed_bit elements. โญ

For the conversion to succeed, every item in the Array must be either an integer (BSON_TYPE_INT32 or BSON_TYPE_INT64) with the values 0 or 1, or boolean (BSON_TYPE_BOOL). If any element has an incorrect type or an out-of-range value, the conversion fails with an error message providing details, and no changes are made to bson. bestie that's a hard no, nothing gets written ๐Ÿ’€

The provided iter must be positioned just prior to the first element of the BSON Array. If your input is a bare BSON Array, set up iter using bson_iter_init(). If the input is within a document field, use bson_iter_recurse().

Returns

Returns true if the operation was applied successfully. On error, returns false and writes additional error information to error without modifying bson. The error will have a domain of BSON_ERROR_VECTOR and a code from bson_vector_error_code_t.


โœจ Additional Definitions

  • Binary subtype:
typedef enum {
  BSON_SUBTYPE_VECTOR = 0x09,
  /* ... */
} bson_subtype_t;
  • Byte length of the Vector header:
// Length of the required header for BSON_SUBTYPE_VECTOR, in bytes
#define BSON_VECTOR_HEADER_LEN 2
  • Byte length for a Vector with specific element type and count: ๐Ÿ‘‡ (it's the next three icons, keep reading)

๐Ÿงš bson_vector_int8_binary_data_length()

Calculate the size of a BSON Binary field that would be needed to store a Vector with the indicated number of int8 elements.

Synopsis

uint32_t
bson_vector_int8_binary_data_length (size_t element_count);

Parameters

  • element_count: Number of elements, as a size_t.

Description

Checks element_count against the maximum representable size, and calculates the required Binary size. ๐Ÿ”ฅ

Returns

On success, returns the required Binary size as a uint32_t greater than or equal to BSON_VECTOR_HEADER_LEN. This length includes the 2-byte Vector header, but not the Binary subtype header or any other BSON headers. If the element_count is too large to represent, returns 0.


๐ŸŒธ bson_vector_float32_binary_data_length()

Calculate the size of a BSON Binary field that would be needed to store a Vector with the indicated number of float32 elements.

Synopsis

uint32_t
bson_vector_float32_binary_data_length (size_t element_count);

Parameters

  • element_count: Number of elements, as a size_t.

Description

Checks element_count against the maximum representable size, and calculates the required Binary size. ๐Ÿ’–

Returns

On success, returns the required Binary size as a uint32_t greater than or equal to BSON_VECTOR_HEADER_LEN. This length includes the 2-byte Vector header, but not the Binary subtype header or any other BSON headers. If the element_count is too large to represent, returns 0.


๐Ÿฆ‹ bson_vector_packed_bit_binary_data_length()

Calculate the size of a BSON Binary field that would be needed to store a Vector with the indicated number of packed_bit elements.

Synopsis

uint32_t
bson_vector_packed_bit_binary_data_length (size_t element_count);

Parameters

  • element_count: Number of single-bit elements, as a size_t. ๐Ÿ‘€ single BIT, not byte, keep up

Description

Checks element_count against the maximum representable size, and calculates the required Binary size.

Returns

On success, returns the required Binary size as a uint32_t greater than or equal to BSON_VECTOR_HEADER_LEN. This length includes the 2-byte Vector header, but not the Binary subtype header or any other BSON headers. If the element_count is too large to represent, returns 0.


  • Errors:
// Error "domain"
#define BSON_ERROR_VECTOR 4

๐Ÿ‘‘ bson_vector_error_code_t

BSON Error codes for BSON Binary Vector subtype operations that could fail in multiple ways. like, it's giving "so many ways to go wrong" ๐Ÿ˜ญ

Synopsis

#define BSON_ERROR_VECTOR 4

typedef enum {
  BSON_VECTOR_ERROR_ARRAY_ELEMENT_TYPE = 1,
  BSON_VECTOR_ERROR_ARRAY_ELEMENT_VALUE = 2,
  BSON_VECTOR_ERROR_ARRAY_KEY = 3,
  BSON_VECTOR_ERROR_MAX_SIZE = 4,
} bson_vector_error_code_t;

Description

The error code values in bson_vector_error_code_t apply to bson_error_t values with a category of BSON_ERROR_CATEGORY and a domain of BSON_ERROR_VECTOR. ๐ŸŒˆ

  • BSON_VECTOR_ERROR_ARRAY_ELEMENT_TYPE: An element was encountered with incorrect type. Location and type details in message.
  • BSON_VECTOR_ERROR_ARRAY_ELEMENT_VALUE: An element was encountered with out-of-range value. Location and value details in message.
  • BSON_VECTOR_ERROR_ARRAY_KEY: An input BSON Array did not contain the expected numeric key value. Expected and actual keys in message.
  • BSON_VECTOR_ERROR_MAX_SIZE: The BSON maximum document size would be exceeded. Equivalent to a failure from bson_append_* functions that do not return an error.

๐ŸŒˆ LIBBSON VERSIONING

Versioning Macros and Functions ๐Ÿซถ

Macros

The following preprocessor macros can be used to perform various checks based on the version of the library you are compiling against. This may be useful if you only want to enable a feature on a certain version of the library. lowkey iconic behaviour honestly

Synopsis

#define BSON_CHECK_VERSION(major, minor, micro)

#define BSON_MAJOR_VERSION (1)
#define BSON_MINOR_VERSION (4)
#define BSON_MICRO_VERSION (1)
#define BSON_VERSION_S "1.4.1"

#define BSON_VERSION_HEX                                  \
   (BSON_MAJOR_VERSION << 24 | BSON_MINOR_VERSION << 16 | \
    BSON_MICRO_VERSION << 8)

Only compile a block on Libbson 1.1.0 and newer. ๐Ÿ‘‡

#if BSON_CHECK_VERSION(1, 1, 0)
static void
do_something (void)
{
}
#endif

๐Ÿฆ‹ LIBBSON LEGACY EXTENDED JSON

libbson can produce a non-portable Legacy Extended JSON format.

WARNING โš ๏ธ: Use of the Legacy Extended JSON format is discouraged. Prefer Canonical Extended JSON or Relaxed Extended JSON for portability. bestie pls, choose portability ๐Ÿ’€

MongoDB Extended JSON (v2) describes the preferred Relaxed Extended JSON format and Canonical Extended Formats.

libbson's Legacy Extended JSON format matches Relaxed Extended JSON with the following exceptions. Notation is borrowed from MongoDB Extended JSON (v2): ๐ŸŽ€

  • Binary
{ "$binary": "<payload>", "$type": "<t>" }
  • Date
{ "$date" : "<millis>" }
  • Regular Expression
{ "$regex" : "<regexPattern>", "$options" : "<options>" }
  • DBPointer (deprecated) โ€” bestie, this one is deprecated, so don't make it your whole personality ๐Ÿ’… It's giving { "$ref" : "<collection namespace>", "$id" : "<ObjectId bytes>" } โœจ
  • Symbol (deprecated) โ€” also deprecated, and it's literally just "<string>" โ€” a little museum piece ๐Ÿ›๏ธ
  • Double infinity โ€” infinity or inf without quotes. Implementation defined. Produces invalid JSON. ๐Ÿ’€
  • Double NaN โ€” nan or nan(n-char-sequence). Implementation defined. Produces invalid JSON. ๐Ÿ˜ญ

๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

MongoDB, Inc

2009-present, MongoDB, Inc.


That's the whole BSON_REFERENCE(3) page, bestie โ€” version 2.5.6, dated Oct 09, 2026, page BSON_REFERENCE(3). Stay iconic ๐Ÿ’–๐Ÿฆ‹

๐Ÿ“ฆ where this page comes from