diff --git a/CMakeLists.txt b/CMakeLists.txt
index ee12730f..a094a550 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -307,4 +307,5 @@ if(NATS_BUILD_STREAMING)
endif()
add_subdirectory(test)
add_subdirectory(test/dylib)
+add_subdirectory(test/check_cpp)
#----------------------------
diff --git a/buildOnTravis.sh b/buildOnTravis.sh
index 8bc7da67..0510cf93 100755
--- a/buildOnTravis.sh
+++ b/buildOnTravis.sh
@@ -73,6 +73,14 @@ if [ $res -ne 0 ]; then
exit $res
fi
+echo "Test C++ compiler compatibility"
+# There is mo need to run check, just make sure it's compiled
+bin/check_cpp
+res=$?
+if [ $res -ne 0 ]; then
+ exit $res
+fi
+
export NATS_TEST_TRAVIS=yes
echo "Using NATS server version: $NATS_TEST_SERVER_VERSION"
ctest -L 'test' --timeout 60 --output-on-failure $4
diff --git a/src/nats.h b/src/nats.h
index e368d89a..0e69b43a 100644
--- a/src/nats.h
+++ b/src/nats.h
@@ -1239,6 +1239,127 @@ typedef void (*jsFetchCompleteHandler)(natsConnection *nc, natsSubscription *sub
*/
typedef bool (*jsFetchNextHandler)(int *messages, int64_t *maxBytes, natsSubscription *sub, void *closure);
+/**
+ * Async pull subscriber options.
+ *
+ * Part of #jsOptions.
+ */
+typedef struct jsOptionsPullSubscribeAsync
+{
+ int64_t Timeout; ///< Auto-unsubsribe after this many milliseconds.
+ int MaxMessages; ///< Auto-unsubscribed after receiving this many messages.
+ int64_t MaxBytes; ///< Auto-unsubscribe after receiving this many bytes.
+
+ /// \brief If NoWait is set, the subscription will receive the
+ /// messages already stored on the server subject to the limits,
+ /// but will not wait for more messages.
+ ///
+ /// \note that if Timeout is set we would still wait for first
+ /// message to become available, even if there are currently any
+ /// on the server
+ bool NoWait;
+
+ /// \brief Fetch complete handler that receives the exit status
+ /// code, the subscription's Complete handler is also invoked,
+ /// but does not have the status code.
+ jsFetchCompleteHandler CompleteHandler;
+ void *CompleteHandlerClosure;
+
+ /// \brief Have server sends heartbeats at this interval (in
+ /// milliseconds) to help detect communication failures.
+ int64_t Heartbeat;
+
+ /// @brief When using the automatic Fetch flow control (default
+ /// NextHandler), this is the number of messages to ask for in a
+ /// single request.
+ int FetchSize;
+
+ /// @brief When using the automatic Fetch flow control (default
+ /// NextHandler), initiate the next fetch request (this many
+ /// messages) prior to the fulfillment of the current request.
+ ///
+ /// @note KeepAhead can not be used in conjunction with MaxBytes
+ /// or NoWait.
+ int KeepAhead;
+
+ /// @brief If set, switches to manual fetch flow control.
+ ///
+ /// If provided, this function gets called before each message
+ /// is deliverered to msgCB, and overrides the default algorithm
+ /// for sending Next fetch requests.
+ jsFetchNextHandler NextHandler;
+ void *NextHandlerClosure;
+
+} jsOptionsPullSubscribeAsync;
+
+/**
+ * Async pull options.
+ *
+ * Part of #jsOptions.
+ */
+typedef struct jsOptionsPublishAsync
+{
+ int64_t MaxPending; ///< Maximum outstanding asynchronous publishes that can be inflight at one time.
+
+ // If jsPubAckHandler is specified, the callback will be invoked
+ // for every asynchronous published message, either as a positive
+ // result, or with the error encountered when publishing that
+ // message. If this callback is specified, ErrHandler (see below)
+ // will be ignored.
+ jsPubAckHandler AckHandler; ///< Callback invoked for each asynchronous published message.
+ void *AckHandlerClosure; ///< Closure (or user data) passed to #jsPubAckHandler callback.
+
+ // This callback is invoked for messages published asynchronously
+ // when an error is returned by the server or if the library has
+ // timed-out waiting for an acknowledgment back from the server
+ // (if publish uses the jsPubOptions.MaxWait).
+ jsPubAckErrHandler ErrHandler; ///< Callback invoked when error encountered publishing a given message.
+ void *ErrHandlerClosure; ///< Closure (or user data) passed to #jsPubAckErrHandler callback.
+
+ int64_t StallWait; ///< Amount of time (in milliseconds) to wait in a PublishAsync call when there is MaxPending inflight messages, default is 200 ms.
+
+} jsOptionsPublishAsync;
+
+/**
+ * Advanced stream purge options
+ *
+ * * `Subject` will filter the purge request to only messages that match the subject, which can have wildcards.
+ * * `Sequence` will purge up to but not including this sequence and can be combined with subject filtering.
+ * * `Keep` will specify how many messages to keep and can be combined with subject filtering.
+ *
+ * \note `Sequence` and `Keep` are mutually exclusive, so both can not be set at the same time.
+ */
+typedef struct jsOptionsStreamPurge
+{
+ const char *Subject; ///< This is the subject to match against messages for the purge command.
+ uint64_t Sequence; ///< Purge up to but not including sequence.
+ uint64_t Keep; ///< Number of messages to keep.
+
+} jsOptionsStreamPurge;
+
+/**
+ * Advance stream information retrieval options
+ */
+typedef struct jsOptionsStreamInfo
+{
+ bool DeletedDetails; ///< Get the list of deleted message sequences.
+ const char *SubjectsFilter; ///< Get the list of subjects in this stream.
+
+} jsOptionsStreamInfo;
+
+/**
+ * Advanced stream options
+ *
+ * * `Purge` for advanced purge options.
+ * * `Info` for advanced information retrieval options.
+ */
+typedef struct jsOptionsStream
+{
+ jsOptionsStreamPurge Purge; ///< Optional stream purge options.
+ jsOptionsStreamInfo Info; ///< Optional stream information retrieval options.
+
+} jsOptionsStream;
+
/**
* JetStream context options.
*
@@ -1246,118 +1367,12 @@ typedef bool (*jsFetchNextHandler)(int *messages, int64_t *maxBytes, natsSubscri
*/
typedef struct jsOptions
{
- const char *Prefix; ///< JetStream prefix, default is "$JS.API"
- const char *Domain; ///< Domain changes the domain part of JetSteam API prefix.
- int64_t Wait; ///< Amount of time (in milliseconds) to wait for various JetStream API requests, default is 5000 ms (5 seconds).
-
- struct jsOptionsPublishAsync
- {
- int64_t MaxPending; ///< Maximum outstanding asynchronous publishes that can be inflight at one time.
-
- // If jsPubAckHandler is specified, the callback will be invoked
- // for every asynchronous published message, either as a positive
- // result, or with the error encountered when publishing that
- // message. If this callback is specified, ErrHandler (see below)
- // will be ignored.
- jsPubAckHandler AckHandler; ///< Callback invoked for each asynchronous published message.
- void *AckHandlerClosure; ///< Closure (or user data) passed to #jsPubAckHandler callback.
-
- // This callback is invoked for messages published asynchronously
- // when an error is returned by the server or if the library has
- // timed-out waiting for an acknowledgment back from the server
- // (if publish uses the jsPubOptions.MaxWait).
- jsPubAckErrHandler ErrHandler; ///< Callback invoked when error encountered publishing a given message.
- void *ErrHandlerClosure; ///< Closure (or user data) passed to #jsPubAckErrHandler callback.
-
- int64_t StallWait; ///< Amount of time (in milliseconds) to wait in a PublishAsync call when there is MaxPending inflight messages, default is 200 ms.
-
- } PublishAsync; ///< extra options for #js_PublishAsync
-
- struct jsOptionsPullSubscribeAsync
- {
- int64_t Timeout; ///< Auto-unsubsribe after this many milliseconds.
- int MaxMessages; ///< Auto-unsubscribed after receiving this many messages.
- int64_t MaxBytes; ///< Auto-unsubscribe after receiving this many bytes.
-
- /// \brief If NoWait is set, the subscription will receive the
- /// messages already stored on the server subject to the limits,
- /// but will not wait for more messages.
- ///
- /// \note that if Timeout is set we would still wait for first
- /// message to become available, even if there are currently any
- /// on the server
- bool NoWait;
-
- /// \brief Fetch complete handler that receives the exit status
- /// code, the subscription's Complete handler is also invoked,
- /// but does not have the status code.
- jsFetchCompleteHandler CompleteHandler;
- void *CompleteHandlerClosure;
-
- /// \brief Have server sends heartbeats at this interval (in
- /// milliseconds) to help detect communication failures.
- int64_t Heartbeat;
-
- /// @brief When using the automatic Fetch flow control (default
- /// NextHandler), this is the number of messages to ask for in a
- /// single request.
- int FetchSize;
-
- /// @brief When using the automatic Fetch flow control (default
- /// NextHandler), initiate the next fetch request (this many
- /// messages) prior to the fulfillment of the current request.
- ///
- /// @note KeepAhead can not be used in conjunction with MaxBytes
- /// or NoWait.
- int KeepAhead;
-
- /// @brief If set, switches to manual fetch flow control.
- ///
- /// If provided, this function gets called before each message
- /// is deliverered to msgCB, and overrides the default algorithm
- /// for sending Next fetch requests.
- jsFetchNextHandler NextHandler;
- void *NextHandlerClosure;
-
- } PullSubscribeAsync; ///< extra options for #js_PullSubscribeAsync
-
-
- /**
- * Advanced stream options
- *
- * * `Purge` for advanced purge options.
- * * `Info` for advanced information retrieval options.
- */
- struct jsOptionsStream
- {
- /**
- * Advanced stream purge options
- *
- * * `Subject` will filter the purge request to only messages that match the subject, which can have wildcards.
- * * `Sequence` will purge up to but not including this sequence and can be combined with subject filtering.
- * * `Keep` will specify how many messages to keep and can be combined with subject filtering.
- *
- * \note `Sequence` and `Keep` are mutually exclusive, so both can not be set at the same time.
- */
- struct jsOptionsStreamPurge
- {
- const char *Subject; ///< This is the subject to match against messages for the purge command.
- uint64_t Sequence; ///< Purge up to but not including sequence.
- uint64_t Keep; ///< Number of messages to keep.
-
- } Purge; ///< Optional stream purge options.
-
- /**
- * Advance stream information retrieval options
- */
- struct jsOptionsStreamInfo
- {
- bool DeletedDetails; ///< Get the list of deleted message sequences.
- const char *SubjectsFilter; ///< Get the list of subjects in this stream.
-
- } Info; ///< Optional stream information retrieval options.
-
- } Stream; ///< Optional stream options.
+ const char *Prefix; ///< JetStream prefix, default is "$JS.API"
+ const char *Domain; ///< Domain changes the domain part of JetSteam API prefix.
+ int64_t Wait; ///< Amount of time (in milliseconds) to wait for various JetStream API requests, default is 5000 ms (5 seconds).
+ jsOptionsPublishAsync PublishAsync; ///< extra options for #js_PublishAsync
+ jsOptionsPullSubscribeAsync PullSubscribeAsync; ///< extra options for #js_PullSubscribeAsync
+ jsOptionsStream Stream; ///< Optional stream options.
} jsOptions;
diff --git a/test/check_cpp/CMakeLists.txt b/test/check_cpp/CMakeLists.txt
new file mode 100644
index 00000000..3df4db4d
--- /dev/null
+++ b/test/check_cpp/CMakeLists.txt
@@ -0,0 +1,25 @@
+if(NOT BUILD_TESTING)
+ return()
+endif()
+
+if(NOT NATS_BUILD_LIB_STATIC)
+ MESSAGE(FATAL_ERROR
+ "Building tests require static library, or run CMake with -DBUILD_TESTING=OFF")
+ return()
+endif()
+
+if(MSVC)
+ set_source_files_properties(test.c PROPERTIES COMPILE_FLAGS "/w")
+endif()
+
+# We need this to build the test program
+include_directories(${PROJECT_SOURCE_DIR}/src)
+
+if(NATS_BUILD_WITH_TLS)
+ include_directories(${OPENSSL_INCLUDE_DIR})
+endif(NATS_BUILD_WITH_TLS)
+
+# Build the test program
+add_executable(check_cpp check_cpp.cpp)
+
+target_link_libraries(check_cpp nats_static ${NATS_EXTRA_LIB})
diff --git a/test/check_cpp/check_cpp.cpp b/test/check_cpp/check_cpp.cpp
new file mode 100644
index 00000000..985bf456
--- /dev/null
+++ b/test/check_cpp/check_cpp.cpp
@@ -0,0 +1,29 @@
+// Copyright 2017-2025 The NATS Authors
+// 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.
+
+#include
+#include
+
+// Check C++ compiler compatibility of structs in
+// natsp.h to avoid incomplete type errors such as C2079.
+#include
+
+int main(int argc, char **argv)
+{
+ // jsOptionsPullSubscribeAsync opts should be accessible
+ jsFetch fetch;
+ fetch.opts.Timeout = 1;
+
+ std::cout << "OK" << std::endl;
+ return 0;
+}