text: /**
   *     Copyright 2019 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 COUCHBASE_PYTHON_CLIENT_LCB_V4_WRAPPER_H
  #define COUCHBASE_PYTHON_CLIENT_LCB_V4_WRAPPER_H
  #include <libcouchbase/couchbase.h>
  #include <libcouchbase/utils.h>
  #include <libcouchbase/crypto.h>
  #ifdef PYCBC_BACKPORT_CRYPTO
  #    include <libcouchbase/../../../libcouchbase_src-prefix/src/libcouchbase_src/src/internalstructs.h>
  #endif
  #define PYCBC_ENDURE 0
  #define PYCBC_V4
  #include "python_wrappers.h"
  
  typedef lcb_DURABILITY_LEVEL pycbc_DURABILITY_LEVEL;
  
  typedef lcb_INSTANCE *lcb_t;
  
  typedef lcb_VIEW_HANDLE *pycbc_VIEW_HANDLE;
  typedef lcb_HTTP_HANDLE *pycbc_HTTP_HANDLE;
  typedef lcb_SEARCH_HANDLE *pycbc_SEARCH_HANDLE;
  typedef lcb_QUERY_HANDLE *pycbc_QUERY_HANDLE;
  typedef lcb_ANALYTICS_HANDLE *pycbc_ANALYTICS_HANDLE;
  
  /** Set this flag to execute an actual get with each response */
  #    define LCB_CMDVIEWQUERY_F_INCLUDE_DOCS (1 << 16)
  
  /**This view is spatial. Modifies how the final view path will be constructed */
  #    define LCB_CMDVIEWQUERY_F_SPATIAL (1 << 18)
  /**Set this flag to only parse the top level row, and not its constituent
   * parts. Note this is incompatible with `F_INCLUDE_DOCS`*/
  #    define LCB_CMDVIEWQUERY_F_NOROWPARSE (1 << 17)
  
  #define pycbc_verb(VERB, INSTANCE, COOKIE, CMD) pycbc_verb_postfix(, VERB, INSTANCE, COOKIE, CMD)
  #define LCB_STORE_WRAPPER(b) handler(module, "LCB_" #b, LCB_STORE_##b);
  
  #ifndef LIBCOUCHBASE_couchbase_internalstructs_h__
  enum replica_legacy { LCB_REPLICA_FIRST, LCB_REPLICA_SELECT, LCB_REPLICA_ALL };
  #endif
  
  
  #define PYCBC_get_ATTR(CMD, attrib, ...) \
      lcb_cmdget_##attrib((CMD), __VA_ARGS__);
  #define PYCBC_subdoc_ATTR(CMD, attrib, ...) \
      lcb_cmdsubdoc_##attrib((CMD), __VA_ARGS__);
  #define PYCBC_touch_ATTR(CMD, attrib, ...) \
      lcb_cmdtouch_##attrib((CMD), __VA_ARGS__);
  #define PYCBC_getreplica_ATTR(CMD, attrib, ...) \
      lcb_cmdgetreplica_##attrib((CMD), __VA_ARGS__);
  #define PYCBC_unlock_ATTR(CMD, attrib, ...) \
      lcb_cmdunlock_##attrib(CMD, __VA_ARGS__);
  #define PYCBC_remove_ATTR(CMD, attrib, ...) \
      lcb_cmdremove_##attrib(CMD, __VA_ARGS__);
  #define PYCBC_endure_ATTR(CMD, attrib, ...) \
      lcb_cmdstore_##attrib(CMD, __VA_ARGS__);
  #define lcb_cmdendure_parent_span(CMD, SPAN) \
      lcb_cmdstore_parent_span((CMD), (SPAN));
  #define lcb_cmdendure_key(CMD, KEY, NKEY) \
      lcb_cmdstore_key(CMD, KEY, NKEY)
  #define CMDSCOPE_CREATECMD_RAW(UC, LC, CMD, ...) \
      CMDSCOPE_CREATECMD_RAW_V4(UC, LC, CMD, __VA_ARGS__)
  
  #define CMDSCOPE_CREATECMD(UC, LC, CMD, ...) \
      CMDSCOPE_CREATECMD_V4(UC, LC, CMD, __VA_ARGS__)
  
  #define CMDSCOPE_DESTROYCMD(UC, LC, CMD, ...) \
      CMDSCOPE_DESTROYCMD_V4(UC, LC, CMD, __VA_ARGS__)
  
  #define CMDSCOPE_DESTROYCMD_RAW(UC, LC, CMD, ...) \
      CMDSCOPE_DESTROYCMD_RAW_V4(UC, LC, CMD, __VA_ARGS__)
  
  #define PYCBC_CMD_SET_KEY_SCOPE(SCOPE, CMD, KEY)                          \
      PYCBC_DEBUG_LOG(                                                      \
              "Setting key %.*s on %s", (KEY).length, (KEY).buffer, #SCOPE) \
      lcb_cmd##SCOPE##_key(CMD, (KEY).buffer, (KEY).length)
  
  #define PYCBC_CMD_SET_VALUE_SCOPE(SCOPE, CMD, KEY)                          \
      PYCBC_DEBUG_LOG(                                                        \
              "Setting value %.*s on %s", (KEY).length, (KEY).buffer, #SCOPE) \
      lcb_cmd##SCOPE##_value(CMD, (KEY).buffer, (KEY).length)
  
  #ifndef LIBCOUCHBASE_couchbase_internalstructs_h__
  typedef lcb_SUBDOCSPECS pycbc_SDSPEC;
  
  /**@ingroup lcb-public-api
   * @defgroup lcb-subdoc Sub-Document API
   * @brief Experimental in-document API access
   * @details The sub-document API uses features from the upcoming Couchbase
   * 4.5 release which allows access to parts of the document. These parts are
   * called _sub-documents_ and can be accessed using the sub-document API
   *
   * @addtogroup lcb-subdoc
   * @{
   */
  
  /**
   * @brief Sub-Document command codes
   *
   * These command codes should be applied as values to lcb_SDSPEC::sdcmd and
   * indicate which type of subdoc command the server should perform.
   */
  typedef enum {
      /**
       * Retrieve the value for a path
       */
      LCB_SDCMD_GET = 1,
  
      /**
       * Check if the value for a path exists. If the path exists then the error
       * code will be @ref LCB_SUCCESS
       */
      LCB_SDCMD_EXISTS,
  
      /**
       * Replace the value at the specified path. This operation can work
       * on any existing and valid path.
       */
      LCB_SDCMD_REPLACE,
  
      /**
       * Add the value at the given path, if the given path does not exist.
       * The penultimate path component must point to an array. The operation
       * may be used in conjunction with @ref LCB_SDSPEC_F_MKINTERMEDIATES to
       * create the parent dictionary (and its parents as well) if it does not
       * yet exist.
       */
      LCB_SDCMD_DICT_ADD,
  
      /**
       * Unconditionally set the value at the path. This logically
       * attempts to perform a @ref LCB_SDCMD_REPLACE, and if it fails, performs
       * an @ref LCB_SDCMD_DICT_ADD.
       */
      LCB_SDCMD_DICT_UPSERT,
  
      /**
       * Prepend the value(s) to the array indicated by the path. The path should
       * reference an array. When the @ref LCB_SDSPEC_F_MKINTERMEDIATES flag
       * is specified then the array may be created if it does not exist.
       *
       * Note that it is possible to add more than a single value to an array
       * in an operation (this is valid for this commnand as well as
       * @ref LCB_SDCMD_ARRAY_ADD_LAST and @ref LCB_SDCMD_ARRAY_INSERT). Multiple
       * items can be specified by placing a comma between then (the values should
       * otherwise be valid JSON).
       */
      LCB_SDCMD_ARRAY_ADD_FIRST,
  
      /**
       * Identical to @ref LCB_SDCMD_ARRAY_ADD_FIRST but places the item(s)
       * at the end of the array rather than at the beginning.
       */
      LCB_SDCMD_ARRAY_ADD_LAST,
  
      /**
       * Add the value to the array indicated by the path, if the value is not
       * already in the array. The @ref LCB_SDSPEC_F_MKINTERMEDIATES flag can
       * be specified to create the array if it does not already exist.
       *
       * Currently the value for this operation must be a JSON primitive (i.e.
       * no arrays or dictionaries) and the existing array itself must also
       * contain only primitives (otherwise a @ref LCB_SUBDOC_PATH_MISMATCH
       * error will be received).
       */
      LCB_SDCMD_ARRAY_ADD_UNIQUE,
  
      /**
       * Add the value at the given array index. Unlike other array operations,
       * the path specified should include the actual index at which the item(s)
       * should be placed, for example `array[2]` will cause the value(s) to be
       * the 3rd item(s) in the array.
       *
       * The array must already exist and the @ref LCB_SDSPEC_F_MKINTERMEDIATES
       * flag is not honored.
       */
      LCB_SDCMD_ARRAY_INSERT,
  
      /**
       * Increment or decrement an existing numeric path. If the number does
       * not exist, it will be created (though its parents will not, unless
       * @ref LCB_SDSPEC_F_MKINTERMEDIATES is specified).
       *
       * The value for this operation should be a valid JSON-encoded integer and
       * must be between `INT64_MIN` and `INT64_MAX`, inclusive.
       */
      LCB_SDCMD_COUNTER,
  
      /**
       * Remove an existing path in the document.
       */
      LCB_SDCMD_REMOVE,
  
      /**
       * Count the number of elements in an array or dictionary
       */
      LCB_SDCMD_GET_COUNT,
  
      /**
       * Retrieve the entire document
       */
      LCB_SDCMD_FULLDOC_GET,
  
      /**
       * Add the entire document
       */
      LCB_SDCMD_FULLDOC_ADD,
  
      /**
       * Upsert the entire document
       */
      LCB_SDCMD_FULLDOC_UPSERT,
      /**
       * Replace the entire document
       */
      LCB_SDCMD_FULLDOC_REPLACE,
  
      /**
       * Remove the entire document
       */
      LCB_SDCMD_FULLDOC_REMOVE,
  
      LCB_SDCMD_MAX
  } lcb_SUBDOCOP;
  #else
  
  /**
   * Retrieve the entire document
   */
  #    define LCB_SDCMD_FULLDOC_GET (LCB_SDCMD_GET_COUNT + 1)
  
  /**
   * Add the entire document
   */
  #    define LCB_SDCMD_FULLDOC_ADD (LCB_SDCMD_GET_COUNT + 2)
  
  /**
   * Upsert the entire document
   */
  #    define LCB_SDCMD_FULLDOC_UPSERT (LCB_SDCMD_GET_COUNT + 3)
  /**
   * Replace the entire document
   */
  #    define LCB_SDCMD_FULLDOC_REPLACE (LCB_SDCMD_GET_COUNT + 4)
  
  /**
   * Remove the entire document
   */
  #    define LCB_SDCMD_FULLDOC_REMOVE (LCB_SDCMD_GET_COUNT + 5)
  
  #endif
  #define CMDSUBDOC_F_UPSERT_DOC (1 << 16)
  #define CMDSUBDOC_F_INSERT_DOC (1 << 17)
  #define CMDSUBDOC_F_ACCESS_DELETED (1 << 18)
  
  #define PYCBC_CRYPTO_VERSION 2
  
  #define ENDUREOPS(X, ...)
  #define OBSERVEOPS(X, ...)
  #define lcb_respendure_cookie(RESP, DEST) *(DEST)=(RESP)->cookie;
  #define lcb_respendure_status(RESP) (RESP)->rc
  #define lcb_respendure_cas(RESP, DEST) *(DEST)=(RESP)->cas;
  #define lcb_respendure_key(RESP, DEST, NDEST) *(DEST)=(RESP)->key; *(NDEST)=(RESP)->nkey;
  
  #define lcb_cmdobserve_parent_span(CMD, SPAN) LCB_ERR_UNSUPPORTED_OPERATION
  #define lcb_respobserve_status(RESP) LCB_ERR_UNSUPPORTED_OPERATION
  #define lcb_respobserve_cas(RESP, DEST) LCB_ERR_UNSUPPORTED_OPERATION
  #define lcb_respobserve_key(RESP, DEST, NDEST) LCB_ERR_UNSUPPORTED_OPERATION
  #define lcb_respobserve_cookie(RESP, DEST) LCB_ERR_UNSUPPORTED_OPERATION
  #define lcb_respobserve_is_master(RESP, DEST) LCB_ERR_UNSUPPORTED_OPERATION;
  #define lcb_respobserve_flags(RESP, DEST) LCB_ERR_UNSUPPORTED_OPERATION
  
  #define PYCBC_OBSERVE_FROM_LCB(X) PYCBC_OBSERVE_##X
  #define lcb_cmdgetreplica_expiry(CMD, TTL)
  
  #define lcb_cmdstats_create(DEST) \
      lcb_CMDSTATS cmd_real = {0};  \
      *(DEST) = &cmd_real;
  #define lcb_cmdstats_destroy(DEST) LCB_SUCCESS
  #define pycbc_cmdstats_kv(CMD)  (CMD)->cmdflags |= LCB_CMDSTATS_F_KV;
  #define pycbc_stats(...) lcb_stats3(__VA_ARGS__)
  
  #define lcb_respstats_cookie(CMD, ...)
  #define lcb_resphttp_key(CMD, ...)
  #define lcb_resphttp_cas(CMD, ...)
  
  #define PYCBC_CMD_SET_TRACESPAN(TYPE, CMD, SPAN) \
      lcb_cmd##TYPE##_parent_span((CMD), (SPAN));
  #define GENERIC_SPAN_OPERAND(SCOPE, INSTANCE, CMD, HANDLE, CONTEXT) \
      if (CONTEXT){lcb_cmd##SCOPE##_parent_span(CMD, (CONTEXT)->span);};
  #define GENERIC_NULL_OPERAND(SCOPE, INSTANCE, CMD, HANDLE, CONTEXT, COMMAND, ...) \
      lcb_##SCOPE(INSTANCE, __VA_ARGS__);
  #define UNSCOPED_OPERAND(SCOPE, INSTANCE, CMD, HANDLE, CONTEXT, COMMAND, ...) lcb_##SCOPE(INSTANCE, __VA_ARGS__)
  
  #define VIEW_SPAN_OPERAND(SCOPE, INSTANCE, CMD, HANDLE, CONTEXT) if (CONTEXT){lcb_cmdview_parent_span(CMD, (CONTEXT)->span);}
  
  #define PYCBC_LOG_KEY(CMD, key)
  
  uint64_t pycbc_mutation_token_seqno(const lcb_MUTATION_TOKEN *pToken);
  
  uint64_t pycbc_mutation_token_vbid(const lcb_MUTATION_TOKEN *pToken);
  
  uint64_t pycbc_mutation_token_uuid(const lcb_MUTATION_TOKEN *pToken);
  
  const lcb_MUTATION_TOKEN *pycbc_get_vbucket_mutation_token(lcb_INSTANCE* instance, lcb_KEYBUF *kb, lcb_STATUS *rc);
  
  lcb_STATUS pycbc_crypto_register(lcb_INSTANCE *instance,
                                   const char *name,
                                   lcbcrypto_PROVIDER *provider);
  lcb_STATUS pycbc_crypto_unregister(lcb_INSTANCE *instance, const char *name);
  
  lcb_STATUS pycbc_encrypt_fields(lcb_INSTANCE* instance, lcbcrypto_CMDENCRYPT* cmd);
  
  lcb_STATUS pycbc_decrypt_fields(lcb_INSTANCE* instance, lcbcrypto_CMDDECRYPT* cmd);
  
  typedef struct {
      const lcb_RESPSUBDOC *resp;
      size_t index;
  } pycbc_SDENTRY;
  
  lcb_STATUS pycbc_respsubdoc_status(const pycbc_SDENTRY *ent);
  
  pycbc_strn_base_const pycbc_respsubdoc_value(const pycbc_SDENTRY *ent);
  
  int pycbc_sdresult_next(const lcb_RESPSUBDOC *resp,
                          pycbc_SDENTRY *dest,
                          size_t *index);
  
  
  void pycbc_cmdsubdoc_flags_from_scv(unsigned int flags, lcb_CMDSUBDOC *cmd);
  
  lcb_STATUS pycbc_cmdquery_multiauth(lcb_CMDQUERY *cmd, int enable);
  
  #define LCB_PING_GET_TYPE_S(X, Y) \
  case LCB_PING_SERVICE_##X:        \
      return #Y;
  
  lcb_STATUS pycbc_cmdview_spatial(lcb_CMDVIEW *pCmdview, int is_spacial);
  
  #define VIEW_FIELDS_REDUCE(X, SEP)\
      X(key,key) SEP \
      X(value,row)
  
  #define PYCBC_PP_ENCRYPT_CONSTANTS(X)
  #define PYCBC_X_SD_OPS_FULLDOC(X, NP, VAL, MVAL, CTR, ...)
  
  typedef lcb_DURABILITY_LEVEL pycbc_DURABILITY_LEVEL;
  #define lcb_cmdremove_durability_observe(...) LCB_ERR_SDK_INTERNAL
  
  #define PYCBC_X_DURLEVEL(X)           \
      X(NONE)                           \
      X(MAJORITY)                       \
      X(MAJORITY_AND_PERSIST_TO_ACTIVE) \
      X(PERSIST_TO_MAJORITY)
  
  #define PYCBX_X_SYNCREPERR(X)                                                 \
      X(LCB_ERR_DURABILITY_LEVEL_NOT_AVAILABLE,                                 \
        307,                                                                    \
        LCB_ERROR_TYPE_KEYVALUE,                                                \
        "Invalid durability level was specified")                               \
      /** Valid request, but given durability requirements are impossible to    \
       * achieve - because insufficient configured replicas are connected.      \
       * Assuming level=majority and C=number of configured nodes, durability   \
       * becomes impossible if floor((C + 1) / 2) nodes or greater are offline. \
       */                                                                       \
      X(LCB_ERR_DURABILITY_IMPOSSIBLE,                                          \
        308,                                                                    \
        LCB_ERROR_TYPE_KEYVALUE,                                                \
        "Given durability requirements are impossible to achieve")              \
      /** Returned if an attempt is made to mutate a key which already has a    \
       * SyncWrite pending. Client would typically retry (possibly with         \
       * backoff). Similar to ELOCKED */                                        \
      X(LCB_ERR_DURABLE_WRITE_IN_PROGRESS,                                      \
        310,                                                                    \
        LCB_ERROR_TYPE_KEYVALUE,                                                \
        "There is a synchronous mutation pending for given key")                \
      /** The SyncWrite request has not completed in the specified time and has \
       * ambiguous result - it may Succeed or Fail; but the final value is not  \
       * yet known */                                                           \
      X(LCB_ERR_DURABILITY_AMBIGUOUS,                                           \
        309,                                                                    \
        LCB_ERROR_TYPE_KEYVALUE,                                                \
        "Synhronous mutation has not completed in the specified time and has "  \
        "ambiguous result")                                                     \
      X(LCB_ERR_DURABLE_WRITE_RE_COMMIT_IN_PROGRESS,                            \
        311,                                                                    \
        LCB_ERROR_TYPE_KEYVALUE,                                                \
        "Durable write re-commit in progress")
  
  #define PYCBC_DURABILITY 1
  #define PYCBC_LCB_ERRTYPES(X)    \
      X(LCB_ERROR_TYPE_BASE);      \
      X(LCB_ERROR_TYPE_SHARED);    \
      X(LCB_ERROR_TYPE_KEYVALUE);  \
      X(LCB_ERROR_TYPE_QUERY);     \
      X(LCB_ERROR_TYPE_ANALYTICS); \
      X(LCB_ERROR_TYPE_SEARCH);    \
      X(LCB_ERROR_TYPE_VIEW);      \
      X(LCB_ERROR_TYPE_SDK);
  
  #define PYCBC_DO_COLL(TYPE, CMD, SCOPE, NSCOPE, COLLECTION, NCOLLECTION) \
      lcb_cmd##TYPE##_collection(CMD, SCOPE, NSCOPE, COLLECTION, NCOLLECTION)
  
  typedef void pycbc_MULTICMD_CTX;
  typedef void pycbc_CMDENDURE;
  
  #include "lcb_dur_wrappers.h"
  #define pycbc_cmdendure_key(...) LCB_ERR_UNSUPPORTED_OPERATION
  #define pycbc_cmdendure_addcmd(...) LCB_ERR_UNSUPPORTED_OPERATION
  #define pycbc_create_cmdendure(cmd) LCB_ERR_UNSUPPORTED_OPERATION
  #define pycbc_cmdendure_cas(cmd, cas) LCB_ERR_UNSUPPORTED_OPERATION
  #define pycbc_mctx_done(mctx, cookie) LCB_ERR_UNSUPPORTED_OPERATION
  #define pycbc_mctx_fail(mctx) LCB_ERR_UNSUPPORTED_OPERATION
  #define lcb_respobserve_is_master(RESP, DEST) LCB_ERR_UNSUPPORTED_OPERATION;
  typedef void pycbc_RESPOBSERVE;
  typedef void pycbc_CMDOBSERVE;
  #define pycbc_cmdobserve_create(cmd)
  #define pycbc_cmdobserve_key(cmd, buffer, nbuffer) LCB_ERR_UNSUPPORTED_OPERATION
  #define pycbc_cmdobserve_master_only(cmd) LCB_ERR_UNSUPPORTED_OPERATION
  #define pycbc_mctx_create(instance, dest) LCB_ERR_UNSUPPORTED_OPERATION
  
  #endif // COUCHBASE_PYTHON_CLIENT_LCB_V4_WRAPPER_H
  