text: /**
   *     Copyright 2013 Couchbase, 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 PYCBC_H_
  #define PYCBC_H_
  /**
   * This file contains the base header for the Python Couchbase Client
   * @author Mark Nunberg
   */
  
  #define PYCBC_TRACE_FINISH_SPANS
  #define PYCBC_GLOBAL_SCHED
  #define PYCBC_POSTINCREMENT
  #define PYCBC_FREE_ACCOUNTING
  #define PYCBC_FREE_CONTEXTS
  
  #ifdef PYCBC_REF_ACCOUNTING_ENABLE
  #define PYCBC_REF_ACCOUNTING
  #endif
  
  #define PYCBC_REF_CLEANUP_ENABLE
  
  #ifdef PYCBC_REF_ACCOUNTING
  #ifdef PYCBC_REF_CLEANUP_ENABLE
  #define PYCBC_REF_CLEANUP
  #endif
  #endif
  
  
  #define PYCBC_GC 3
  #define PYCBC_AUTO_DEREF_FAILED
  
  #include "python_wrappers.h"
  #define PYCBC_COLLECTIONS
  
  /**
   * This code supports both PYCBC V2 and PYCBC V3. The
  idea is to wrap the LCB V3 API and the features it supports
  in the V4 API, or V4-style functions/macros.
  
  Everything is, as far as possible,
  written against the V4 API or an abstraction thereof.
  
  Mostly the V4 API changes
  affect:
  
  1. creational logic:
   wrapped using CMDSCOPE_NG etc, as defined in pycbc.h
  
  2. 'shared' attributes of structures.
   PYCBC_LCB_API represents LCB_API version,
   but we use 0x02FF0x for V3 alphas (e.g. 0x02FF04 for 3.0.0 Alpha 4).
   */
  
  #include "lcb_v4_wrapper.h"
  
  // TODO: fix in libcouchbase
  #ifdef _WIN32
  //#if _MSC_VER >= 1600
  //        #include <cstdint>
  //#else
      typedef __int8              int8_t;
      typedef __int16             int16_t;
  //#endif
  #include "libcouchbase/sysdefs.h"
  #define uint8_t lcb_uint8_t
  #define uint16_t lcb_uint16_t
  #define uint64_t lcb_uint64_t
  #endif
  
  #include <libcouchbase/crypto.h>
  #include "../build/lcb_min_version.h"
  
  #include <pythread.h>
  #include "mresdict.h"
  
  #define PYCBC_REFCNT_ASSERT pycbc_assert
  
  void pycbc_fetch_error(PyObject *err[3]);
  void pycbc_store_error(PyObject *err[3]);
  lcb_STATUS pycbc_report_err(int res, const char *generic_errmsg, const char* FILE, int LINE);
  #define PYCBC_REPORT_ERR(RES, MSG) pycbc_report_err(RES,MSG, __FILE__, __LINE__);
  
  void *malloc_and_log(const char *file,
                       const char *func,
                       int line,
                       size_t quant,
                       size_t size,
                       const char *type_name);
  void *calloc_and_log(const char *file,
                       const char *func,
                       int line,
                       size_t quant,
                       size_t size,
                       const char *type_name);
  
  #define PYCBC_STASH_EXCEPTION(OP)                           \
      {                                                       \
          PyObject *pycbc_err[3] = {0};                       \
          pycbc_store_error(pycbc_err);                       \
          {                                                   \
              OP;                                             \
          }                                                   \
          if (pycbc_err[0] || pycbc_err[1] || pycbc_err[2]) { \
              pycbc_fetch_error(pycbc_err);                   \
          }                                                   \
      };
  
  /**
   * See http://docs.python.org/2/c-api/arg.html for an explanation of this
   * definition.
   */
  #ifdef PY_SSIZE_T_CLEAN
  typedef Py_ssize_t pycbc_strlen_t;
  #else
  typedef int pycbc_strlen_t;
  #endif
  
  #define PYCBC_MODULE_NAME "_libcouchbase"
  #define PYCBC_FQNAME PYCBC_PACKAGE_NAME "." PYCBC_MODULE_NAME
  
  #define PYCBC_TCNAME_ENCODE_KEY "encode_key"
  #define PYCBC_TCNAME_ENCODE_VALUE "encode_value"
  #define PYCBC_TCNAME_DECODE_KEY "decode_key"
  #define PYCBC_TCNAME_DECODE_VALUE "decode_value"
  
  /**
   * Python 2.x and Python 3.x have different ideas of what a basic string
   * and int types are. These blocks help us sort things out if we just want a
   * "plain" integer or string
   */
  #if PY_MAJOR_VERSION == 3
  #define PYCBC_POBJ_HEAD_INIT(t) { PyObject_HEAD_INIT(t) },
  
  /**
   * The IntFrom* macros get us a 'default' integer type from a long, etc.
   * Implemented (if not a simple macro) in numutil.c
   */
  #define pycbc_IntFromL PyLong_FromLong
  #define pycbc_IntFromUL PyLong_FromUnsignedLong
  #define pycbc_IntFromULL PyLong_FromUnsignedLongLong
  
  /**
   * The IntAs* convert the integer type (long, int) into something we want
   */
  #define pycbc_IntAsULL PyLong_AsUnsignedLongLong
  #define pycbc_IntAsLL PyLong_AsLongLong
  #define pycbc_IntAsUL PyLong_AsUnsignedLong
  #define pycbc_IntAsL PyLong_AsLong
  
  /**
   * The SimpleString macros generate strings for us. The 'Z' variant takes a
   * NUL-terminated string, while the 'N' variant accepts a length specifier
   */
  #define pycbc_SimpleStringZ(c) PyUnicode_FromString(c)
  #define pycbc_SimpleStringN(c, n) PyUnicode_FromStringAndSize(c, n)
  
  
  #else
  
  /**
   * This defines the PyObject head for our types
   */
  #define PYCBC_POBJ_HEAD_INIT(t) PyObject_HEAD_INIT(t)
  
  /**
   * See above block for explanation of these macros
   */
  #define pycbc_IntFromL PyInt_FromLong
  #define pycbc_IntFromUL PyLong_FromUnsignedLong
  #define pycbc_IntFromULL PyLong_FromUnsignedLongLong
  #define pycbc_SimpleStringZ(c) PyString_FromString(c)
  #define pycbc_SimpleStringN(c, n) PyString_FromStringAndSize(c, n)
  
  unsigned PY_LONG_LONG pycbc_IntAsULL(PyObject *o);
  PY_LONG_LONG pycbc_IntAsLL(PyObject *o);
  long pycbc_IntAsL(PyObject *o);
  unsigned long pycbc_IntAsUL(PyObject *o);
  
  #endif
  
  const char *pycbc_cstr(PyObject *object);
  const char *pycbc_cstrn(PyObject *object, Py_ssize_t *length);
  
  #define PYCBC_CSTR(X) pycbc_cstr(X)
  #define PYCBC_CSTRN(X, n) pycbc_cstrn((X), (Py_ssize_t *)(n))
  
  PyObject* pycbc_replace_str(PyObject** string, const char* pat, const char* replace);
  PyObject *pycbc_none_or_value(PyObject *maybe_value);
  
  /**
   * Fetches a valid TTL from the object
   * @param obj an object to be parsed as the TTL
   * @param ttl a pointer to the TTL itself
   * @param canbezero whether to allow a value of 0 for the TTL
   * @return 0 on success, nonzero on error.
   */
  int pycbc_get_duration(PyObject *obj, unsigned long *ttl, int canbezero);
  
  /**
   * Fetches a valid 32 bit integer from the object. The object must be a long
   * or int.
   * @param obj the object containing the number
   * @param out a pointer to a 32 bit integer to be populated
   * @return 0 on success, -1 on failure. On failure, the error indicator is also
   * set
   */
  int pycbc_get_u32(PyObject *obj, lcb_uint32_t *out);
  
  /**
   * Converts the object into an PyInt (2.x only) or PyLong (2.x or 3.x)
   */
  PyObject *pycbc_maybe_convert_to_int(PyObject *o);
  
  /**
   * Gives us a C buffer from a Python string.
   * @param orig the original object containg a string thing. This is something
   * we can convert into a byte buffer
   *
   * @param buf out, the C buffer, out, set to the new buffer
   * @param nbuf, out, the length of the new buffer
   * @param newkey, out, the new PyObject, which will back the buffer.
   * This should not be DECREF'd until the @c buf is no longer needed
   */
  int pycbc_BufFromString(PyObject *orig,
                          char **buf,
                          Py_ssize_t *nbuf,
                          PyObject **newkey);
  
  
  /**
   * These constants are used internally to figure out the high level
   * operation being performed.
   *
   * Note that not all operations are defined here; it is only those operations
   * where a single C function can handle multiple entry points.
   */
  enum {
      PYCBC_CMD_GET = 500,
      PYCBC_CMD_LOCK,
      PYCBC_CMD_TOUCH,
      PYCBC_CMD_GAT,
      PYCBC_CMD_COUNTER,
      PYCBC_CMD_DELETE,
      PYCBC_CMD_UNLOCK,
      PYCBC_CMD_GETREPLICA,
      /** "Extended" get replica, provides for more options */
      PYCBC_CMD_GETREPLICA_INDEX,
      PYCBC_CMD_GETREPLICA_ALL,
      PYCBC_CMD_ENDURE,
      PYCBC_CMD_EXISTS
  };
  
  /**
   * Various exception types to be thrown
   */
  enum {
      /** Argument Error. User passed the wrong arguments */
      PYCBC_EXC_ARGUMENTS,
  
      /** Couldn't encode/decode something */
      PYCBC_EXC_ENCODING,
  
      /** Operational error returned from LCB */
      PYCBC_EXC_LCBERR,
  
      /** Internal error. There's something wrong with our code */
      PYCBC_EXC_INTERNAL,
  
      /** HTTP Error */
      PYCBC_EXC_HTTP,
  
      /** ObjectThreadError */
      PYCBC_EXC_THREADING,
  
      /** Object destroyed before it could connect */
      PYCBC_EXC_DESTROYED,
  
      /** Illegal operation in pipeline context */
      PYCBC_EXC_PIPELINE
  };
  
  /* Argument options */
  enum {
      /** Entry point is a single key variant */
      PYCBC_ARGOPT_SINGLE = 0x1,
  
      /** Entry point is a multi key variant */
      PYCBC_ARGOPT_MULTI = 0x2,
  
      PYCBC_ARGOPT_SUBDOC = 0x04,
  
      PYCBC_ARGOPT_SDMULTI = 0x08
  };
  
  /**
   * Format flags
   */
  enum {
      PYCBC_FMT_LEGACY_JSON = 0x00,
      PYCBC_FMT_LEGACY_PICKLE = 0x01,
      PYCBC_FMT_LEGACY_BYTES = 0x02,
      PYCBC_FMT_LEGACY_UTF8 = 0x04,
      PYCBC_FMT_LEGACY_MASK = 0x07,
  
      PYCBC_FMT_COMMON_PICKLE = (0x01U << 24),
      PYCBC_FMT_COMMON_JSON = (0x02U << 24),
      PYCBC_FMT_COMMON_BYTES = (0x03U << 24),
      PYCBC_FMT_COMMON_UTF8 = (0x04U << 24),
      PYCBC_FMT_COMMON_MASK = (0xFFU << 24),
  
      PYCBC_FMT_JSON = PYCBC_FMT_LEGACY_JSON|PYCBC_FMT_COMMON_JSON,
      PYCBC_FMT_PICKLE = PYCBC_FMT_LEGACY_PICKLE|PYCBC_FMT_COMMON_PICKLE,
      PYCBC_FMT_BYTES = PYCBC_FMT_LEGACY_BYTES|PYCBC_FMT_COMMON_BYTES,
      PYCBC_FMT_UTF8 = PYCBC_FMT_LEGACY_UTF8|PYCBC_FMT_COMMON_UTF8
  };
  
  typedef enum {
      PYCBC_LOCKMODE_NONE = 0,
      PYCBC_LOCKMODE_EXC = 1,
      PYCBC_LOCKMODE_WAIT = 2,
      PYCBC_LOCKMODE_MAX
  } pycbc_lockmode_t;
  
  enum {
      PYCBC_CONN_F_WARNEXPLICIT = 1 << 0,
      PYCBC_CONN_F_USEITEMRESULT = 1 << 1,
      PYCBC_CONN_F_CLOSED = 1 << 2,
  
      /**
       * For use with (but not limited to) Twisted.
       *
       * Deliver results asynchronously. This means:
       * 1) Don't call lcb_wait()
       * 2) Return an AsyncContainer (i.e. a MultiResult)
       * 3) Invoke the MultiResult (AsyncContainer)'s callback as needed
       */
      PYCBC_CONN_F_ASYNC = 1 << 3,
  
      /** Whether this instance has been connected */
      PYCBC_CONN_F_CONNECTED = 1 << 4,
  
      /** Schedule destruction of iops and lcb instance for later */
      PYCBC_CONN_F_ASYNC_DTOR = 1 << 5
  };
  
  
  #ifndef PYCBC_DUR_DISABLED
  #define PYCBC_DUR_ENABLED
  #endif
  
  #ifdef PYCBC_DUR_ENABLED
  #define PYCBC_SYNCREP_INIT(ERR, CMD, TYPE, SYNCREP_LEVEL)\
      PYCBC_DEBUG_LOG("Setting sync durability level %d",            \
                      SYNCREP_LEVEL)                        \
      ERR = lcb_cmd##TYPE##_durability(CMD, SYNCREP_LEVEL); \
  
  #    define PYCBC_DUR_INIT(ERR, CMD, TYPE, DUR)                            \
          if ((DUR).durability_level) {                                      \
              PYCBC_SYNCREP_INIT(ERR,CMD, TYPE, (DUR).durability_level)      \
              assert(!((DUR).persist_to || (DUR).replicate_to));             \
          }                                                                  \
          if ((DUR).persist_to || (DUR).replicate_to) {                      \
              PYCBC_DEBUG_LOG(                                               \
                      "Setting client durability level persist_to=%d, "      \
                      "replicate_to=%d",                                     \
                      (DUR).persist_to,                                      \
                      (DUR).replicate_to)                                    \
              ERR = lcb_cmd##TYPE##_durability_observe(                      \
                      CMD, (DUR).persist_to, (DUR).replicate_to);            \
          }
  #else
  #    define PYCBC_DUR_INIT(ERR, CMD, TYPE, DUR)
  #endif
  
  void pycbc_dict_add_text_kv(PyObject *dict, const char *key, const char *value);
  
  struct pycbc_Tracer;
  
  #define PYCBC_TRACING
  
  
  extern pycbc_strn pycbc_invalid_strn;
  
  extern const char PYCBC_UNKNOWN[];
  static char *const PYCBC_DEBUG_INFO_STR = "debug_info";
  #define sizeof_array(X) sizeof(X) / sizeof(X[0])
  
  #define PYCBC_STRN_FREE(BUF)                            \
      PYCBC_DEBUG_LOG("Freeing string buffer %.*s at %p", \
                      (int)(BUF).content.length,          \
                      (BUF).content.buffer,               \
                      (BUF).content.buffer)               \
      pycbc_strn_free(BUF);
  
  #define PYCBC_DUMMY(...)
  
  #define CMDSCOPE_GENERIC_FAIL(PREFIX, UC, LC) \
      fail = 1;                                 \
      goto GT_##PREFIX##_##UC##_ERR;
  
  #define CMDSCOPE_GENERIC_DONE(PREFIX, UC, LC) goto GT_##PREFIX##_##UC##_DONE;
  
  #define CMDSCOPE_GENERIC_ALL_PREFIX(                                           \
          PREFIX, UC, LC, INITIALIZER, DESTRUCTOR, CMDS, ...)                    \
      INITIALIZER(UC, LC, CMDS, __VA_ARGS__);                                    \
      PYCBC_DEBUG_LOG("Called initialzer for %s, %s, with args %s",              \
                      #UC,                                                       \
                      #LC,                                                       \
                      #__VA_ARGS__)                                              \
      goto SKIP_##PREFIX##_##UC##_FAIL;                                          \
      goto GT_##PREFIX##_##UC##_DONE;                                            \
      GT_##PREFIX##_##UC##_DONE : PYCBC_DEBUG_LOG("Cleanup up %s %s", #UC, #LC)( \
                                          void)(DESTRUCTOR(UC, LC, CMDS));       \
      goto GT_DONE;                                                              \
      goto GT_##PREFIX##_##UC##_ERR;\
      GT_##PREFIX##_##UC##_ERR : (void)(DESTRUCTOR(UC, LC, CMDS));               \
      goto GT_ERR;                                                               \
                                                                                 \
      SKIP_##PREFIX##_##UC##_FAIL                                                \
          : for (int finished = 0, fail = 0; !(finished) && !fail;               \
                 (finished = (1 + DESTRUCTOR(UC, LC, CMDS))))
  
  #define CMDSCOPE_GENERIC_ALL(UC, LC, INITIALIZER, DESTRUCTOR, CMDS, ...) \
      CMDSCOPE_GENERIC_ALL_PREFIX(                                         \
              , UC, LC, INITIALIZER, DESTRUCTOR, CMDS, __VA_ARGS__)
  
  #define pycbc_verb_postfix(POSTFIX, VERB, INSTANCE, COOKIE, CMD) \
      pycbc_logging_monad_verb(__FILE__,                           \
                               __FUNCTION__,                       \
                               __LINE__,                           \
                               INSTANCE,                           \
                               COOKIE,                             \
                               CMD,                                \
                               #CMD,                               \
                               #VERB,                              \
                               lcb_##VERB##POSTFIX(INSTANCE, COOKIE, CMD))
  
  lcb_STATUS pycbc_logging_monad_verb(const char *FILE,
                                      const char *FUNC,
                                      int LINE,
                                      lcb_INSTANCE *instance,
                                      void *COOKIE,
                                      void *CMD,
                                      const char *CMDNAME,
                                      const char *VERB,
                                      lcb_STATUS result);
  
  #define IMPL_DECL(...)
  #define DECL_IMPL(...) __VA_ARGS__
  #define DECL_DECL(...) DECL_IMPL(__VA_ARGS__);
  #define IMPL_IMPL(...) __VA_ARGS__
  
  #define CMDSCOPE_SDCMD_CREATE_V4(TYPE, LC, CMD, ...) \
      TYPE *CMD = NULL;                                \
      lcb_##LC##_create(&(CMD), __VA_ARGS__);
  
  #define CMDSCOPE_SDCMD_DESTROY_RAW_V4(TYPE, LC, CMD, ...) \
      lcb_##LC##_destroy(CMD)
  
  #define CMDSCOPE_CREATECMD_RAW_V4(UC, LC, CMD, ...) \
      lcb_CMD##UC *CMD = NULL;                        \
      lcb_cmd##LC##_create(&CMD)
  
  #define CMDSCOPE_CREATECMD_V4(UC, LC, CMD, ...) \
      lcb_CMD##UC *CMD = NULL;                    \
      lcb_cmd##LC##_create(&CMD, __VA_ARGS__)
  
  #define CMDSCOPE_DESTROYCMD_V4(UC, LC, CMD, ...) lcb_cmd##LC##_destroy(CMD)
  
  #define CMDSCOPE_DESTROYCMD_RAW_V4(UC, LC, CMD, ...) lcb_cmd##LC##_destroy(CMD)
  
  #define CMDSCOPE_NG_V4(UC, LC)                       \
      CMDSCOPE_GENERIC_ALL(UC,                         \
                           LC,                         \
                           CMDSCOPE_CREATECMD_RAW_V4,  \
                           CMDSCOPE_DESTROYCMD_RAW_V4, \
                           cmd)
  #define CMDSCOPE_NG(UC, LC) \
      CMDSCOPE_GENERIC_ALL(   \
              UC, LC, CMDSCOPE_CREATECMD_RAW, CMDSCOPE_DESTROYCMD_RAW, cmd)
  
  #define CMDSCOPE_NG_PARAMS(UC, LC, ...) \
      CMDSCOPE_GENERIC_ALL(               \
              UC, LC, CMDSCOPE_CREATECMD, CMDSCOPE_DESTROYCMD, cmd, __VA_ARGS__)
  #define CMDSCOPE_NG_GENERIC_PARAMS(PREFIX, TYPE, LC, CMDNAME, ...) \
      CMDSCOPE_GENERIC_ALL_PREFIX(PREFIX,                            \
                                  TYPE,                              \
                                  LC,                                \
                                  CMDSCOPE_SDCMD_CREATE_V4,          \
                                  CMDSCOPE_SDCMD_DESTROY_RAW_V4,     \
                                  CMDNAME,                           \
                                  __VA_ARGS__)
  
  
  typedef struct {
  #define PYCBC_BUCKET_BASE                                                    \
      PyObject_HEAD /** LCB instance */                                        \
              lcb_INSTANCE *instance;                                          \
      /** Tracer **/                                                           \
      struct pycbc_Tracer *tracer;                                             \
      PyObject *parent_tracer;                                                 \
      /** Transcoder object */                                                 \
      PyObject *tc;                                                            \
                                                                               \
      /** Default format, PyInt */                                             \
      PyObject *dfl_fmt;                                                       \
                                                                               \
      /** Callback to be invoked when connected */                             \
      PyObject *conncb;                                                        \
                                                                               \
      /**                                                                      \
       * Callback to be invoked upon destruction. Because we can fall out      \
       * of scope in middle of an LCB function, this is required.              \
       *                                                                       \
       * The dtorcb is first called when the refcount of the connection        \
       */                                                                      \
      PyObject *dtorcb;                                                        \
                                                                               \
      /**                                                                      \
       * Test hook for reacting to durability/persistence settings from within \
       * mutator functions                                                     \
       */                                                                      \
      PyObject *dur_testhook;                                                  \
                                                                               \
      /** String bucket */                                                     \
      PyObject *bucket;                                                        \
                                                                               \
      /** Bucket type */                                                       \
      PyObject *btype;                                                         \
                                                                               \
      /** Pipeline MultiResult container */                                    \
      PyObject *pipeline_queue;                                                \
                                                                               \
      /** If using a custom IOPS, this contains it */                          \
      PyObject *iopswrap;                                                      \
                                                                               \
      /** Thread state. Used to lock/unlock the GIL */                         \
      PyThreadState *thrstate;                                                 \
                                                                               \
      PyThread_type_lock lock;                                                 \
      unsigned int lockmode;                                                   \
                                                                               \
      /** Whether to not raise any exceptions */                               \
      unsigned int quiet;                                                      \
                                                                               \
      /** Whether GIL handling is in effect */                                 \
      unsigned int unlock_gil;                                                 \
                                                                               \
      /** Don't decode anything */                                             \
      unsigned int data_passthrough;                                           \
                                                                               \
      /** whether __init__ has already been called */                          \
      unsigned char init_called;                                               \
                                                                               \
      /** How many operations are waiting for a reply */                       \
      Py_ssize_t nremaining;                                                   \
                                                                               \
      unsigned int flags;                                                      \
                                                                               \
      pycbc_dur_params dur_global;                                             \
      unsigned long dur_timeout;
      PYCBC_BUCKET_BASE
  } pycbc_Bucket;
  
  /**
   * Collection structures
   */
  
  /** Text coordinates for collections */
  typedef struct {
      pycbc_strn_unmanaged collection;
      pycbc_strn_unmanaged scope;
  } pycbc_Collection_coords;
  
  /** Collection class **/
  
  typedef struct pycbc_Collection pycbc_Collection_t;
  
  struct pycbc_Collection {
      PyObject_HEAD pycbc_Bucket *bucket;
      pycbc_Collection_coords collection;
  };
  
  /**
   * Server-provided IDs/handles for collections
   */
  
  typedef struct {
      lcb_U64 manifest_id;
      lcb_U32 collection_id;
  } pycbc_coll_res_success_t;
  
  typedef struct {
      pycbc_coll_res_success_t value;
      lcb_STATUS err;
  } pycbc_coll_res_t;
  
  typedef struct {
      pycbc_coll_res_t result;
      pycbc_Collection_t *coll;
  } pycbc_coll_context;
  
  int pycbc_collection_init_from_fn_args(pycbc_Collection_t *self,
                                         pycbc_Bucket *bucket,
                                         PyObject *kwargs);
  pycbc_Collection_t pycbc_Collection_as_value(pycbc_Bucket *self,
                                               PyObject *kwargs);
  void pycbc_Collection_free_unmanaged_contents(
          const pycbc_Collection_t *collection);
  #define PYCBC_COLLECTION_XARGS(X) X("collection", &collection, "O")
  
  #ifdef PYCBC_DEBUG
  lcb_STATUS pycbc_log_coll(const char *TYPE,
                            void *CMD,
                            const char *SCOPE,
                            size_t NSCOPE,
                            const char *COLLECTION,
                            size_t NCOLLECTION,
                            lcb_STATUS RC);
  
  #    define PYCBC_DO_COLL_LOGGING_IF_APPLICABLE(               \
              TYPE, CMD, SCOPE, NSCOPE, COLLECTION, NCOLLECTION) \
          pycbc_log_coll(                                        \
                  #TYPE,                                         \
                  CMD,                                           \
                  SCOPE,                                         \
                  NSCOPE,                                        \
                  COLLECTION,                                    \
                  NCOLLECTION,                                   \
                  PYCBC_DO_COLL(                                 \
                          TYPE, CMD, SCOPE, NSCOPE, COLLECTION, NCOLLECTION))
  #else
  #    define PYCBC_DO_COLL_LOGGING_IF_APPLICABLE(               \
              TYPE, CMD, SCOPE, NSCOPE, COLLECTION, NCOLLECTION) \
          PYCBC_DO_COLL(TYPE, CMD, SCOPE, NSCOPE, COLLECTION, NCOLLECTION)
  #endif
  
  #define PYCBC_DO_COLL_IF_APPLICABLE(                                     \
          TYPE, CMD, SCOPE, NSCOPE, COLLECTION, NCOLLECTION)               \
      ((NSCOPE && SCOPE) || (COLLECTION && NCOLLECTION))                   \
              ? PYCBC_DO_COLL_LOGGING_IF_APPLICABLE(                       \
                        TYPE, CMD, SCOPE, NSCOPE, COLLECTION, NCOLLECTION) \
              : LCB_SUCCESS
  
  #define PYCBC_CMD_COLLECTION(TYPE, CMD, COLLECTION)             \
      PYCBC_DO_COLL_IF_APPLICABLE(                                \
              TYPE,                                               \
              CMD,                                                \
              (COLLECTION)->collection.scope.content.buffer,      \
              (COLLECTION)->collection.scope.content.length,      \
              (COLLECTION)->collection.collection.content.buffer, \
              (COLLECTION)->collection.collection.content.length)
  
  #define PYCBC_CMD_PROXY(UC, LC, SUBJECT, IMPL_TYPE)                            \
      DECL_##IMPL_TYPE(lcb_STATUS pycbc_##LC(                                    \
              SUBJECT##_##ARG subject, void *cookie, lcb_CMD##UC *cmd))          \
              IMPL_##IMPL_TYPE({                                                 \
                  lcb_STATUS rc = SUBJECT##_##SET_COLL(UC, LC, cmd, subject);    \
                  return rc ? rc                                                 \
                            : pycbc_verb(                                        \
                                      LC, SUBJECT##_##GETINSTANCE, cookie, cmd); \
              };)
  #define PYCBC_X_VERBS(X, COLLECTION, NOCOLLECTION, IMPL_TYPE) \
      X(COUNTER, counter, COLLECTION, IMPL_TYPE)                \
      X(GET, get, COLLECTION, IMPL_TYPE)                        \
      X(TOUCH, touch, COLLECTION, IMPL_TYPE)                    \
      X(UNLOCK, unlock, COLLECTION, IMPL_TYPE)                  \
      X(REMOVE, remove, COLLECTION, IMPL_TYPE)                  \
      X(STORE, store, COLLECTION, IMPL_TYPE)                    \
      X(HTTP, http, NOCOLLECTION, IMPL_TYPE)                    \
      X(PING, ping, NOCOLLECTION, IMPL_TYPE)                    \
      X(EXISTS, exists, COLLECTION, IMPL_TYPE)                  \
      X(SUBDOC, subdoc, COLLECTION, IMPL_TYPE)                  \
      X(GETREPLICA, getreplica, COLLECTION, IMPL_TYPE)
  
  #define COLLECTION_ARG pycbc_Collection_t *
  #define NOCOLLECTION_ARG lcb_INSTANCE *
  #define COLLECTION_GETINSTANCE subject->bucket->instance
  #define NOCOLLECTION_GETINSTANCE subject
  #define COLLECTION_SET_COLL(UC, LC, CMD, SUBJECT) \
      PYCBC_CMD_COLLECTION(LC, CMD, SUBJECT)
  #define NOCOLLECTION_SET_COLL(UC, LC, CMD, SUBJECT) LCB_SUCCESS
  PYCBC_X_VERBS(PYCBC_CMD_PROXY, COLLECTION, NOCOLLECTION, DECL);
  
  void *pycbc_capsule_value_or_null(PyObject *capsule, const char *capsule_name);
  
  typedef struct pycbc_Tracer {
      PyObject_HEAD
      lcbtrace_TRACER *tracer;
      int is_lcb_tracer;
  } pycbc_Tracer_t;
  
  typedef struct {
      PyObject_HEAD
      lcbtrace_SPAN *span;
  } pycbc_Span_t;
  
  typedef struct pycbc_context_children_t {
      pycbc_stack_context_handle value;
      struct pycbc_context_children_t *next;
  } pycbc_context_children;
  
  typedef struct pycbc_stack_context_decl {
      int is_stub;
      pycbc_Tracer_t* tracer;
      lcbtrace_SPAN* span;
      pycbc_stack_context_handle parent;
      size_t ref_count;
  #ifdef PYCBC_REF_ACCOUNTING
  #ifdef PYCBC_INLINE_ACC
      pycbc_stack_context_handle next;
      pycbc_stack_context_handle first_child;
  #else
      pycbc_context_children *acc_node;
      pycbc_context_children *children;
  #endif
  #endif
  #ifdef PYCBC_TABBED_CONTEXTS
      size_t depth;
  #endif
  } pycbc_stack_context;
  
  pycbc_strn pycbc_get_string_tag_basic(lcbtrace_SPAN *span, const char *tagname);
  PyObject *pycbc_Context_capsule(pycbc_stack_context_handle context);
  void pycbc_Context_capsule_destructor(PyObject *context_capsule);
  void *pycbc_Context_capsule_value(PyObject *context_capsule);
  
  #define PYCBC_RES_CONTEXT(MRES) (MRES) ? (MRES)->tracing_context : NULL
  
  typedef struct pycbc_Result pycbc_Result_t;
  typedef struct pycbc_MultiResult_st pycbc_MultiResult;
  void pycbc_set_dict_kv_object(PyObject *dict,
                                PyObject *key,
                                const char *value_str);
  
  void pycbc_set_kv_ull(PyObject *dict,
                        PyObject *keystr,
                        lcb_uint64_t parenti_id);
  void pycbc_set_kv_ull_str(PyObject *dict,
                            const char *keystr,
                            lcb_uint64_t parenti_id);
  
  int pycbc_is_async_or_pipeline(const pycbc_Bucket *self);
  
  pycbc_stack_context_handle pycbc_Result_start_context(
          pycbc_stack_context_handle parent_context,
          PyObject *hkey,
          const char *component,
          char *operation,
          lcbtrace_REF_TYPE ref_type);
  void pycbc_Result_propagate_context(pycbc_Result_t *res,
                                      pycbc_stack_context_handle parent_context,
                                      pycbc_Bucket *bucket);
  void pycbc_MultiResult_init_context(pycbc_MultiResult *self,
                                      PyObject *curkey,
                                      pycbc_stack_context_handle context,
                                      pycbc_Bucket *bucket);
  pycbc_stack_context_handle pycbc_MultiResult_extract_context(
          pycbc_MultiResult *self, PyObject *hkey, pycbc_Result_t **res);
  #define PYCBC_MULTIRESULT_EXTRACT_CONTEXT(MRES, KEY, RES) \
      pycbc_MultiResult_extract_context(MRES, KEY, RES)
  pycbc_stack_context_handle pycbc_Result_extract_context(
          const pycbc_Result_t *res);
  #define PYCBC_RESULT_EXTRACT_CONTEXT(RESULT) \
      pycbc_Result_extract_context(RESULT)
  
  pycbc_stack_context_handle pycbc_Context_init(
          pycbc_Tracer_t *py_tracer,
          const char *operation,
          lcb_uint64_t now,
          pycbc_stack_context_handle ref_context,
          lcbtrace_REF_TYPE ref_type,
          const char *component);
  
  pycbc_stack_context_handle pycbc_Context_init_debug(
          const char *FILE,
          int LINE,
          const char *FUNC,
          pycbc_Tracer_t *py_tracer,
          const char *operation,
          lcb_uint64_t now,
          pycbc_stack_context_handle ref_context,
          lcbtrace_REF_TYPE ref_type,
          const char *component);
  #define PYCBC_CONTEXT_INIT(                                          \
          py_tracer, operation, now, ref_context, ref_type, component) \
      pycbc_Context_init_debug(__FILE__,                               \
                               __LINE__,                               \
                               __FUNCTION_NAME__,                      \
                               py_tracer,                              \
                               operation,                              \
                               now,                                    \
                               ref_context,                            \
                               ref_type,                               \
                               component)
  
  pycbc_stack_context_handle pycbc_Context_check(
          pycbc_stack_context_handle context,
          const char *file,
          const char *func,
          int line);
  
  #ifdef PYCBC_DEBUG
  #define PYCBC_CHECK_CONTEXT(CONTEXT) \
      pycbc_Context_check(CONTEXT, __FILE__, __FUNCTION_NAME__, __LINE__)
  #else
  #define PYCBC_CHECK_CONTEXT(CONTEXT) \
      pycbc_Context_check(CONTEXT, __FILE__, "N/A", __LINE__)
  #endif
  
  pycbc_stack_context_handle pycbc_Context_deref(
          pycbc_stack_context_handle context,
          int should_be_final,
          int account_for_children,
          pycbc_stack_context_handle from_context);
  pycbc_stack_context_handle pycbc_Context_deref_debug(
          const char *file,
          const char *func,
          int line,
          pycbc_stack_context_handle context,
          int should_be_final,
          int dealloc_children,
          pycbc_stack_context_handle from_context);
  
  #ifdef PYCBC_DEBUG
  #define PYCBC_CONTEXT_DEREF_FROM_CONTEXT(                         \
          CONTEXT, SHOULD_BE_FINAL, DEALLOC_CHILDREN, FROM_CONTEXT) \
      pycbc_Context_deref_debug(__FILE__,                           \
                                __FUNCTION_NAME__,                  \
                                __LINE__,                           \
                                CONTEXT,                            \
                                SHOULD_BE_FINAL,                    \
                                DEALLOC_CHILDREN,                   \
                                FROM_CONTEXT);
  #else
  #define PYCBC_CONTEXT_DEREF_FROM_CONTEXT(                         \
          CONTEXT, SHOULD_BE_FINAL, DEALLOC_CHILDREN, FROM_CONTEXT) \
      pycbc_Context_deref(      CONTEXT,                            \
                                SHOULD_BE_FINAL,                    \
                                DEALLOC_CHILDREN,                   \
                                FROM_CONTEXT);
  
  #endif
  
  #ifdef PYCBC_DEBUG
  #define PYCBC_CONTEXT_DEREF(CONTEXT, SHOULD_BE_FINAL) \
      pycbc_Context_deref_debug(__FILE__,               \
                                __FUNCTION_NAME__,      \
                                __LINE__,               \
                                CONTEXT,                \
                                SHOULD_BE_FINAL,        \
                                1,                      \
                                NULL)
  #else
  #define PYCBC_CONTEXT_DEREF(CONTEXT, SHOULD_BE_FINAL) \
      pycbc_Context_deref(CONTEXT, SHOULD_BE_FINAL, 1, NULL)
  #endif
  
  size_t pycbc_Context_get_ref_count(pycbc_stack_context_handle context);
  size_t pycbc_Context_get_ref_count_debug(const char *FILE,
                                           const char *FUNC,
                                           int line,
                                           pycbc_stack_context_handle context);
  #ifdef PYCBC_DEBUG
  #define PYCBC_CONTEXT_GET_REF_COUNT(CONTEXT) \
      pycbc_Context_get_ref_count_debug(       \
              __FILE__, __FUNCTION_NAME__, __LINE__, CONTEXT)
  #else
  #define PYCBC_CONTEXT_GET_REF_COUNT(CONTEXT) \
      pycbc_Context_get_ref_count(CONTEXT)
  #endif
  
  void pycbc_ref_context(pycbc_stack_context_handle parent_context);
  #define PYCBC_REF_CONTEXT(CONTEXT)                                     \
      PYCBC_DEBUG_LOG_CONTEXT(                                           \
              CONTEXT,                                                   \
              "starting reffing context %p cv %llu",                     \
              CONTEXT,                                                   \
              (long long unsigned)pycbc_Context_get_ref_count(CONTEXT)); \
      pycbc_ref_context(CONTEXT);                                        \
      PYCBC_DEBUG_LOG_CONTEXT(                                           \
              CONTEXT,                                                   \
              "finished reffing context %p to get %llu",                 \
              CONTEXT,                                                   \
              (long long unsigned)pycbc_Context_get_ref_count(CONTEXT));
  
  pycbc_stack_context_handle pycbc_Tracer_start_span(
          pycbc_Tracer_t *py_tracer,
          PyObject *kwargs,
          const char *operation,
          lcb_uint64_t now,
          pycbc_stack_context_handle *context,
          lcbtrace_REF_TYPE ref_type,
          const char *component);
  pycbc_stack_context_handle pycbc_Tracer_start_span_debug(
          const char *FILE,
          int LINE,
          const char *FUNCTION,
          pycbc_Tracer_t *py_tracer,
          PyObject *kwargs,
          const char *operation,
          lcb_uint64_t now,
          pycbc_stack_context_handle *context,
          lcbtrace_REF_TYPE ref_type,
          const char *component);
  
  #ifdef PYCBC_DEBUG
  #define PYCBC_TRACER_START_SPAN(...) \
      pycbc_Tracer_start_span_debug(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
  #else
  #define PYCBC_TRACER_START_SPAN(...) pycbc_Tracer_start_span(__VA_ARGS__)
  #endif
  
  void pycbc_Tracer_propagate(pycbc_Tracer_t *tracer);
  void pycbc_Tracer_set_child(pycbc_Tracer_t *pTracer, lcbtrace_TRACER *pTRACER);
  
  #define PYCBC_TRACE_GET_STACK_CONTEXT_TOPLEVEL(KWARGS, CATEGORY, TRACER, NAME) \
      PYCBC_TRACER_START_SPAN(                                                   \
              TRACER, KWARGS, CATEGORY, 0, NULL, LCBTRACE_REF_NONE, NAME)
  
  #define PYCBC_TRACECMD_PURE(TYPE, CMD, CONTEXT)                          \
      {                                                                    \
          if (PYCBC_CHECK_CONTEXT(CONTEXT)) {                              \
              PYCBC_LOG_KEY(CMD, key)                                      \
              (void)PYCBC_CMD_SET_TRACESPAN(TYPE, (CMD), (CONTEXT)->span); \
          } else {                                                         \
              PYCBC_EXCEPTION_LOG_NOCLEAR;                                 \
          }                                                                \
      }
  
  #define PYCBC_TRACECMD_SCOPED_GENERIC(RV,           \
                                        SCOPE,        \
                                        COMMAND,      \
                                        INSTANCE,     \
                                        CMD,          \
                                        HANDLE,       \
                                        CONTEXT,      \
                                        SPAN_OPERAND, \
                                        OPERAND,      \
                                        ...)          \
      SPAN_OPERAND(SCOPE, INSTANCE, CMD, HANDLE, CONTEXT);\
      RV = OPERAND(SCOPE, INSTANCE, CMD, HANDLE, CONTEXT, COMMAND, __VA_ARGS__);
  
  #    define PYCBC_TRACECMD_SCOPED_NULL(                     \
              RV, SCOPE, INSTANCE, CMD, HANDLE, CONTEXT, ...) \
          PYCBC_TRACECMD_SCOPED_GENERIC(RV,                   \
                                        SCOPE,                \
                                        ,                     \
                                        INSTANCE,             \
                                        CMD,                  \
                                        HANDLE,               \
                                        CONTEXT,              \
                                        GENERIC_SPAN_OPERAND, \
                                        GENERIC_NULL_OPERAND, \
                                        __VA_ARGS__)
  #    define PYCBC_TRACECMD_TYPED(TYPE, CMD, CONTEXT, MRES, CURKEY, BUCKET) \
          PYCBC_TRACECMD_PURE(TYPE, CMD, CONTEXT);                           \
          pycbc_MultiResult_init_context(MRES, CURKEY, CONTEXT, BUCKET);
  
  #    define PYCBC_TRACE_POP_CONTEXT(CONTEXT) PYCBC_CONTEXT_DEREF((CONTEXT), 1);
  
  pycbc_stack_context_handle pycbc_wrap_setup(const char *CATEGORY,
                                              const char *NAME,
                                              pycbc_Tracer_t *TRACER,
                                              const char *STRINGNAME,
                                              PyObject *KWARGS);
  
  void pycbc_wrap_teardown(pycbc_stack_context_handle sub_context,
                           pycbc_Bucket *self,
                           const char *NAME,
                           PyObject **RV);
  
  #    define PYCBC_TRACE_WRAP_TOPLEVEL_WITHNAME(                        \
              RV, CATEGORY, NAME, TRACER, STRINGNAME, ...)               \
          {                                                              \
              pycbc_stack_context_handle sub_context = pycbc_wrap_setup( \
                      CATEGORY, #NAME, TRACER, STRINGNAME, kwargs);      \
              RV = NAME(__VA_ARGS__, sub_context);                       \
              pycbc_wrap_teardown(sub_context, self, #NAME, &RV);        \
          }
  
  typedef struct pycbc_common_vars pycbc_common_vars_t;
  int pycbc_wrap_and_pop(pycbc_stack_context_handle *contextptr,
                         int noterv,
                         int result,
                         pycbc_common_vars_t *cv);
  pycbc_stack_context_handle pycbc_logging_monad(const char *FILE,
                          int LINE,
                          const char *FUNC,
                          const char *NAME,
                          pycbc_stack_context_handle context);
  
  int pycbc_wrap_and_pop_debug(const char *FILE,
                               int LINE,
                               const char *FUNC,
                               const char *NAME,
                               pycbc_stack_context_handle *contextptr,
                               int noterv,
                               int result,
                               pycbc_common_vars_t *cv);
  
  #define PYCBC_WRAP_AND_POP(CONTEXTPTR, RESULT, NAME, NOTERV, CV) \
      pycbc_wrap_and_pop_debug(__FILE__,                           \
                               __LINE__,                           \
                               __FUNCTION__,                       \
                               NAME,                               \
                               CONTEXTPTR,                         \
                               NOTERV,                             \
                               (RESULT),                           \
                               CV)
  
  pycbc_stack_context_handle pycbc_explicit_named_setup(
          const char *FILE,
          int LINE,
          const char *FUNCTION,
          pycbc_stack_context_handle *CONTEXTPTR,
          const char *COMPONENTNAME,
          const char *CATEGORY,
          PyObject *KWARGS,
          pycbc_Tracer_t *self);
  
  #define PYCBC_EXPLICIT_NAMED_SETUP(                        \
          CONTEXTPTR, COMPONENTNAME, CATEGORY, KWARGS, SELF) \
      pycbc_explicit_named_setup(__FILE__,                   \
                                 __LINE__,                   \
                                 __FUNCTION__,               \
                                 CONTEXTPTR,                 \
                                 COMPONENTNAME,              \
                                 CATEGORY,                   \
                                 KWARGS,                     \
                                 SELF)
  
  #define PYCBC_TRACE_WRAP_EXPLICIT_NAMED(CONTEXTPTR,                      \
                                          NAME,                            \
                                          COMPONENTNAME,                   \
                                          CATEGORY,                        \
                                          KWARGS,                          \
                                          NOTERV,                          \
                                          CV,                              \
                                          SELF,                            \
                                          ...)                             \
      PYCBC_WRAP_AND_POP(CONTEXTPTR,                                       \
                         NAME(__VA_ARGS__,                                 \
                              PYCBC_EXPLICIT_NAMED_SETUP(CONTEXTPTR,       \
                                                         COMPONENTNAME,    \
                                                         CATEGORY,         \
                                                         KWARGS,           \
                                                         (SELF)->tracer)), \
                         COMPONENTNAME,                                    \
                         NOTERV,                                           \
                         CV)
  
  #define PYCBC_TRACE_WRAP_EXPLICIT_NAMED_VOID(                             \
          CONTEXTPTR, NAME, COMPONENTNAME, CATEGORY, KWARGS, CV, SELF, ...) \
      {                                                                     \
          NAME(__VA_ARGS__,                                                 \
               PYCBC_EXPLICIT_NAMED_SETUP(CONTEXTPTR,                       \
                                          COMPONENTNAME,                    \
                                          CATEGORY,                         \
                                          KWARGS,                           \
                                          SELF->tracer));                   \
          (void)PYCBC_WRAP_AND_POP(CONTEXTPTR, 0, COMPONENTNAME, 0, CV);    \
      }
  
  #define PYCBC_TRACE_WRAP_NOTERV(NAME, KWARGS, NOTERV, CV, CONTEXT, SELF, ...) \
      PYCBC_TRACE_WRAP_EXPLICIT_NAMED(CONTEXT,                                  \
                                      NAME,                                     \
                                      #NAME,                                    \
                                      NAME##_category(),                        \
                                      KWARGS,                                   \
                                      NOTERV,                                   \
                                      CV,                                       \
                                      SELF,                                     \
                                      __VA_ARGS__)
  
  #define PYCBC_TRACE_WRAP(NAME, KWARGS, ...) \
      PYCBC_TRACE_WRAP_NOTERV(NAME, KWARGS, 0, NULL, &context, self, __VA_ARGS__)
  
  #define PYCBC_TRACE_WRAP_VOID(NAME, KWARGS, CONTEXT, SELF, ...) \
      PYCBC_TRACE_WRAP_EXPLICIT_NAMED_VOID(CONTEXT,               \
                                           NAME,                  \
                                           #NAME,                 \
                                           NAME##_category(),     \
                                           KWARGS,                \
                                           NULL,                  \
                                           SELF,                  \
                                           __VA_ARGS__)
  
  #define PYCBC_TRACE_WRAP_TOPLEVEL(RV, CATEGORY, NAME, TRACER, ...) \
      PYCBC_TRACE_WRAP_TOPLEVEL_WITHNAME(                            \
              RV, CATEGORY, NAME, TRACER, #NAME, __VA_ARGS__)
  
  
  
  #define TRACED_FUNCTION(CATEGORY,QUALIFIERS,RTYPE,NAME,...)\
      const char* NAME##_category(void){ return CATEGORY; }\
      QUALIFIERS RTYPE NAME(__VA_ARGS__, pycbc_stack_context_handle context)
  
  #define TRACED_FUNCTION_DECL(QUALIFIERS,RTYPE,NAME,...)\
      const char* NAME##_category(void);\
      QUALIFIERS RTYPE NAME(__VA_ARGS__, pycbc_stack_context_handle context);
  
  #define TRACED_FUNCTION_WRAPPER(name, CATEGORY, CLASS)                    \
      PyObject *pycbc_##CLASS##_##name##_real(                              \
              pycbc_##CLASS *self,                                          \
              PyObject *args,                                               \
              PyObject *kwargs,                                             \
              pycbc_stack_context_handle context);                          \
      PyObject *pycbc_##CLASS##_##name(                                     \
              pycbc_##CLASS *self, PyObject *args, PyObject *kwargs)        \
      {                                                                     \
          PyObject *result;                                                 \
          PYCBC_TRACE_WRAP_TOPLEVEL_WITHNAME(result,                        \
                                             CATEGORY,                      \
                                             pycbc_##CLASS##_##name##_real, \
                                             self->tracer,                  \
                                             #CLASS "." #name,              \
                                             self,                          \
                                             args,                          \
                                             kwargs);                       \
          return result;                                                    \
      }                                                                     \
      PyObject *pycbc_##CLASS##_##name##_real(                              \
              pycbc_##CLASS *self,                                          \
              PyObject *args,                                               \
              PyObject *kwargs,                                             \
              pycbc_stack_context_handle context)
  
  /*****************
   * Result Objects.
   *****************
   *
   * These objects are returned to indicate the status/value of operations.
   * The following defines a 'base' class and several 'subclasses'.
   *
   * See result.c and opresult.c
   */
  
  #define TRACING_DATA                            \
      pycbc_stack_context_handle tracing_context; \
      char is_tracing_stub;                       \
      PyObject *tracing_output;
  
  #define pycbc_Result_HEAD \
      PyObject_HEAD \
      lcb_STATUS rc; \
      PyObject *key; \
      TRACING_DATA
  
  #define pycbc_OpResult_HEAD \
      pycbc_Result_HEAD \
      lcb_uint64_t cas; \
      PyObject *mutinfo;
  
  typedef struct pycbc_Result {
      pycbc_Result_HEAD
  } pycbc_Result;
  
  typedef struct {
      pycbc_OpResult_HEAD
  } pycbc_OperationResult;
  
  
  #define pycbc_ValResult_HEAD \
      pycbc_OpResult_HEAD \
      PyObject *value; \
      lcb_uint32_t flags;
  
  typedef struct {
      pycbc_ValResult_HEAD
  } pycbc_ValueResult;
  
  /**
   * Item or 'Document' object
   */
  typedef struct {
      pycbc_ValResult_HEAD
      PyObject* vdict;
  } pycbc_Item;
  
  typedef struct {
      pycbc_OpResult_HEAD
      /* List of results. (value,errcode) */
      PyObject *results;
  
      /* Original list of specs passed. We can cache this later on if access
       * by element is required. */
      PyObject *specs;
  } pycbc__SDResult;
  
  enum {
      PYCBC_HTTP_HVIEW = 1,
      PYCBC_HTTP_HRAW,
      PYCBC_HTTP_HQUERY,
      PYCBC_HTTP_HANALYTICS,
      PYCBC_HTTP_HSEARCH,
      PYCBC_HTTP_HNONE
  };
  
  enum {
      /** 'quiet' boolean set */
      PYCBC_MRES_F_QUIET      = 1 << 0,
  
      /** We're using a user-created Item; Don't create our own results */
      PYCBC_MRES_F_ITEMS      = 1 << 1,
  
      /** Items are already allocated and present within the dictionary. */
      PYCBC_MRES_F_UALLOCED   = 1 << 2,
  
      /** For GET (and possibly others), force FMT_BYTES */
      PYCBC_MRES_F_FORCEBYTES = 1 << 3,
  
      /** The commands have durability requirements */
      PYCBC_MRES_F_DURABILITY = 1 << 4,
  
      /** The command is an async subclass. Do we need this? */
      PYCBC_MRES_F_ASYNC = 1 << 5,
  
      /** This result is from a call to one of the single-item APIs */
      PYCBC_MRES_F_SINGLE = 1 << 6,
  
      /* Hint to dispatch to the view callback functions */
      PYCBC_MRES_F_VIEWS = 1 << 7,
  
      /** Hint that the operation will make multiple callbacks on a single key */
      PYCBC_MRES_F_MULTI = 1 << 8
  };
  /**
   * Contextual info for enhanced error logging
   */
  typedef struct {
      const char *FILE;
      const char *FUNC;
      int LINE;
  } pycbc_debug_info;
  
  int pycbc_debug_info_is_valid(pycbc_debug_info *info);
  
  typedef PyObject pycbc_enhanced_err_info;
  
  /**
   * Object containing the result of a 'Multi' operation. It's the same as a
   * normal dict, except we add an 'all_ok' field, so a user doesn't need to
   * skim through all the pairs to determine if something failed.
   *
   * See multiresult.c
   */
  struct pycbc_MultiResult_st {
      PYCBC_MULTIRESULT_BASE;
  
      /** parent Connection object */
      pycbc_Bucket *parent;
  
      /**
       * A list of fatal exceptions, i.e. ones not resulting from a bad
       * LCB error code
       */
      PyObject *exceptions;
  
      /** A failed LCB operation, if any */
      PyObject *errop;
  
      pycbc_dur_params dur;
  
      /** Quick-check value to see if everything went well */
      int all_ok;
  
      /** Options for 'MultiResult' */
      int mropts;
  
      pycbc_enhanced_err_info *err_info;
  };
  
  typedef struct {
      pycbc_MultiResult base;
  
      /* How many operations do we have remaining */
      unsigned int nops;
  
      /* Object for the callback */
      PyObject *callback;
  
      /* Object to be invoked with errors */
      PyObject *errback;
  } pycbc_AsyncResult;
  
  
  /**
   * This structure is passed to our exception throwing function, it's
   * usually wrapped by one of the macros below
   */
  struct pycbc_exception_params {
      /** C Source file at which the error was thrown (populated by macro */
      const char *file;
  
      /** C Source line, as above */
      int line;
  
      /** LCB Error code, if any */
      lcb_STATUS err;
  
      /** Error message, if any */
      const char *msg;
  
      /** Key at which the error occurred. Not always present */
      PyObject *key;
  
      /** Single result which triggered the error, if present */
      PyObject *result;
  
      /**
       * A MultiResult object. This contains other operations which may
       * or may not have failed. This allows a user to check the status
       * of multi operations in which one of the keys resulted in an
       * exception
       */
      PyObject *all_results;
  
      /**
       * Extra info which caused the error. This is usually some kind of
       * bad parameter.
       */
      PyObject *objextra;
  
      /**
       * Enhanced error info if required.
       */
      pycbc_enhanced_err_info *err_info;
  };
  
  /**
   * Initializes a pycbc_exception_params to contain the proper
   * source context info
   */
  #define PYCBC_EXC_STATIC_INIT { __FILE__, __LINE__ }
  
  /**
   * Argument object, used for passing more information to the
   * multi functions. This isn't documented API yest.
   */
  typedef struct {
      PyDictObject dict;
      int dummy; /* avoid sizing issues */
  } pycbc_ArgumentObject;
  
  
  /**
   * Object used as the 'value' for observe responses
   */
  typedef struct {
      PyObject_HEAD
      unsigned int flags;
      int from_master;
      unsigned PY_LONG_LONG cas;
  } pycbc_ObserveInfo;
  
  /**
   * Flags to use for each type to indicate which subfields are relevant to
   * print out.
   */
  enum {
      PYCBC_RESFLD_RC     = 1 << 0,
      PYCBC_RESFLD_CAS    = 1 << 1,
      PYCBC_RESFLD_KEY    = 1 << 2,
      PYCBC_RESFLD_FLAGS  = 1 << 3,
      PYCBC_RESFLD_HTCODE = 1 << 4,
      PYCBC_RESFLD_VALUE  = 1 << 5,
      PYCBC_RESFLD_URL    = 1 << 6
  };
  
  #define PYCBC_RESULT_BASEFLDS (PYCBC_RESFLD_RC)
  #define PYCBC_OPRESULT_BASEFLDS \
      (PYCBC_RESULT_BASEFLDS| \
              PYCBC_RESFLD_CAS| \
              PYCBC_RESFLD_KEY)
  
  #define PYCBC_VALRESULT_BASEFLDS (PYCBC_OPRESULT_BASEFLDS| \
          PYCBC_RESFLD_VALUE| \
          PYCBC_RESFLD_FLAGS)
  
  #define PYCBC_HTRESULT_BASEFLDS \
      (       PYCBC_RESULT_BASEFLDS   | \
              PYCBC_RESFLD_HTCODE     | \
              PYCBC_RESFLD_URL        | \
              PYCBC_RESFLD_VALUE)
  
  #define PYCBC_RESPROPS_NAME "_fldprops"
  /**
   * Wrapper around PyType_Ready which also injects the common flags properties
   */
  int pycbc_ResultType_ready(PyTypeObject *p, int flags);
  
  /**
   * Types used for tracing
   */
  #define PYCBC_TRACING_TYPES(X)\
      X(Tracer, "The Tracer Object")
  
  #define PYCBC_CRYPTO_TYPES(X)                         \
      X(CryptoProvider,                                 \
        "A Cryptography Provider for Field Encryption", \
        pycbc_CryptoProvideType_extra_init(ptr))        \
      X(NamedCryptoProvider, "A Named Cryptography Provider for Field Encryption")
  
  #define PYCBC_COLLECTION_TYPES(X) \
      X(Collection,                 \
        "A Couchbase Collection",   \
        pycbc_CryptoProvideType_extra_init(ptr))
  #define PYCBC_AUTODEF_TYPES(X) \
      PYCBC_CRYPTO_TYPES(X)      \
      PYCBC_TRACING_TYPES(X)     \
      PYCBC_COLLECTION_TYPES(X)
  
  /**
   * Extern PyTypeObject declaraions.
   */
  
  /* multiresult.c */
  extern PyTypeObject pycbc_MultiResultType;
  extern PyTypeObject pycbc_AsyncResultType;
  
  /* result.c */
  extern PyTypeObject pycbc_ResultType;
  
  /* opresult.c */
  extern PyTypeObject pycbc_OperationResultType;
  extern PyTypeObject pycbc_ValueResultType;
  extern PyTypeObject pycbc_HttpResultType;
  extern PyTypeObject pycbc_ItemType;
  extern PyTypeObject pycbc__SDResultType;
  
  /* views.c */
  extern PyTypeObject pycbc_ViewResultType;
  
  /* ext.c */
  #define PYCBC_EXTERN(X, DOC, ...) extern PyTypeObject pycbc_##X##Type;
  
  PYCBC_AUTODEF_TYPES(PYCBC_EXTERN);
  #undef PYCBC_EXTERN
  /**
   * Result type check macros
   */
  #define PYCBC_VALRES_CHECK(o) \
          PyObject_IsInstance(o, &pycbc_ValueResultType)
  
  #define PYCBC_OPRES_CHECK(o) \
      PyObject_IsInstance(o, (PyObject*)&pycbc_OperationResultType)
  
  extern PyTypeObject pycbc_ArgumentType;
  
  /**
   * XXX: This isn't used.
   */
  extern PyObject *pycbc_ExceptionType;
  
  /**
   * X-macro to define the helpers we pass from _bootstrap.py along to
   * the module's '_init_helpers' function. We use an xmacro here because
   * the parameters may change and the argument handling is rather complex.
   * See below (in the pycbc_helpers structure) and in ext.c for more usages.
   */
  #define PYCBC_XHELPERS(X) \
      X(result_reprfunc) \
      X(fmt_utf8_flags) \
      X(fmt_bytes_flags) \
      X(fmt_json_flags) \
      X(fmt_pickle_flags) \
      X(pickle_encode) \
      X(pickle_decode) \
      X(json_encode) \
      X(json_decode) \
      X(lcb_errno_map) \
      X(misc_errno_map) \
      X(default_exception) \
      X(obsinfo_reprfunc) \
      X(itmcoll_base_type) \
      X(itmopts_dict_type) \
      X(itmopts_seq_type) \
      X(fmt_auto) \
      X(view_path_helper) \
      X(sd_result_type) \
      X(sd_multival_type)
  
  #define PYCBC_XHELPERS_STRS(X) \
      X(tcname_encode_key, PYCBC_TCNAME_ENCODE_KEY) \
      X(tcname_encode_value, PYCBC_TCNAME_ENCODE_VALUE) \
      X(tcname_decode_key, PYCBC_TCNAME_DECODE_KEY) \
      X(tcname_decode_value, PYCBC_TCNAME_DECODE_VALUE) \
      X(ioname_modevent, "update_event") \
      X(ioname_modtimer, "update_timer") \
      X(ioname_startwatch, "start_watching") \
      X(ioname_stopwatch, "stop_watching") \
      X(ioname_mkevent, "io_event_factory") \
      X(ioname_mktimer, "timer_event_factory") \
      X(vkey_id,        "id") \
      X(vkey_key,       "key") \
      X(vkey_value,     "value") \
      X(vkey_geo,       "geometry") \
      X(vkey_docresp,   "__DOCRESULT__")
  
  /**
   * Definition of global helpers. This is only instantiated once as
   * pycbc_helpers.
   */
  struct pycbc_helpers_ST {
      #define X(n) PyObject *n;
      PYCBC_XHELPERS(X)
      #undef X
  
      #define X(n, s) PyObject *n;
      PYCBC_XHELPERS_STRS(X)
      #undef X
  };
  
  /**
   * We use this one a lot. This is defined in ext.c
   */
  extern struct pycbc_helpers_ST pycbc_helpers;
  
  /**
   * Threading macros
   */
  #define PYCBC_USE_THREADS
  
  #ifdef PYCBC_USE_THREADS
  #define PYCBC_CONN_THR_BEGIN(conn) \
      if ((conn)->unlock_gil) { \
          pycbc_assert((conn)->thrstate == NULL); \
          (conn)->thrstate = PyEval_SaveThread(); \
      }
  
  #define PYCBC_CONN_THR_END(conn) \
      if ((conn)->unlock_gil) { \
          pycbc_assert((conn)->thrstate); \
          PyEval_RestoreThread((conn)->thrstate); \
          (conn)->thrstate = NULL; \
      }
  
  #else
  #define PYCBC_CONN_THR_BEGIN(X)
  #define PYCBC_CONN_THR_END(X)
  #endif
  
  /*******************************
   * Type Initialization Functions
   *******************************
   *
   * These functions are called once from the extension's import method.
   * See ext.c
   *
   * They basically initialize the corresponding Python type so that
   * we can use them further on.
   */
  
  /** Initializes the constants, constants. */
  void pycbc_init_pyconstants(PyObject *module);
  PyObject *pycbc_lcb_errstr(lcb_t instance, lcb_STATUS err);
  PyObject *pycbc_print_constants(PyObject *mod, PyObject *args);
  
  int pycbc_ResultType_init(PyObject **ptr);
  int pycbc_BucketType_init(PyObject **ptr);
  int pycbc_MultiResultType_init(PyObject **ptr);
  int pycbc_ValueResultType_init(PyObject **ptr);
  int pycbc_OperationResultType_init(PyObject **ptr);
  int pycbc_SDResultType_init(PyObject **ptr);
  int pycbc_HttpResultType_init(PyObject **ptr);
  int pycbc_TranscoderType_init(PyObject **ptr);
  int pycbc_ObserveInfoType_init(PyObject **ptr);
  int pycbc_ItemType_init(PyObject **ptr);
  int pycbc_EventType_init(PyObject **ptr);
  int pycbc_TimerEventType_init(PyObject **ptr);
  int pycbc_IOEventType_init(PyObject **ptr);
  int pycbc_AsyncResultType_init(PyObject **ptr);
  int pycbc_IOPSWrapperType_init(PyObject **ptr);
  int pycbc_ViewResultType_init(PyObject **ptr);
  int pycbc_CollectionType_init(PyObject **ptr);
  
  #define PYCBC_TYPE_INIT_DECL(TYPENAME, TYPE_DOC, ...) \
      int pycbc_##TYPENAME##Type_init(PyObject **ptr);
  
  PYCBC_AUTODEF_TYPES(PYCBC_TYPE_INIT_DECL)
  
  #undef PYCBC_TYPE_INIT_DECL
  /**
   * Calls the type's constructor with no arguments:
   */
  
  #define PYCBC_TYPE_CTOR_1_args(t)               PyObject_CallFunction((PyObject*)t, 0)
  #define PYCBC_TYPE_CTOR_2_args(t, args)         PyObject_CallFunction((PyObject*)t, "O", args)
  #define PYCBC_TYPE_CTOR_3_args(t, args, kwargs) PyObject_CallFunction((PyObject*)t, "OO", args, kwargs)
  
  #define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
  #define PYCBC_TYPE_CTOR_CHOOSER(...) \
      GET_4TH_ARG(__VA_ARGS__, PYCBC_TYPE_CTOR_3_args, \
                  PYCBC_TYPE_CTOR_2_args, PYCBC_TYPE_CTOR_1_args, )
  
  #define PYCBC_TYPE_CTOR(...) PYCBC_TYPE_CTOR_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
  
  /**
   * Allocators for result functions. See callbacks.c:get_common
   */
  PyObject *pycbc_result_new(pycbc_Bucket *parent);
  PyObject *pycbc_multiresult_new(pycbc_Bucket *parent);
  pycbc_ValueResult *pycbc_valresult_new(pycbc_Bucket *parent);
  pycbc_OperationResult *pycbc_opresult_new(pycbc_Bucket *parent);
  pycbc_Item *pycbc_item_new(pycbc_Bucket *parent);
  pycbc__SDResult *pycbc_sdresult_new(pycbc_Bucket *parent, PyObject *specs);
  
  /* Add a result to a list of multi results. Specify the index */
  void pycbc_sdresult_addresult(pycbc__SDResult *obj, size_t ii, PyObject *item);
  
  /**
   * Simple function, here because it's defined in result.c but needed in
   * opresult.c
   */
  void pycbc_Result_dealloc(pycbc_Result *self);
  
  /**
   * Traps the current exception and adds it to the current MultiResult
   * context.
   * @param mres The MultiResult object.
   *
   * This calls pycbc_exc_mktuple(), so the constrains there apply to this
   * function as well.
   */
  void pycbc_multiresult_adderr(pycbc_MultiResult* mres);
  
  /**
   * Raise an exception from a multi result. This will raise an exception if:
   * 1) There is a 'fatal' error in the 'exceptions' list
   * 2) There is an 'operr'. 'operr' can be a failed LCB code (if no_raise_enoent
   * is on, this is not present if the failed code was LCB_ERR_DOCUMENT_NOT_FOUND)
   */
  int pycbc_multiresult_maybe_raise(pycbc_MultiResult *self);
  
  /**
   * Return the effective user-facing value from this MultiResult object.
   * This should only be called if 'maybe_raise' returns false.
   * @param self the object
   * @return a new reference to the final result, or NULL on error.
   */
  PyObject* pycbc_multiresult_get_result(pycbc_MultiResult *self);
  
  /**
   * Invokes a callback when an operation has been completed. This will either
   * invoke the operation's "error callback" or the operation's "result callback"
   * depending on the state.
   */
  void pycbc_asyncresult_invoke(pycbc_AsyncResult *mres,
                                pycbc_enhanced_err_info *err_info);
  
  /**
   * Initialize the callbacks for the lcb_t
   */
  void pycbc_callbacks_init(lcb_t instance);
  void pycbc_http_callbacks_init(lcb_t instance);
  void pycbc_views_callbacks_init(lcb_t instance);
  
  /**
   * "Real" exception handler.
   * @param mode one of the PYCBC_EXC_* constants
   * @param p a struct of exception parameters
   */
  void pycbc_exc_wrap_REAL(int mode, struct pycbc_exception_params *p);
  
  /**
   * Get the appropriate Couchbase exception object.
   * @param mode one of the PYCBC_EXC_* constants
   * @param err the libcouchbase error, if any
   * @return a borrowed reference to the appropriate exception class
   */
  PyObject* pycbc_exc_map(int mode, lcb_STATUS err);
  
  /**
   * Creates a simple exception with a given message. The exception
   * is not thrown.
   */
  PyObject* pycbc_exc_message(int mode, lcb_STATUS err, const char *msg);
  
  /**
   * Gets the error classifier categories (as a set of bit flags) for a given
   * error code.
   */
  PyObject* pycbc_exc_get_categories(PyObject *self, PyObject *arg);
  /**
   * Throws an exception. If an exception is pending, it is caught and wrapped,
   * delivered into the CouchbaseException's 'inner_cause' field
   *
   * @param e_mode one of the PYCBC_EXC_* constants
   * @param e_err the LCB error code (use 0 if none)
   * @param e_msg a string message, if any
   * @param e_key the key during the handling of which the error occurred
   * @param e_objextra the problematic object which actually caused the errror
   */
  #define PYCBC_EXC_WRAP_EX_FILE_LINE(e_mode, e_err, e_msg, e_key, e_objextra, e_err_info, e_file, e_line) \
      {                                                                          \
          PYCBC_DEBUG_LOG("Raising exception at %s, %d", e_file, e_line)     \
          struct pycbc_exception_params __pycbc_ep = {0};                        \
          __pycbc_ep.file = e_file;                                              \
          __pycbc_ep.line = e_line;                                              \
          __pycbc_ep.err = e_err;                                                \
          __pycbc_ep.msg = e_msg;                                                \
          __pycbc_ep.key = e_key;                                                \
          __pycbc_ep.objextra = e_objextra;                                      \
          __pycbc_ep.err_info = e_err_info;                                      \
          Py_XINCREF(e_err_info);                                                \
          pycbc_exc_wrap_REAL(e_mode, &__pycbc_ep);                              \
      }
  
  #define PYCBC_EXC_WRAP_EX(e_mode, e_err, e_msg, e_key, e_objextra, e_err_info) \
      PYCBC_EXC_WRAP_EX_FILE_LINE(e_mode, e_err, e_msg, e_key, e_objextra, e_err_info, __FILE__, __LINE__)
  
  #define PYCBC_EXC_WRAP(mode, err, msg) \
      PYCBC_EXC_WRAP_EX(mode, err, msg, NULL, NULL, NULL)
  
  #define PYCBC_EXC_WRAP_OBJ(mode, err, msg, obj) \
      PYCBC_EXC_WRAP_EX(mode, err, msg, NULL, obj, NULL)
  
  #define PYCBC_EXC_WRAP_KEY(mode, err, msg, key) \
      PYCBC_EXC_WRAP_EX(mode, err, msg, key, NULL, NULL)
  
  #define PYCBC_EXC_WRAP_KEY_ERR_INFO(mode, err, msg, key, err_info) \
      PYCBC_EXC_WRAP_EX(mode, err, msg, key, NULL, err_info)
  
  #define PYCBC_EXC_WRAP_VALUE PYCBC_EXC_WRAP_KEY
  
  int pycbc_handle_assert(const char *msg, const char* file, int line);
  
  /**
   * Creates a tuple of (class, object, traceback), similar to what would be
   * returned from sys.exc_info()
   * @return The error tuple.
   *
   * Calling this function will also clear the error
   * state. This must be called only if PyErr_Occurred() is true.
   */
  PyObject *pycbc_exc_mktuple(void);
  
  /**
   * This macro can be used as an 'if' structure. It returns false if the
   * condition fails and try otherwise
   */
  #define pycbc_assert(e) ((e) ? 1 : pycbc_handle_assert(#e, __FILE__, __LINE__))
  
  /**
   * EXCTHROW macros. These provide error messages for common stages.
   */
  #define PYCBC_EXCTHROW_WAIT(err) PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, err, \
         "There was a problem while trying to send/receive " \
         "your request over the network. This may be a result of a " \
         "bad network or a misconfigured client or server")
  
  #define PYCBC_EXCTHROW_SCHED(err) PYCBC_EXC_WRAP(PYCBC_EXC_LCBERR, err, \
          "There was a problem scheduling your request, or determining " \
          "the appropriate server or vBucket for the key(s) requested. "\
          "This may also be a bug in the SDK if there are no network issues")
  
  #define PYCBC_EXCTHROW_ARGS() PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, \
                                             "Bad/insufficient arguments provided")
  
  #define PYCBC_EXCTHROW_EMPTYKEY() PYCBC_EXC_WRAP(PYCBC_EXC_ARGUMENTS, 0, \
          "Empty key (i.e. '', empty string) passed")
  
  /**
   * Encodes a key into a buffer.
   * @param conn the connection object
   * @param key. in-out. Input should be the Python key. Output should be the
   * new python object which contains the underlying buffer for the key.
   * @param buf a pointer to a buffer pointer
   * @param nbuf pointer to the length of the buffer
   *
   * The buf parameter will likely be tied to the key parameter, so be sure not
   * to decrement its refcount until buf is no longer needed
   *
   * @return
   * 0 on success, nonzero on error
   */
  int pycbc_tc_encode_key(pycbc_Bucket *conn, PyObject *src, pycbc_pybuffer *dst);
  
  /**
   * Decodes a key buffer into a python object.
   * @param conn the connection object
   * @param key the key buffer
   * @param nkey the size of the key
   * @param pobj a pointer to a PyObject*, will be set with a newly-created python
   * object which represents the converted key
   *
   * @return
   * 0 on success, nonzero on error
   */
  int pycbc_tc_decode_key(pycbc_Bucket *conn, const void *key, size_t nkey,
                          PyObject **pobj);
  
  /**
   * Encode a value with flags
   * @param value. in-out. Input should be the Python value, Output should be the
   * new python object which contains the converted value.
   * @param flag_v. Python object representing 'flags'. This is used for efficiency
   * in order to pass a pythonized version of the flags
   * @param buf a pointer to a buffer, likely tied to 'buf'
   * @param nbuf pointer to buffer length
   * @param flags pointer to a flags variable, will be set with the appropriate
   * flags
   */
  int pycbc_tc_encode_value(pycbc_Bucket *conn, PyObject *srcbuf, PyObject *flag_v,
                            pycbc_pybuffer *dstbuf, lcb_U32 *dstflags);
  
  /**
   * Decode a value with flags
   * @param conn the connection object
   * @param value as received from the server
   * @param nvalue length of value
   * @param flags flags as received from the server
   * @param pobj the pythonized value
   */
  int pycbc_tc_decode_value(pycbc_Bucket *conn, const void *value, size_t nvalue,
                            lcb_U32 flags, PyObject **pobj);
  
  /**
   * Like encode_value, but only uses built-in encoders
   */
  int pycbc_tc_simple_encode(PyObject *src, pycbc_pybuffer *dst, lcb_U32 flags);
  
  /**
   * Like decode_value, but only uses built-in decoders
   */
  int pycbc_tc_simple_decode(PyObject **vp, const char *buf, size_t nbuf,
                             lcb_U32 flags);
  
  /**
   * Automatically determine the format for the object.
   */
  PyObject *
  pycbc_tc_determine_format(PyObject *value);
  
  PyObject *
  pycbc_iowrap_new(pycbc_Bucket *conn, PyObject *pyio);
  
  lcb_io_opt_t
  pycbc_iowrap_getiops(PyObject *iowrap);
  
  /**
   * Event callback handling
   */
  void pycbc_invoke_connected_event(pycbc_Bucket *conn, lcb_STATUS err);
  
  /**
   * Schedule the dtor event
   */
  void pycbc_schedule_dtor_event(pycbc_Bucket *self);
  
  /**
   * Pipeline handlers
   */
  PyObject* pycbc_Bucket__start_pipeline(pycbc_Bucket *);
  PyObject* pycbc_Bucket__end_pipeline(pycbc_Bucket *);
  
  /**
   * Control methods
   */
  PyObject* pycbc_Bucket__cntl(pycbc_Bucket *, PyObject *, PyObject *);
  PyObject* pycbc_Bucket__vbmap(pycbc_Bucket *, PyObject *);
  PyObject* pycbc_Bucket__cntlstr(pycbc_Bucket *conn, PyObject *args, PyObject *kw);
  
  /**
   * Health-check methods
   */
  PyObject *pycbc_Bucket__ping(pycbc_Bucket *self,
                               PyObject *args,
                               PyObject *kwargs);
  
  PyObject *pycbc_Bucket__diagnostics(pycbc_Bucket *self,
                                      PyObject *args,
                                      PyObject *kwargs);
  /**
   * Encryption Provider
   */
  typedef struct {
      PyObject_HEAD lcbcrypto_PROVIDER *lcb_provider;
  } pycbc_CryptoProvider;
  
  typedef struct {
      PyObject_HEAD pycbc_CryptoProvider *orig_py_provider;
      lcbcrypto_PROVIDER *lcb_provider;
      PyObject *name;
  } pycbc_NamedCryptoProvider;
  
  #define PP_FOR_EACH_CRYPTO_EXCEPTION(X, ...)                               \
      X(PYCBC_CRYPTO_PROVIDER_NOT_FOUND, = LCB_MAX_ERROR),                   \
              X(PYCBC_CRYPTO_PROVIDER_ALIAS_NULL),                           \
              X(PYCBC_CRYPTO_PROVIDER_MISSING_PUBLIC_KEY),                   \
              X(PYCBC_CRYPTO_PROVIDER_MISSING_SIGNING_KEY),                  \
              X(PYCBC_CRYPTO_PROVIDER_MISSING_PRIVATE_KEY),                  \
              X(PYCBC_CRYPTO_PROVIDER_SIGNING_FAILED),                       \
              X(PYCBC_CRYPTO_PROVIDER_ENCRYPT_FAILED),                       \
              X(PYCBC_CRYPTO_PROVIDER_DECRYPT_FAILED),                       \
              X(PYCBC_CRYPTO_PROVIDER_KEY_SIZE_EXCEPTION),                   \
              X(PYCBC_CRYPTO_CONFIG_ERROR), X(PYCBC_CRYPTO_EXECUTION_ERROR), \
              X(PYCBC_CRYPTO_ERROR)
  
  typedef enum {
  #define PYCBC_CRYPTO_X(NAME, ...) NAME __VA_ARGS__
  #define COMMA ,
      PP_FOR_EACH_CRYPTO_EXCEPTION(PYCBC_CRYPTO_X),
      PYCBC_CRYPTO_PROVIDER_ERROR_MAX
  #undef COMMA
  #undef PYCBC_CRYPTO_X
  } pycbc_crypto_err;
  
  PyObject *pycbc_gen_crypto_exception_map(void);
  
  /**
   * Flag to check if logging is enabled for the library via Python's logging
   */
  extern PyObject* pycbc_log_handler;
  extern lcb_LOGGER *pycbc_lcb_logger;
  
  /**
   * Dummy tuple/keywords, used for PyArg_ParseTupleAndKeywordArgs, which dies
   * if one of the arguments is NULL, so these contain empty tuples and dicts,
   * respectively.
   */
  extern PyObject *pycbc_DummyTuple;
  extern PyObject *pycbc_DummyKeywords;
  
  #endif /* PYCBC_H_ */
  