From 580f786d962222407862ecd29070ee1eaa23b91d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:38:25 +0000 Subject: [PATCH 1/9] Initial plan From ae8d1e523d853f1a9fbf2be07c414d9ed1d4ff6b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:51:13 +0000 Subject: [PATCH 2/9] Add SDK implementations for TypeScript, Python, C++, and C# Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- .../cpp/sdk/network_transports.hpp | 110 +++++++ .../boilerplate/cpp/sdk/observer.hpp | 164 ++++++++++ src/struct_frame/boilerplate/cpp/sdk/sdk.hpp | 10 + .../boilerplate/cpp/sdk/serial_transport.hpp | 199 ++++++++++++ .../boilerplate/cpp/sdk/struct_frame_sdk.hpp | 288 ++++++++++++++++++ .../boilerplate/cpp/sdk/transport.hpp | 143 +++++++++ .../sdk/SerialAndWebSocketTransports.cs | 266 ++++++++++++++++ .../boilerplate/csharp/sdk/StructFrameSdk.cs | 263 ++++++++++++++++ .../boilerplate/csharp/sdk/TcpTransport.cs | 131 ++++++++ .../boilerplate/csharp/sdk/Transport.cs | 130 ++++++++ .../boilerplate/csharp/sdk/UdpTransport.cs | 134 ++++++++ .../boilerplate/py/sdk/__init__.py | 65 ++++ .../py/sdk/async_serial_transport.py | 135 ++++++++ .../py/sdk/async_struct_frame_sdk.py | 174 +++++++++++ .../boilerplate/py/sdk/async_tcp_transport.py | 89 ++++++ .../boilerplate/py/sdk/async_transport.py | 92 ++++++ .../boilerplate/py/sdk/async_udp_transport.py | 88 ++++++ .../py/sdk/async_websocket_transport.py | 89 ++++++ .../boilerplate/py/sdk/serial_transport.py | 103 +++++++ .../boilerplate/py/sdk/struct_frame_sdk.py | 173 +++++++++++ .../boilerplate/py/sdk/tcp_transport.py | 87 ++++++ .../boilerplate/py/sdk/transport.py | 115 +++++++ .../boilerplate/py/sdk/udp_transport.py | 82 +++++ .../boilerplate/py/sdk/websocket_transport.py | 104 +++++++ src/struct_frame/boilerplate/ts/sdk/index.ts | 15 + .../boilerplate/ts/sdk/serial_transport.ts | 121 ++++++++ .../boilerplate/ts/sdk/struct_frame_sdk.ts | 220 +++++++++++++ .../boilerplate/ts/sdk/tcp_transport.ts | 95 ++++++ .../boilerplate/ts/sdk/transport.ts | 131 ++++++++ .../boilerplate/ts/sdk/udp_transport.ts | 102 +++++++ .../boilerplate/ts/sdk/websocket_transport.ts | 100 ++++++ 31 files changed, 4018 insertions(+) create mode 100644 src/struct_frame/boilerplate/cpp/sdk/network_transports.hpp create mode 100644 src/struct_frame/boilerplate/cpp/sdk/observer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/sdk/sdk.hpp create mode 100644 src/struct_frame/boilerplate/cpp/sdk/serial_transport.hpp create mode 100644 src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp create mode 100644 src/struct_frame/boilerplate/cpp/sdk/transport.hpp create mode 100644 src/struct_frame/boilerplate/csharp/sdk/SerialAndWebSocketTransports.cs create mode 100644 src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs create mode 100644 src/struct_frame/boilerplate/csharp/sdk/TcpTransport.cs create mode 100644 src/struct_frame/boilerplate/csharp/sdk/Transport.cs create mode 100644 src/struct_frame/boilerplate/csharp/sdk/UdpTransport.cs create mode 100644 src/struct_frame/boilerplate/py/sdk/__init__.py create mode 100644 src/struct_frame/boilerplate/py/sdk/async_serial_transport.py create mode 100644 src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py create mode 100644 src/struct_frame/boilerplate/py/sdk/async_tcp_transport.py create mode 100644 src/struct_frame/boilerplate/py/sdk/async_transport.py create mode 100644 src/struct_frame/boilerplate/py/sdk/async_udp_transport.py create mode 100644 src/struct_frame/boilerplate/py/sdk/async_websocket_transport.py create mode 100644 src/struct_frame/boilerplate/py/sdk/serial_transport.py create mode 100644 src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py create mode 100644 src/struct_frame/boilerplate/py/sdk/tcp_transport.py create mode 100644 src/struct_frame/boilerplate/py/sdk/transport.py create mode 100644 src/struct_frame/boilerplate/py/sdk/udp_transport.py create mode 100644 src/struct_frame/boilerplate/py/sdk/websocket_transport.py create mode 100644 src/struct_frame/boilerplate/ts/sdk/index.ts create mode 100644 src/struct_frame/boilerplate/ts/sdk/serial_transport.ts create mode 100644 src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts create mode 100644 src/struct_frame/boilerplate/ts/sdk/tcp_transport.ts create mode 100644 src/struct_frame/boilerplate/ts/sdk/transport.ts create mode 100644 src/struct_frame/boilerplate/ts/sdk/udp_transport.ts create mode 100644 src/struct_frame/boilerplate/ts/sdk/websocket_transport.ts diff --git a/src/struct_frame/boilerplate/cpp/sdk/network_transports.hpp b/src/struct_frame/boilerplate/cpp/sdk/network_transports.hpp new file mode 100644 index 00000000..01794d64 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/sdk/network_transports.hpp @@ -0,0 +1,110 @@ +// Network transport implementations using ASIO +// NOTE: These require the ASIO library (header-only or standalone) +// Include asio.hpp or boost/asio.hpp in your project + +#pragma once + +#include "transport.hpp" + +namespace StructFrame { + +/* + * UDP Transport using ASIO + * + * To use this transport, you need to: + * 1. Include ASIO in your project + * 2. Implement the transport using asio::ip::udp::socket + * 3. Handle async operations with io_context + * + * Example implementation: + * + * class UdpTransport : public BaseTransport { + * private: + * asio::io_context io_context_; + * asio::ip::udp::socket socket_; + * asio::ip::udp::endpoint remote_endpoint_; + * + * public: + * UdpTransport(const std::string& host, uint16_t port); + * void connect() override; + * void disconnect() override; + * void send(const uint8_t* data, size_t length) override; + * void startReceive(); + * }; + */ + +/* + * TCP Transport using ASIO + * + * To use this transport, you need to: + * 1. Include ASIO in your project + * 2. Implement the transport using asio::ip::tcp::socket + * 3. Handle async operations with io_context + * + * Example implementation: + * + * class TcpTransport : public BaseTransport { + * private: + * asio::io_context io_context_; + * asio::ip::tcp::socket socket_; + * asio::ip::tcp::endpoint endpoint_; + * + * public: + * TcpTransport(const std::string& host, uint16_t port); + * void connect() override; + * void disconnect() override; + * void send(const uint8_t* data, size_t length) override; + * void startReceive(); + * }; + */ + +/* + * WebSocket Transport using Simple-WebSocket-Server + * + * To use this transport, you need to: + * 1. Include Simple-WebSocket-Server in your project + * 2. Include ASIO (required by Simple-WebSocket-Server) + * 3. Implement the transport using WsClient or WssClient + * + * Example implementation: + * + * #include "client_ws.hpp" + * using WsClient = SimpleWeb::SocketClient; + * + * class WebSocketTransport : public BaseTransport { + * private: + * std::shared_ptr client_; + * std::shared_ptr connection_; + * + * public: + * WebSocketTransport(const std::string& url); + * void connect() override; + * void disconnect() override; + * void send(const uint8_t* data, size_t length) override; + * }; + */ + +/* + * Serial Transport using ASIO Serial Port + * + * To use this transport, you need to: + * 1. Include ASIO in your project + * 2. Implement the transport using asio::serial_port + * + * Example implementation: + * + * class AsioSerialTransport : public BaseTransport { + * private: + * asio::io_context io_context_; + * asio::serial_port serial_port_; + * + * public: + * AsioSerialTransport(const std::string& port, uint32_t baud_rate); + * void connect() override; + * void disconnect() override; + * void send(const uint8_t* data, size_t length) override; + * void startReceive(); + * }; + */ + +} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/cpp/sdk/observer.hpp b/src/struct_frame/boilerplate/cpp/sdk/observer.hpp new file mode 100644 index 00000000..0b0f601a --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/sdk/observer.hpp @@ -0,0 +1,164 @@ +// Observer/Subscriber pattern for C++ struct-frame SDK +// Header-only implementation inspired by ETLCPP but with no dependencies + +#pragma once + +#include +#include +#include + +namespace StructFrame { + +// Forward declarations +template +class Observable; + +/** + * Observer interface for receiving messages + * @tparam TMessage The message type to observe + */ +template +class IObserver { +public: + virtual ~IObserver() = default; + + /** + * Called when a message is received + * @param message The received message + * @param msgId The message ID + */ + virtual void onMessage(const TMessage& message, uint8_t msgId) = 0; +}; + +/** + * Lambda-based observer for functional style subscription + * @tparam TMessage The message type to observe + */ +template +class LambdaObserver : public IObserver { +public: + using CallbackType = std::function; + + explicit LambdaObserver(CallbackType callback) : callback_(std::move(callback)) {} + + void onMessage(const TMessage& message, uint8_t msgId) override { + if (callback_) { + callback_(message, msgId); + } + } + +private: + CallbackType callback_; +}; + +/** + * Observable subject that notifies observers of messages + * @tparam TMessage The message type + */ +template +class Observable { +public: + /** + * Subscribe an observer to this observable + * @param observer The observer to add + */ + void subscribe(IObserver* observer) { + if (observer && std::find(observers_.begin(), observers_.end(), observer) == observers_.end()) { + observers_.push_back(observer); + } + } + + /** + * Unsubscribe an observer from this observable + * @param observer The observer to remove + */ + void unsubscribe(IObserver* observer) { + observers_.erase( + std::remove(observers_.begin(), observers_.end(), observer), + observers_.end() + ); + } + + /** + * Notify all observers of a new message + * @param message The message to send + * @param msgId The message ID + */ + void notify(const TMessage& message, uint8_t msgId) { + for (auto* observer : observers_) { + if (observer) { + observer->onMessage(message, msgId); + } + } + } + + /** + * Get the number of subscribed observers + */ + size_t observerCount() const { + return observers_.size(); + } + + /** + * Clear all observers + */ + void clear() { + observers_.clear(); + } + +private: + std::vector*> observers_; +}; + +/** + * RAII subscription handle that automatically unsubscribes on destruction + * @tparam TMessage The message type + */ +template +class Subscription { +public: + Subscription() : observable_(nullptr), observer_(nullptr) {} + + Subscription(Observable* observable, IObserver* observer) + : observable_(observable), observer_(observer) {} + + ~Subscription() { + unsubscribe(); + } + + // Move semantics + Subscription(Subscription&& other) noexcept + : observable_(other.observable_), observer_(other.observer_) { + other.observable_ = nullptr; + other.observer_ = nullptr; + } + + Subscription& operator=(Subscription&& other) noexcept { + if (this != &other) { + unsubscribe(); + observable_ = other.observable_; + observer_ = other.observer_; + other.observable_ = nullptr; + other.observer_ = nullptr; + } + return *this; + } + + // Disable copy + Subscription(const Subscription&) = delete; + Subscription& operator=(const Subscription&) = delete; + + void unsubscribe() { + if (observable_ && observer_) { + observable_->unsubscribe(observer_); + observable_ = nullptr; + observer_ = nullptr; + } + } + +private: + Observable* observable_; + IObserver* observer_; +}; + +} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/cpp/sdk/sdk.hpp b/src/struct_frame/boilerplate/cpp/sdk/sdk.hpp new file mode 100644 index 00000000..d3562acc --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/sdk/sdk.hpp @@ -0,0 +1,10 @@ +// C++ Struct Frame SDK +// Header-only SDK for structured message communication + +#pragma once + +#include "transport.hpp" +#include "serial_transport.hpp" +#include "network_transports.hpp" +#include "observer.hpp" +#include "struct_frame_sdk.hpp" diff --git a/src/struct_frame/boilerplate/cpp/sdk/serial_transport.hpp b/src/struct_frame/boilerplate/cpp/sdk/serial_transport.hpp new file mode 100644 index 00000000..53a452c1 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/sdk/serial_transport.hpp @@ -0,0 +1,199 @@ +// Generic Serial Interface for embedded systems +// Header-only implementation without external dependencies + +#pragma once + +#include "transport.hpp" +#include + +namespace StructFrame { + +/** + * Generic serial interface that can be implemented for any platform + * This provides a hardware abstraction layer for embedded systems + */ +class ISerialPort { +public: + virtual ~ISerialPort() = default; + + /** + * Open the serial port + * @return true on success + */ + virtual bool open() = 0; + + /** + * Close the serial port + */ + virtual void close() = 0; + + /** + * Write data to serial port + * @param data Pointer to data buffer + * @param length Length of data + * @return Number of bytes written + */ + virtual size_t write(const uint8_t* data, size_t length) = 0; + + /** + * Read data from serial port (non-blocking) + * @param buffer Buffer to read into + * @param maxLength Maximum bytes to read + * @return Number of bytes read + */ + virtual size_t read(uint8_t* buffer, size_t maxLength) = 0; + + /** + * Check if serial port is open + */ + virtual bool isOpen() const = 0; + + /** + * Get number of bytes available to read + */ + virtual size_t available() const = 0; +}; + +/** + * Serial transport configuration + */ +struct SerialTransportConfig : public TransportConfig { + size_t bufferSize = 4096; +}; + +/** + * Serial transport using generic serial interface + * Suitable for embedded systems and cross-platform development + */ +class SerialTransport : public BaseTransport { +private: + ISerialPort* serialPort_; + SerialTransportConfig serialConfig_; + std::vector receiveBuffer_; + bool running_ = false; + +public: + /** + * Construct serial transport + * @param serialPort Platform-specific serial port implementation + * @param config Transport configuration + */ + SerialTransport(ISerialPort* serialPort, const SerialTransportConfig& config = SerialTransportConfig()) + : BaseTransport(config), serialPort_(serialPort), serialConfig_(config) { + receiveBuffer_.resize(config.bufferSize); + } + + void connect() override { + if (!serialPort_) { + handleError("Serial port not initialized"); + return; + } + + if (!serialPort_->open()) { + handleError("Failed to open serial port"); + return; + } + + connected_ = true; + running_ = true; + } + + void disconnect() override { + running_ = false; + if (serialPort_ && serialPort_->isOpen()) { + serialPort_->close(); + } + connected_ = false; + } + + void send(const uint8_t* data, size_t length) override { + if (!serialPort_ || !connected_ || !serialPort_->isOpen()) { + handleError("Serial port not connected"); + return; + } + + size_t written = serialPort_->write(data, length); + if (written != length) { + handleError("Failed to write all data to serial port"); + } + } + + /** + * Poll for incoming data (call this regularly in your main loop) + * This is designed for embedded systems without threading + */ + void poll() { + if (!serialPort_ || !connected_ || !serialPort_->isOpen() || !running_) { + return; + } + + size_t available = serialPort_->available(); + if (available > 0) { + size_t toRead = (available < receiveBuffer_.size()) ? available : receiveBuffer_.size(); + size_t bytesRead = serialPort_->read(receiveBuffer_.data(), toRead); + + if (bytesRead > 0) { + handleData(receiveBuffer_.data(), bytesRead); + } + } + } +}; + +// Example platform-specific implementation stub +// Users would implement this for their specific hardware + +#ifdef EXAMPLE_IMPLEMENTATION +/** + * Example UART implementation for embedded system + * Replace this with your platform's UART driver + */ +class ExampleUartPort : public ISerialPort { +private: + // Platform-specific UART handle + void* uartHandle_; + bool isOpen_; + +public: + ExampleUartPort() : uartHandle_(nullptr), isOpen_(false) {} + + bool open() override { + // Platform-specific code to open UART + // uartHandle_ = HAL_UART_Init(...); + isOpen_ = true; + return isOpen_; + } + + void close() override { + // Platform-specific code to close UART + // HAL_UART_DeInit(uartHandle_); + isOpen_ = false; + } + + size_t write(const uint8_t* data, size_t length) override { + if (!isOpen_) return 0; + // Platform-specific code to write data + // return HAL_UART_Transmit(uartHandle_, data, length, timeout); + return length; + } + + size_t read(uint8_t* buffer, size_t maxLength) override { + if (!isOpen_) return 0; + // Platform-specific code to read data + // return HAL_UART_Receive(uartHandle_, buffer, maxLength, timeout); + return 0; + } + + bool isOpen() const override { + return isOpen_; + } + + size_t available() const override { + if (!isOpen_) return 0; + // Platform-specific code to check available bytes + // return HAL_UART_GetRxDataCount(uartHandle_); + return 0; + } +}; +#endif // EXAMPLE_IMPLEMENTATION + +} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp b/src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp new file mode 100644 index 00000000..f1265f0d --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp @@ -0,0 +1,288 @@ +// Struct Frame SDK Client for C++ +// Header-only implementation + +#pragma once + +#include "transport.hpp" +#include "observer.hpp" +#include +#include +#include +#include + +namespace StructFrame { + +/** + * Frame parser interface - must be implemented by generated frame parsers + */ +class IFrameParser { +public: + virtual ~IFrameParser() = default; + + /** + * Parse incoming data and extract message + * Returns frame message info with valid flag + */ + virtual FrameParsers::FrameMsgInfo parse(const uint8_t* data, size_t length) = 0; + + /** + * Frame a message for sending + * @param msgId Message ID + * @param data Message payload + * @param dataLen Payload length + * @param output Output buffer for framed message + * @param outputMaxLen Maximum output buffer size + * @return Actual framed message length + */ + virtual size_t frame(uint8_t msgId, const uint8_t* data, size_t dataLen, + uint8_t* output, size_t outputMaxLen) = 0; +}; + +/** + * Message codec interface - deserializes raw bytes into message objects + */ +template +class IMessageCodec { +public: + virtual ~IMessageCodec() = default; + + /** + * Get message ID for this codec + */ + virtual uint8_t getMsgId() const = 0; + + /** + * Deserialize bytes into message object + */ + virtual bool deserialize(const uint8_t* data, size_t length, TMessage& message) = 0; +}; + +/** + * Struct Frame SDK Configuration + */ +struct StructFrameSdkConfig { + ITransport* transport; + IFrameParser* frameParser; + bool debug = false; + size_t maxBufferSize = 8192; +}; + +/** + * Main SDK Client + */ +class StructFrameSdk { +private: + ITransport* transport_; + IFrameParser* frameParser_; + bool debug_; + std::vector buffer_; + size_t maxBufferSize_; + + // Type-erased observable map for different message types + std::map observables_; + + void handleIncomingData(const uint8_t* data, size_t length) { + // Append to buffer + if (buffer_.size() + length > maxBufferSize_) { + log("Buffer overflow, clearing buffer"); + buffer_.clear(); + } + + buffer_.insert(buffer_.end(), data, data + length); + + // Try to parse messages from buffer + parseBuffer(); + } + + void parseBuffer() { + while (!buffer_.empty()) { + auto result = frameParser_->parse(buffer_.data(), buffer_.size()); + + if (!result.valid) { + // No valid frame found + break; + } + + // Valid message found + log("Received message ID " + std::to_string(result.msg_id) + + ", " + std::to_string(result.msg_len) + " bytes"); + + // Notify observers (user must call notifyObservers with proper type) + // This is handled by the typed notifyObservers method + + // Remove parsed data from buffer + size_t frameSize = calculateFrameSize(result); + buffer_.erase(buffer_.begin(), buffer_.begin() + frameSize); + } + } + + size_t calculateFrameSize(const FrameParsers::FrameMsgInfo& result) const { + // Conservative estimate - adjust based on frame format + return result.msg_len + 10; + } + + void handleError(const std::string& error) { + log("Transport error: " + error); + } + + void handleClose() { + log("Transport closed"); + buffer_.clear(); + } + + void log(const std::string& message) { + if (debug_) { + // In a real implementation, this would use platform-specific logging + // printf("[StructFrameSdk] %s\n", message.c_str()); + } + } + +public: + StructFrameSdk(const StructFrameSdkConfig& config) + : transport_(config.transport), + frameParser_(config.frameParser), + debug_(config.debug), + maxBufferSize_(config.maxBufferSize) { + + buffer_.reserve(maxBufferSize_); + + // Set up transport callbacks + transport_->onData([this](const uint8_t* data, size_t length) { + handleIncomingData(data, length); + }); + + transport_->onError([this](const std::string& error) { + handleError(error); + }); + + transport_->onClose([this]() { + handleClose(); + }); + } + + ~StructFrameSdk() { + // Clean up observables + for (auto& pair : observables_) { + // Type-erased, would need proper cleanup in real implementation + } + } + + /** + * Connect to the transport + */ + void connect() { + transport_->connect(); + log("Connected"); + } + + /** + * Disconnect from the transport + */ + void disconnect() { + transport_->disconnect(); + log("Disconnected"); + } + + /** + * Get or create observable for a specific message type + * @tparam TMessage The message type + * @param msgId The message ID + */ + template + Observable* getObservable(uint8_t msgId) { + auto it = observables_.find(msgId); + if (it == observables_.end()) { + auto* observable = new Observable(); + observables_[msgId] = static_cast(observable); + return observable; + } + return static_cast*>(it->second); + } + + /** + * Subscribe to messages with a specific message ID + * @tparam TMessage The message type + * @param msgId The message ID + * @param observer The observer to subscribe + * @return Subscription handle (RAII) + */ + template + Subscription subscribe(uint8_t msgId, IObserver* observer) { + auto* observable = getObservable(msgId); + observable->subscribe(observer); + log("Subscribed to message ID " + std::to_string(msgId)); + return Subscription(observable, observer); + } + + /** + * Subscribe with lambda function + * @tparam TMessage The message type + * @param msgId The message ID + * @param callback Lambda to call when message is received + * @return Subscription handle (RAII) - keep alive as long as subscription is needed + */ + template + Subscription subscribe(uint8_t msgId, + std::function callback) { + auto* observer = new LambdaObserver(std::move(callback)); + auto* observable = getObservable(msgId); + observable->subscribe(observer); + log("Subscribed to message ID " + std::to_string(msgId)); + return Subscription(observable, observer); + } + + /** + * Notify observers of a parsed message (internal use) + * @tparam TMessage The message type + * @param msgId The message ID + * @param message The parsed message + */ + template + void notifyObservers(uint8_t msgId, const TMessage& message) { + auto it = observables_.find(msgId); + if (it != observables_.end()) { + auto* observable = static_cast*>(it->second); + observable->notify(message, msgId); + } + } + + /** + * Send a raw message (already serialized) + * @param msgId Message ID + * @param data Message payload + * @param dataLen Payload length + */ + void sendRaw(uint8_t msgId, const uint8_t* data, size_t dataLen) { + // Frame the message + std::vector framedData(dataLen + 20); // Extra space for framing + size_t framedLen = frameParser_->frame(msgId, data, dataLen, + framedData.data(), framedData.size()); + + transport_->send(framedData.data(), framedLen); + log("Sent message ID " + std::to_string(msgId) + ", " + + std::to_string(dataLen) + " bytes"); + } + + /** + * Send a message object (requires pack() method and msg_id member) + * @tparam TMessage Message type + * @param message The message to send + */ + template + void send(const TMessage& message) { + // Assuming message has pack method and msg_id member + std::vector packed(message.msg_size); + // User would call message.pack(packed.data()) or similar + // This is placeholder - actual implementation depends on generated code + sendRaw(message.msg_id, packed.data(), packed.size()); + } + + /** + * Check if connected + */ + bool isConnected() const { + return transport_->isConnected(); + } +}; + +} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/cpp/sdk/transport.hpp b/src/struct_frame/boilerplate/cpp/sdk/transport.hpp new file mode 100644 index 00000000..8ab67139 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/sdk/transport.hpp @@ -0,0 +1,143 @@ +// Transport interface for C++ struct-frame SDK +// Header-only implementation + +#pragma once + +#include +#include +#include +#include + +namespace StructFrame { + +/** + * Transport configuration base + */ +struct TransportConfig { + bool autoReconnect = false; + int reconnectDelayMs = 1000; + int maxReconnectAttempts = 0; // 0 = infinite +}; + +/** + * Transport interface for sending and receiving data + */ +class ITransport { +public: + using DataCallback = std::function; + using ErrorCallback = std::function; + using CloseCallback = std::function; + + virtual ~ITransport() = default; + + /** + * Connect to the transport endpoint + */ + virtual void connect() = 0; + + /** + * Disconnect from the transport endpoint + */ + virtual void disconnect() = 0; + + /** + * Send data through the transport + * @param data Pointer to data buffer + * @param length Length of data + */ + virtual void send(const uint8_t* data, size_t length) = 0; + + /** + * Set callback for receiving data + * @param callback Function to call when data is received + */ + virtual void onData(DataCallback callback) = 0; + + /** + * Set callback for connection errors + * @param callback Function to call when error occurs + */ + virtual void onError(ErrorCallback callback) = 0; + + /** + * Set callback for connection close + * @param callback Function to call when connection closes + */ + virtual void onClose(CloseCallback callback) = 0; + + /** + * Check if transport is connected + */ + virtual bool isConnected() const = 0; +}; + +/** + * Base transport with common functionality + */ +class BaseTransport : public ITransport { +protected: + bool connected_ = false; + DataCallback dataCallback_; + ErrorCallback errorCallback_; + CloseCallback closeCallback_; + TransportConfig config_; + int reconnectAttempts_ = 0; + + void handleData(const uint8_t* data, size_t length) { + if (dataCallback_) { + dataCallback_(data, length); + } + } + + void handleError(const std::string& error) { + if (errorCallback_) { + errorCallback_(error); + } + if (config_.autoReconnect && connected_) { + attemptReconnect(); + } + } + + void handleClose() { + connected_ = false; + if (closeCallback_) { + closeCallback_(); + } + if (config_.autoReconnect) { + attemptReconnect(); + } + } + + virtual void attemptReconnect() { + if (config_.maxReconnectAttempts > 0 && + reconnectAttempts_ >= config_.maxReconnectAttempts) { + return; + } + + reconnectAttempts_++; + // Reconnect logic would go here + // In practice, this would use a timer/thread to delay reconnection + } + +public: + BaseTransport(const TransportConfig& config = TransportConfig()) + : config_(config) {} + + void onData(DataCallback callback) override { + dataCallback_ = std::move(callback); + } + + void onError(ErrorCallback callback) override { + errorCallback_ = std::move(callback); + } + + void onClose(CloseCallback callback) override { + closeCallback_ = std::move(callback); + } + + bool isConnected() const override { + return connected_; + } +}; + +} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/csharp/sdk/SerialAndWebSocketTransports.cs b/src/struct_frame/boilerplate/csharp/sdk/SerialAndWebSocketTransports.cs new file mode 100644 index 00000000..b4d0f22d --- /dev/null +++ b/src/struct_frame/boilerplate/csharp/sdk/SerialAndWebSocketTransports.cs @@ -0,0 +1,266 @@ +// WebSocket and Serial transports for C# +// WebSocket uses NetCoreServer, Serial uses System.IO.Ports + +using System; +using System.Threading.Tasks; + +namespace StructFrame.Sdk +{ + /// + /// WebSocket transport configuration + /// + public class WebSocketTransportConfig : TransportConfig + { + public string Url { get; set; } + public int TimeoutMs { get; set; } = 5000; + } + + /// + /// WebSocket Transport using NetCoreServer + /// NOTE: This is a stub implementation. Full implementation requires NetCoreServer package. + /// + /// To implement: + /// 1. Install NetCoreServer NuGet package + /// 2. Inherit from NetCoreServer.WsClient + /// 3. Override OnWsConnected, OnWsDisconnected, OnWsReceived, OnWsError methods + /// + /// Example: + /// using NetCoreServer; + /// + /// public class WebSocketTransport : WsClient, ITransport + /// { + /// protected override void OnWsReceived(byte[] buffer, long offset, long size) + /// { + /// byte[] data = new byte[size]; + /// Array.Copy(buffer, offset, data, 0, size); + /// OnDataReceived(data); + /// } + /// } + /// + public class WebSocketTransport : BaseTransport + { + private readonly WebSocketTransportConfig _wsConfig; + + public WebSocketTransport(WebSocketTransportConfig config) : base(config) + { + _wsConfig = config; + } + + public override async Task ConnectAsync() + { + // Stub implementation + throw new NotImplementedException( + "WebSocket transport requires NetCoreServer package. " + + "Please see documentation for full implementation."); + } + + public override async Task DisconnectAsync() + { + await Task.CompletedTask; + } + + public override async Task SendAsync(byte[] data) + { + await Task.CompletedTask; + } + } + + /// + /// Serial transport configuration + /// + public class SerialTransportConfig : TransportConfig + { + public string PortName { get; set; } + public int BaudRate { get; set; } = 9600; + public int DataBits { get; set; } = 8; + public System.IO.Ports.Parity Parity { get; set; } = System.IO.Ports.Parity.None; + public System.IO.Ports.StopBits StopBits { get; set; } = System.IO.Ports.StopBits.One; + } + + /// + /// Serial Transport using System.IO.Ports + /// + public class SerialTransport : BaseTransport + { + private readonly SerialTransportConfig _serialConfig; + private System.IO.Ports.SerialPort _serialPort; + + public SerialTransport(SerialTransportConfig config) : base(config) + { + _serialConfig = config; + } + + public override async Task ConnectAsync() + { + try + { + _serialPort = new System.IO.Ports.SerialPort + { + PortName = _serialConfig.PortName, + BaudRate = _serialConfig.BaudRate, + DataBits = _serialConfig.DataBits, + Parity = _serialConfig.Parity, + StopBits = _serialConfig.StopBits + }; + + _serialPort.DataReceived += OnSerialDataReceived; + _serialPort.ErrorReceived += OnSerialError; + + _serialPort.Open(); + _connected = true; + + await Task.CompletedTask; + } + catch (Exception ex) + { + OnErrorOccurred(ex); + throw; + } + } + + public override async Task DisconnectAsync() + { + _connected = false; + if (_serialPort != null && _serialPort.IsOpen) + { + _serialPort.Close(); + _serialPort.Dispose(); + _serialPort = null; + } + await Task.CompletedTask; + } + + public override async Task SendAsync(byte[] data) + { + if (_serialPort == null || !_connected || !_serialPort.IsOpen) + { + throw new InvalidOperationException("Serial port not connected"); + } + + try + { + _serialPort.Write(data, 0, data.Length); + await Task.CompletedTask; + } + catch (Exception ex) + { + OnErrorOccurred(ex); + throw; + } + } + + private void OnSerialDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) + { + if (_serialPort != null && _serialPort.BytesToRead > 0) + { + byte[] buffer = new byte[_serialPort.BytesToRead]; + _serialPort.Read(buffer, 0, buffer.Length); + OnDataReceived(buffer); + } + } + + private void OnSerialError(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e) + { + OnErrorOccurred(new Exception($"Serial error: {e.EventType}")); + } + } + + /// + /// Generic serial interface for mobile applications + /// Provides abstraction for platform-specific serial implementations (e.g., Xamarin, MAUI) + /// + public interface IGenericSerialPort + { + Task OpenAsync(); + Task CloseAsync(); + Task WriteAsync(byte[] data); + Task ReadAsync(); + bool IsOpen { get; } + } + + /// + /// Generic Serial Transport for mobile/cross-platform scenarios + /// + public class GenericSerialTransport : BaseTransport + { + private readonly IGenericSerialPort _serialPort; + + public GenericSerialTransport(IGenericSerialPort serialPort, TransportConfig config = null) + : base(config) + { + _serialPort = serialPort; + } + + public override async Task ConnectAsync() + { + try + { + bool success = await _serialPort.OpenAsync(); + if (!success) + { + throw new Exception("Failed to open serial port"); + } + _connected = true; + + // Start receive loop + _ = ReceiveLoopAsync(); + } + catch (Exception ex) + { + OnErrorOccurred(ex); + throw; + } + } + + public override async Task DisconnectAsync() + { + _connected = false; + if (_serialPort.IsOpen) + { + await _serialPort.CloseAsync(); + } + } + + public override async Task SendAsync(byte[] data) + { + if (!_connected || !_serialPort.IsOpen) + { + throw new InvalidOperationException("Serial port not connected"); + } + + try + { + await _serialPort.WriteAsync(data); + } + catch (Exception ex) + { + OnErrorOccurred(ex); + throw; + } + } + + private async Task ReceiveLoopAsync() + { + while (_connected && _serialPort.IsOpen) + { + try + { + byte[] data = await _serialPort.ReadAsync(); + if (data != null && data.Length > 0) + { + OnDataReceived(data); + } + await Task.Delay(10); // Small delay to prevent tight loop + } + catch (Exception ex) + { + if (_connected) + { + OnErrorOccurred(ex); + } + break; + } + } + } + } +} diff --git a/src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs b/src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs new file mode 100644 index 00000000..59b10caf --- /dev/null +++ b/src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs @@ -0,0 +1,263 @@ +// Struct Frame SDK Client for C# +// High-level interface for sending and receiving framed messages + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace StructFrame.Sdk +{ + /// + /// Frame parser interface - must be implemented by generated frame parsers + /// + public interface IFrameParser + { + /// + /// Parse incoming data and extract message + /// + FrameMsgInfo Parse(byte[] data); + + /// + /// Frame a message for sending + /// + byte[] Frame(byte msgId, byte[] data); + } + + /// + /// Frame message info (compatible with generated parsers) + /// + public class FrameMsgInfo + { + public bool Valid { get; set; } + public byte MsgId { get; set; } + public int MsgLen { get; set; } + public byte[] MsgData { get; set; } + } + + /// + /// Message codec interface - deserializes raw bytes into message objects + /// + public interface IMessageCodec + { + byte MsgId { get; } + T Deserialize(byte[] data); + } + + /// + /// Message handler delegate + /// + public delegate void MessageHandler(T message, byte msgId); + + /// + /// Struct Frame SDK Configuration + /// + public class StructFrameSdkConfig + { + public ITransport Transport { get; set; } + public IFrameParser FrameParser { get; set; } + public bool Debug { get; set; } = false; + } + + /// + /// Main SDK Client + /// + public class StructFrameSdk + { + private readonly ITransport _transport; + private readonly IFrameParser _frameParser; + private readonly bool _debug; + private readonly Dictionary> _messageHandlers; + private readonly Dictionary _messageCodecs; + private byte[] _buffer; + + public StructFrameSdk(StructFrameSdkConfig config) + { + _transport = config.Transport; + _frameParser = config.FrameParser; + _debug = config.Debug; + _messageHandlers = new Dictionary>(); + _messageCodecs = new Dictionary(); + _buffer = Array.Empty(); + + // Set up transport callbacks + _transport.DataReceived += (sender, data) => HandleIncomingData(data); + _transport.ErrorOccurred += (sender, error) => HandleError(error); + _transport.ConnectionClosed += (sender, args) => HandleClose(); + } + + /// + /// Connect to the transport + /// + public async Task ConnectAsync() + { + await _transport.ConnectAsync(); + Log("Connected"); + } + + /// + /// Disconnect from the transport + /// + public async Task DisconnectAsync() + { + await _transport.DisconnectAsync(); + Log("Disconnected"); + } + + /// + /// Register a message codec for automatic deserialization + /// + public void RegisterCodec(IMessageCodec codec) + { + _messageCodecs[codec.MsgId] = codec; + } + + /// + /// Subscribe to messages with a specific message ID + /// + public Action Subscribe(byte msgId, MessageHandler handler) + { + if (!_messageHandlers.ContainsKey(msgId)) + { + _messageHandlers[msgId] = new List(); + } + _messageHandlers[msgId].Add(handler); + Log($"Subscribed to message ID {msgId}"); + + // Return unsubscribe action + return () => + { + if (_messageHandlers.ContainsKey(msgId)) + { + _messageHandlers[msgId].Remove(handler); + } + }; + } + + /// + /// Send a raw message (already serialized) + /// + public async Task SendRawAsync(byte msgId, byte[] data) + { + byte[] framedData = _frameParser.Frame(msgId, data); + await _transport.SendAsync(framedData); + Log($"Sent message ID {msgId}, {data.Length} bytes"); + } + + /// + /// Send a message object (requires Pack() method and MsgId property) + /// + public async Task SendAsync(T message) where T : IPackableMessage + { + byte[] data = message.Pack(); + await SendRawAsync(message.MsgId, data); + } + + /// + /// Check if connected + /// + public bool IsConnected => _transport.IsConnected; + + private void HandleIncomingData(byte[] data) + { + // Append to buffer + byte[] newBuffer = new byte[_buffer.Length + data.Length]; + Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _buffer.Length); + Buffer.BlockCopy(data, 0, newBuffer, _buffer.Length, data.Length); + _buffer = newBuffer; + + // Try to parse messages from buffer + ParseBuffer(); + } + + private void ParseBuffer() + { + while (_buffer.Length > 0) + { + FrameMsgInfo result = _frameParser.Parse(_buffer); + + if (!result.Valid) + { + // No valid frame found + break; + } + + // Valid message found + Log($"Received message ID {result.MsgId}, {result.MsgLen} bytes"); + + // Notify handlers + if (_messageHandlers.ContainsKey(result.MsgId)) + { + // Try to deserialize with registered codec + object message = result.MsgData; + if (_messageCodecs.ContainsKey(result.MsgId)) + { + try + { + var codec = _messageCodecs[result.MsgId]; + var deserializeMethod = codec.GetType().GetMethod("Deserialize"); + message = deserializeMethod.Invoke(codec, new object[] { result.MsgData }); + } + catch (Exception ex) + { + Log($"Failed to deserialize message ID {result.MsgId}: {ex.Message}"); + } + } + + // Call all handlers + foreach (var handler in _messageHandlers[result.MsgId]) + { + try + { + handler.DynamicInvoke(message, result.MsgId); + } + catch (Exception ex) + { + Log($"Handler error for message ID {result.MsgId}: {ex.Message}"); + } + } + } + + // Remove parsed data from buffer + int totalFrameSize = CalculateFrameSize(result); + byte[] newBuffer = new byte[_buffer.Length - totalFrameSize]; + Buffer.BlockCopy(_buffer, totalFrameSize, newBuffer, 0, newBuffer.Length); + _buffer = newBuffer; + } + } + + private int CalculateFrameSize(FrameMsgInfo result) + { + // Conservative estimate - adjust based on frame format + return result.MsgLen + 10; + } + + private void HandleError(Exception error) + { + Log($"Transport error: {error.Message}"); + } + + private void HandleClose() + { + Log("Transport closed"); + _buffer = Array.Empty(); + } + + private void Log(string message) + { + if (_debug) + { + Console.WriteLine($"[StructFrameSdk] {message}"); + } + } + } + + /// + /// Interface for messages that can be packed + /// + public interface IPackableMessage + { + byte MsgId { get; } + byte[] Pack(); + } +} diff --git a/src/struct_frame/boilerplate/csharp/sdk/TcpTransport.cs b/src/struct_frame/boilerplate/csharp/sdk/TcpTransport.cs new file mode 100644 index 00000000..76a6ef57 --- /dev/null +++ b/src/struct_frame/boilerplate/csharp/sdk/TcpTransport.cs @@ -0,0 +1,131 @@ +// TCP Transport implementation using NetCoreServer +// Requires: NetCoreServer NuGet package + +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace StructFrame.Sdk +{ + /// + /// TCP transport configuration + /// + public class TcpTransportConfig : TransportConfig + { + public string Host { get; set; } + public int Port { get; set; } + public int TimeoutMs { get; set; } = 5000; + } + + /// + /// TCP Transport using NetCoreServer + /// NOTE: This is a stub implementation. Full implementation requires NetCoreServer package. + /// + /// To implement: + /// 1. Install NetCoreServer NuGet package + /// 2. Inherit from NetCoreServer.TcpClient + /// 3. Override OnConnected, OnDisconnected, OnReceived, OnError methods + /// + /// Example: + /// using NetCoreServer; + /// + /// public class TcpTransport : TcpClient, ITransport + /// { + /// protected override void OnReceived(byte[] buffer, long offset, long size) + /// { + /// byte[] data = new byte[size]; + /// Array.Copy(buffer, offset, data, 0, size); + /// OnDataReceived(data); + /// } + /// } + /// + public class TcpTransport : BaseTransport + { + private readonly TcpTransportConfig _tcpConfig; + private TcpClient _client; + private NetworkStream _stream; + + public TcpTransport(TcpTransportConfig config) : base(config) + { + _tcpConfig = config; + } + + public override async Task ConnectAsync() + { + try + { + _client = new TcpClient(); + await _client.ConnectAsync(_tcpConfig.Host, _tcpConfig.Port); + _stream = _client.GetStream(); + _connected = true; + + // Start receiving + _ = ReceiveAsync(); + } + catch (Exception ex) + { + OnErrorOccurred(ex); + throw; + } + } + + public override async Task DisconnectAsync() + { + _connected = false; + _stream?.Close(); + _client?.Close(); + _stream = null; + _client = null; + await Task.CompletedTask; + } + + public override async Task SendAsync(byte[] data) + { + if (_stream == null || !_connected) + { + throw new InvalidOperationException("TCP socket not connected"); + } + + try + { + await _stream.WriteAsync(data, 0, data.Length); + await _stream.FlushAsync(); + } + catch (Exception ex) + { + OnErrorOccurred(ex); + throw; + } + } + + private async Task ReceiveAsync() + { + byte[] buffer = new byte[4096]; + while (_connected && _stream != null) + { + try + { + int bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length); + if (bytesRead == 0) + { + OnConnectionClosed(); + break; + } + + byte[] data = new byte[bytesRead]; + Array.Copy(buffer, data, bytesRead); + OnDataReceived(data); + } + catch (Exception ex) + { + if (_connected) + { + OnErrorOccurred(ex); + } + break; + } + } + } + } +} diff --git a/src/struct_frame/boilerplate/csharp/sdk/Transport.cs b/src/struct_frame/boilerplate/csharp/sdk/Transport.cs new file mode 100644 index 00000000..67bd4740 --- /dev/null +++ b/src/struct_frame/boilerplate/csharp/sdk/Transport.cs @@ -0,0 +1,130 @@ +// Transport interface for C# struct-frame SDK +// Provides abstraction for various communication channels + +using System; +using System.Threading.Tasks; + +namespace StructFrame.Sdk +{ + /// + /// Transport configuration + /// + public class TransportConfig + { + public bool AutoReconnect { get; set; } = false; + public int ReconnectDelayMs { get; set; } = 1000; + public int MaxReconnectAttempts { get; set; } = 0; // 0 = infinite + } + + /// + /// Transport interface for sending and receiving data + /// + public interface ITransport + { + /// + /// Connect to the transport endpoint + /// + Task ConnectAsync(); + + /// + /// Disconnect from the transport endpoint + /// + Task DisconnectAsync(); + + /// + /// Send data through the transport + /// + Task SendAsync(byte[] data); + + /// + /// Event fired when data is received + /// + event EventHandler DataReceived; + + /// + /// Event fired when an error occurs + /// + event EventHandler ErrorOccurred; + + /// + /// Event fired when connection closes + /// + event EventHandler ConnectionClosed; + + /// + /// Check if transport is connected + /// + bool IsConnected { get; } + } + + /// + /// Base transport with common functionality + /// + public abstract class BaseTransport : ITransport + { + protected bool _connected; + protected TransportConfig _config; + protected int _reconnectAttempts; + + public event EventHandler DataReceived; + public event EventHandler ErrorOccurred; + public event EventHandler ConnectionClosed; + + public bool IsConnected => _connected; + + protected BaseTransport(TransportConfig config = null) + { + _config = config ?? new TransportConfig(); + } + + public abstract Task ConnectAsync(); + public abstract Task DisconnectAsync(); + public abstract Task SendAsync(byte[] data); + + protected void OnDataReceived(byte[] data) + { + DataReceived?.Invoke(this, data); + } + + protected void OnErrorOccurred(Exception error) + { + ErrorOccurred?.Invoke(this, error); + if (_config.AutoReconnect && _connected) + { + _ = AttemptReconnectAsync(); + } + } + + protected void OnConnectionClosed() + { + _connected = false; + ConnectionClosed?.Invoke(this, EventArgs.Empty); + if (_config.AutoReconnect) + { + _ = AttemptReconnectAsync(); + } + } + + protected async Task AttemptReconnectAsync() + { + if (_config.MaxReconnectAttempts > 0 && + _reconnectAttempts >= _config.MaxReconnectAttempts) + { + return; + } + + _reconnectAttempts++; + await Task.Delay(_config.ReconnectDelayMs); + + try + { + await ConnectAsync(); + _reconnectAttempts = 0; + } + catch (Exception ex) + { + OnErrorOccurred(ex); + } + } + } +} diff --git a/src/struct_frame/boilerplate/csharp/sdk/UdpTransport.cs b/src/struct_frame/boilerplate/csharp/sdk/UdpTransport.cs new file mode 100644 index 00000000..eb2a34eb --- /dev/null +++ b/src/struct_frame/boilerplate/csharp/sdk/UdpTransport.cs @@ -0,0 +1,134 @@ +// UDP Transport implementation using NetCoreServer +// Requires: NetCoreServer NuGet package + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace StructFrame.Sdk +{ + /// + /// UDP transport configuration + /// + public class UdpTransportConfig : TransportConfig + { + public int LocalPort { get; set; } = 0; + public string LocalAddress { get; set; } = "0.0.0.0"; + public string RemoteHost { get; set; } + public int RemotePort { get; set; } + public bool EnableBroadcast { get; set; } = false; + } + + /// + /// UDP Transport using NetCoreServer + /// NOTE: This is a stub implementation. Full implementation requires NetCoreServer package. + /// + /// To implement: + /// 1. Install NetCoreServer NuGet package + /// 2. Inherit from NetCoreServer.UdpClient + /// 3. Override OnReceived, OnSent, OnError methods + /// + /// Example: + /// using NetCoreServer; + /// + /// public class UdpTransport : UdpClient, ITransport + /// { + /// // Implement transport interface + /// protected override void OnReceived(EndPoint endpoint, byte[] buffer, long offset, long size) + /// { + /// byte[] data = new byte[size]; + /// Array.Copy(buffer, offset, data, 0, size); + /// OnDataReceived(data); + /// } + /// } + /// + public class UdpTransport : BaseTransport + { + private readonly UdpTransportConfig _udpConfig; + private UdpClient _client; + private IPEndPoint _remoteEndpoint; + + public UdpTransport(UdpTransportConfig config) : base(config) + { + _udpConfig = config; + } + + public override async Task ConnectAsync() + { + try + { + _client = new UdpClient(_udpConfig.LocalPort); + + if (_udpConfig.EnableBroadcast) + { + _client.EnableBroadcast = true; + } + + _remoteEndpoint = new IPEndPoint( + IPAddress.Parse(_udpConfig.RemoteHost), + _udpConfig.RemotePort + ); + + _connected = true; + + // Start receiving + _ = ReceiveAsync(); + + await Task.CompletedTask; + } + catch (Exception ex) + { + OnErrorOccurred(ex); + throw; + } + } + + public override async Task DisconnectAsync() + { + _connected = false; + _client?.Close(); + _client?.Dispose(); + _client = null; + await Task.CompletedTask; + } + + public override async Task SendAsync(byte[] data) + { + if (_client == null || !_connected) + { + throw new InvalidOperationException("UDP socket not connected"); + } + + try + { + await _client.SendAsync(data, data.Length, _remoteEndpoint); + } + catch (Exception ex) + { + OnErrorOccurred(ex); + throw; + } + } + + private async Task ReceiveAsync() + { + while (_connected && _client != null) + { + try + { + var result = await _client.ReceiveAsync(); + OnDataReceived(result.Buffer); + } + catch (Exception ex) + { + if (_connected) + { + OnErrorOccurred(ex); + } + break; + } + } + } + } +} diff --git a/src/struct_frame/boilerplate/py/sdk/__init__.py b/src/struct_frame/boilerplate/py/sdk/__init__.py new file mode 100644 index 00000000..bf16227a --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/__init__.py @@ -0,0 +1,65 @@ +"""Struct Frame SDK - Python +Export all SDK components for both sync and async usage +""" + +# Sync transports +from .transport import ITransport, TransportConfig, BaseTransport +from .udp_transport import UdpTransport, UdpTransportConfig +from .tcp_transport import TcpTransport, TcpTransportConfig +from .websocket_transport import WebSocketTransport, WebSocketTransportConfig +from .serial_transport import SerialTransport, SerialTransportConfig + +# Async transports +from .async_transport import IAsyncTransport, AsyncTransportConfig, BaseAsyncTransport +from .async_udp_transport import AsyncUdpTransport, AsyncUdpTransportConfig +from .async_tcp_transport import AsyncTcpTransport, AsyncTcpTransportConfig +from .async_websocket_transport import AsyncWebSocketTransport, AsyncWebSocketTransportConfig +from .async_serial_transport import AsyncSerialTransport, AsyncSerialTransportConfig + +# SDK clients +from .struct_frame_sdk import ( + StructFrameSdk, + StructFrameSdkConfig, + IFrameParser, + IMessageCodec, + MessageHandler, +) +from .async_struct_frame_sdk import ( + AsyncStructFrameSdk, + AsyncStructFrameSdkConfig, +) + +__all__ = [ + # Sync + 'ITransport', + 'TransportConfig', + 'BaseTransport', + 'UdpTransport', + 'UdpTransportConfig', + 'TcpTransport', + 'TcpTransportConfig', + 'WebSocketTransport', + 'WebSocketTransportConfig', + 'SerialTransport', + 'SerialTransportConfig', + 'StructFrameSdk', + 'StructFrameSdkConfig', + # Async + 'IAsyncTransport', + 'AsyncTransportConfig', + 'BaseAsyncTransport', + 'AsyncUdpTransport', + 'AsyncUdpTransportConfig', + 'AsyncTcpTransport', + 'AsyncTcpTransportConfig', + 'AsyncWebSocketTransport', + 'AsyncWebSocketTransportConfig', + 'AsyncSerialTransport', + 'AsyncSerialTransportConfig', + 'AsyncStructFrameSdk', + 'AsyncStructFrameSdkConfig', + # Common + 'IFrameParser', + 'IMessageCodec', + 'MessageHandler', +] diff --git a/src/struct_frame/boilerplate/py/sdk/async_serial_transport.py b/src/struct_frame/boilerplate/py/sdk/async_serial_transport.py new file mode 100644 index 00000000..d5207660 --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/async_serial_transport.py @@ -0,0 +1,135 @@ +"""Async Serial Port Transport implementation using asyncio and pyserial""" + +import asyncio +from dataclasses import dataclass +from typing import Optional +try: + import serial +except ImportError: + serial = None + +from .async_transport import BaseAsyncTransport, AsyncTransportConfig + + +@dataclass +class AsyncSerialTransportConfig(AsyncTransportConfig): + """Async Serial transport configuration""" + port: str = '' + baudrate: int = 9600 + bytesize: int = 8 + parity: str = 'N' # 'N', 'E', 'O', 'M', 'S' + stopbits: float = 1 # 1, 1.5, 2 + timeout: float = 0.1 # Short timeout for async operations + xonxoff: bool = False + rtscts: bool = False + dsrdtr: bool = False + + +class AsyncSerialTransport(BaseAsyncTransport): + """Async Serial transport using pyserial with asyncio""" + + def __init__(self, config: AsyncSerialTransportConfig): + super().__init__(config) + if serial is None: + raise ImportError('pyserial package is required. Install with: pip install pyserial') + self.serial_config = config + self.serial_port: Optional[serial.Serial] = None + self.receive_task: Optional[asyncio.Task] = None + + async def connect(self) -> None: + """Connect serial port""" + try: + # Run serial port opening in executor to avoid blocking + loop = asyncio.get_event_loop() + self.serial_port = await loop.run_in_executor( + None, + self._open_serial_port + ) + + self.connected = True + + # Start receive task + self.receive_task = asyncio.create_task(self._receive_loop()) + + except Exception as e: + self._handle_error(e) + raise + + def _open_serial_port(self) -> serial.Serial: + """Open serial port (blocking operation)""" + port = serial.Serial( + port=self.serial_config.port, + baudrate=self.serial_config.baudrate, + bytesize=self.serial_config.bytesize, + parity=self.serial_config.parity, + stopbits=self.serial_config.stopbits, + timeout=self.serial_config.timeout, + xonxoff=self.serial_config.xonxoff, + rtscts=self.serial_config.rtscts, + dsrdtr=self.serial_config.dsrdtr + ) + + if not port.is_open: + port.open() + + return port + + async def disconnect(self) -> None: + """Disconnect serial port""" + self.connected = False + + if self.receive_task: + self.receive_task.cancel() + try: + await self.receive_task + except asyncio.CancelledError: + pass + self.receive_task = None + + if self.serial_port and self.serial_port.is_open: + loop = asyncio.get_event_loop() + await loop.run_in_executor(None, self.serial_port.close) + self.serial_port = None + + async def send(self, data: bytes) -> None: + """Send data via serial port""" + if not self.serial_port or not self.connected or not self.serial_port.is_open: + raise RuntimeError('Serial port not connected') + + try: + loop = asyncio.get_event_loop() + await loop.run_in_executor(None, self._write_serial, data) + except Exception as e: + self._handle_error(e) + raise + + def _write_serial(self, data: bytes) -> None: + """Write to serial port (blocking operation)""" + if self.serial_port: + self.serial_port.write(data) + self.serial_port.flush() + + async def _receive_loop(self) -> None: + """Receive loop""" + loop = asyncio.get_event_loop() + while self.connected and self.serial_port and self.serial_port.is_open: + try: + # Read in executor to avoid blocking + data = await loop.run_in_executor(None, self._read_serial) + if data: + self._handle_data(data) + else: + # Small delay when no data available + await asyncio.sleep(0.01) + except asyncio.CancelledError: + break + except Exception as e: + if self.connected: + self._handle_error(e) + break + + def _read_serial(self) -> bytes: + """Read from serial port (blocking operation)""" + if self.serial_port and self.serial_port.in_waiting > 0: + return self.serial_port.read(self.serial_port.in_waiting) + return b'' diff --git a/src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py b/src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py new file mode 100644 index 00000000..4801a248 --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py @@ -0,0 +1,174 @@ +"""Async Struct Frame SDK Client +High-level interface for sending and receiving framed messages using asyncio +""" + +import asyncio +from typing import Callable, Dict, List, Optional, Any, Protocol +from dataclasses import dataclass +from .async_transport import IAsyncTransport + + +class IFrameParser(Protocol): + """Frame parser interface - must be implemented by generated frame parsers""" + + def parse(self, data: bytes): + """Parse incoming data and extract message + Returns FrameMsgInfo with valid=True if message found + """ + ... + + def frame(self, msg_id: int, data: bytes) -> bytes: + """Frame a message for sending""" + ... + + +class IMessageCodec(Protocol): + """Message codec interface - deserializes raw bytes into message objects""" + + @property + def msg_id(self) -> int: + """Get message ID for this codec""" + ... + + def create_unpack(self, data: bytes) -> Any: + """Deserialize bytes into message object""" + ... + + +MessageHandler = Callable[[Any, int], None] + + +@dataclass +class AsyncStructFrameSdkConfig: + """Async Struct Frame SDK Configuration""" + transport: IAsyncTransport + frame_parser: IFrameParser + debug: bool = False + + +class AsyncStructFrameSdk: + """Main SDK Client for async operations""" + + def __init__(self, config: AsyncStructFrameSdkConfig): + self.transport = config.transport + self.frame_parser = config.frame_parser + self.debug = config.debug + self.message_handlers: Dict[int, List[MessageHandler]] = {} + self.message_codecs: Dict[int, IMessageCodec] = {} + self.buffer = b'' + + # Set up transport callbacks + self.transport.set_data_callback(self._handle_incoming_data) + self.transport.set_error_callback(self._handle_error) + self.transport.set_close_callback(self._handle_close) + + async def connect(self) -> None: + """Connect to the transport""" + await self.transport.connect() + self._log('Connected') + + async def disconnect(self) -> None: + """Disconnect from the transport""" + await self.transport.disconnect() + self._log('Disconnected') + + def register_codec(self, codec: IMessageCodec) -> None: + """Register a message codec for automatic deserialization""" + self.message_codecs[codec.msg_id] = codec + + def subscribe(self, msg_id: int, handler: MessageHandler) -> Callable[[], None]: + """Subscribe to messages with a specific message ID + + Returns an unsubscribe function + """ + if msg_id not in self.message_handlers: + self.message_handlers[msg_id] = [] + self.message_handlers[msg_id].append(handler) + self._log(f'Subscribed to message ID {msg_id}') + + # Return unsubscribe function + def unsubscribe(): + handlers = self.message_handlers.get(msg_id) + if handlers and handler in handlers: + handlers.remove(handler) + + return unsubscribe + + async def send_raw(self, msg_id: int, data: bytes) -> None: + """Send a raw message (already serialized)""" + framed_data = self.frame_parser.frame(msg_id, data) + await self.transport.send(framed_data) + self._log(f'Sent message ID {msg_id}, {len(data)} bytes') + + async def send(self, message: Any) -> None: + """Send a message object (requires pack() method and msg_id attribute)""" + data = message.pack() + await self.send_raw(message.msg_id, data) + + def is_connected(self) -> bool: + """Check if connected""" + return self.transport.is_connected() + + def _handle_incoming_data(self, data: bytes) -> None: + """Handle incoming data from transport""" + # Append to buffer + self.buffer += data + + # Try to parse messages from buffer + self._parse_buffer() + + def _parse_buffer(self) -> None: + """Parse messages from buffer""" + while len(self.buffer) > 0: + result = self.frame_parser.parse(self.buffer) + + if not result.valid: + # No valid frame found, keep buffer as is + break + + # Valid message found + self._log(f'Received message ID {result.msg_id}, {result.msg_len} bytes') + + # Notify handlers + handlers = self.message_handlers.get(result.msg_id, []) + if handlers: + # Try to deserialize with registered codec + message: Any = result.msg_data + codec = self.message_codecs.get(result.msg_id) + if codec: + try: + message = codec.create_unpack(result.msg_data) + except Exception as e: + self._log(f'Failed to deserialize message ID {result.msg_id}: {e}') + + # Call all handlers + for handler in handlers: + try: + handler(message, result.msg_id) + except Exception as e: + self._log(f'Handler error for message ID {result.msg_id}: {e}') + + # Remove parsed data from buffer + total_frame_size = self._calculate_frame_size(result) + self.buffer = self.buffer[total_frame_size:] + + def _calculate_frame_size(self, result) -> int: + """Calculate total frame size including headers and footers""" + # This is a heuristic - actual size depends on frame format + # For most formats: start bytes + header + payload + crc + # Conservative estimate + return result.msg_len + 10 # Adjust based on frame format + + def _handle_error(self, error: Exception) -> None: + """Handle transport error""" + self._log(f'Transport error: {error}') + + def _handle_close(self) -> None: + """Handle transport close""" + self._log('Transport closed') + self.buffer = b'' + + def _log(self, message: str) -> None: + """Log debug message""" + if self.debug: + print(f'[AsyncStructFrameSdk] {message}') diff --git a/src/struct_frame/boilerplate/py/sdk/async_tcp_transport.py b/src/struct_frame/boilerplate/py/sdk/async_tcp_transport.py new file mode 100644 index 00000000..abdd1705 --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/async_tcp_transport.py @@ -0,0 +1,89 @@ +"""Async TCP Transport implementation using asyncio""" + +import asyncio +from dataclasses import dataclass +from typing import Optional +from .async_transport import BaseAsyncTransport, AsyncTransportConfig + + +@dataclass +class AsyncTcpTransportConfig(AsyncTransportConfig): + """Async TCP transport configuration""" + host: str = '' + port: int = 0 + timeout: float = 5.0 + + +class AsyncTcpTransport(BaseAsyncTransport): + """Async TCP transport using asyncio""" + + def __init__(self, config: AsyncTcpTransportConfig): + super().__init__(config) + self.tcp_config = config + self.reader: Optional[asyncio.StreamReader] = None + self.writer: Optional[asyncio.StreamWriter] = None + self.receive_task: Optional[asyncio.Task] = None + + async def connect(self) -> None: + """Connect TCP socket""" + try: + self.reader, self.writer = await asyncio.wait_for( + asyncio.open_connection(self.tcp_config.host, self.tcp_config.port), + timeout=self.tcp_config.timeout + ) + self.connected = True + + # Start receive task + self.receive_task = asyncio.create_task(self._receive_loop()) + + except Exception as e: + self._handle_error(e) + raise + + async def disconnect(self) -> None: + """Disconnect TCP socket""" + self.connected = False + + if self.receive_task: + self.receive_task.cancel() + try: + await self.receive_task + except asyncio.CancelledError: + pass + self.receive_task = None + + if self.writer: + self.writer.close() + await self.writer.wait_closed() + self.writer = None + + self.reader = None + + async def send(self, data: bytes) -> None: + """Send data via TCP""" + if not self.writer or not self.connected: + raise RuntimeError('TCP socket not connected') + + try: + self.writer.write(data) + await self.writer.drain() + except Exception as e: + self._handle_error(e) + raise + + async def _receive_loop(self) -> None: + """Receive loop""" + while self.connected and self.reader: + try: + data = await self.reader.read(4096) + if not data: + # Connection closed + self._handle_close() + break + self._handle_data(data) + except asyncio.CancelledError: + break + except Exception as e: + if self.connected: + self._handle_error(e) + break diff --git a/src/struct_frame/boilerplate/py/sdk/async_transport.py b/src/struct_frame/boilerplate/py/sdk/async_transport.py new file mode 100644 index 00000000..3924f65e --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/async_transport.py @@ -0,0 +1,92 @@ +"""Async Transport interface for struct-frame SDK""" + +from abc import ABC, abstractmethod +from typing import Callable, Optional +from dataclasses import dataclass + + +@dataclass +class AsyncTransportConfig: + """Configuration for async transport layer""" + auto_reconnect: bool = False + reconnect_delay: float = 1.0 # seconds + max_reconnect_attempts: int = 0 # 0 = infinite + + +class IAsyncTransport(ABC): + """Async transport interface for sending and receiving data""" + + @abstractmethod + async def connect(self) -> None: + """Connect to the transport endpoint""" + pass + + @abstractmethod + async def disconnect(self) -> None: + """Disconnect from the transport endpoint""" + pass + + @abstractmethod + async def send(self, data: bytes) -> None: + """Send data through the transport""" + pass + + @abstractmethod + def set_data_callback(self, callback: Callable[[bytes], None]) -> None: + """Set callback for receiving data""" + pass + + @abstractmethod + def set_error_callback(self, callback: Callable[[Exception], None]) -> None: + """Set callback for connection errors""" + pass + + @abstractmethod + def set_close_callback(self, callback: Callable[[], None]) -> None: + """Set callback for connection close""" + pass + + @abstractmethod + def is_connected(self) -> bool: + """Check if transport is connected""" + pass + + +class BaseAsyncTransport(IAsyncTransport): + """Base async transport with common functionality""" + + def __init__(self, config: Optional[AsyncTransportConfig] = None): + self.config = config or AsyncTransportConfig() + self.connected = False + self.data_callback: Optional[Callable[[bytes], None]] = None + self.error_callback: Optional[Callable[[Exception], None]] = None + self.close_callback: Optional[Callable[[], None]] = None + self.reconnect_attempts = 0 + + def set_data_callback(self, callback: Callable[[bytes], None]) -> None: + self.data_callback = callback + + def set_error_callback(self, callback: Callable[[Exception], None]) -> None: + self.error_callback = callback + + def set_close_callback(self, callback: Callable[[], None]) -> None: + self.close_callback = callback + + def is_connected(self) -> bool: + return self.connected + + def _handle_data(self, data: bytes) -> None: + """Internal method to handle received data""" + if self.data_callback: + self.data_callback(data) + + def _handle_error(self, error: Exception) -> None: + """Internal method to handle errors""" + if self.error_callback: + self.error_callback(error) + + def _handle_close(self) -> None: + """Internal method to handle connection close""" + self.connected = False + if self.close_callback: + self.close_callback() diff --git a/src/struct_frame/boilerplate/py/sdk/async_udp_transport.py b/src/struct_frame/boilerplate/py/sdk/async_udp_transport.py new file mode 100644 index 00000000..a97f5a6c --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/async_udp_transport.py @@ -0,0 +1,88 @@ +"""Async UDP Transport implementation using asyncio""" + +import asyncio +from dataclasses import dataclass +from typing import Optional +from .async_transport import BaseAsyncTransport, AsyncTransportConfig + + +@dataclass +class AsyncUdpTransportConfig(AsyncTransportConfig): + """Async UDP transport configuration""" + local_port: int = 0 + local_address: str = '0.0.0.0' + remote_host: str = '' + remote_port: int = 0 + enable_broadcast: bool = False + + +class AsyncUdpProtocol(asyncio.DatagramProtocol): + """UDP protocol handler""" + + def __init__(self, transport_obj): + self.transport_obj = transport_obj + self.transport = None + + def connection_made(self, transport): + self.transport = transport + + def datagram_received(self, data, addr): + self.transport_obj._handle_data(data) + + def error_received(self, exc): + self.transport_obj._handle_error(exc) + + def connection_lost(self, exc): + if exc: + self.transport_obj._handle_error(exc) + self.transport_obj._handle_close() + + +class AsyncUdpTransport(BaseAsyncTransport): + """Async UDP transport using asyncio""" + + def __init__(self, config: AsyncUdpTransportConfig): + super().__init__(config) + self.udp_config = config + self.transport: Optional[asyncio.DatagramTransport] = None + self.protocol: Optional[AsyncUdpProtocol] = None + + async def connect(self) -> None: + """Connect (bind) UDP socket""" + try: + loop = asyncio.get_event_loop() + self.transport, self.protocol = await loop.create_datagram_endpoint( + lambda: AsyncUdpProtocol(self), + local_addr=(self.udp_config.local_address, self.udp_config.local_port) + ) + + if self.udp_config.enable_broadcast: + sock = self.transport.get_extra_info('socket') + if sock: + import socket + sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + + self.connected = True + + except Exception as e: + self._handle_error(e) + raise + + async def disconnect(self) -> None: + """Disconnect UDP socket""" + if self.transport: + self.transport.close() + self.transport = None + self.protocol = None + self.connected = False + + async def send(self, data: bytes) -> None: + """Send data via UDP""" + if not self.transport or not self.connected: + raise RuntimeError('UDP socket not connected') + + try: + self.transport.sendto(data, (self.udp_config.remote_host, self.udp_config.remote_port)) + except Exception as e: + self._handle_error(e) + raise diff --git a/src/struct_frame/boilerplate/py/sdk/async_websocket_transport.py b/src/struct_frame/boilerplate/py/sdk/async_websocket_transport.py new file mode 100644 index 00000000..5f7f7cde --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/async_websocket_transport.py @@ -0,0 +1,89 @@ +"""Async WebSocket Transport implementation using websockets""" + +import asyncio +from dataclasses import dataclass +from typing import Optional +try: + import websockets +except ImportError: + websockets = None + +from .async_transport import BaseAsyncTransport, AsyncTransportConfig + + +@dataclass +class AsyncWebSocketTransportConfig(AsyncTransportConfig): + """Async WebSocket transport configuration""" + url: str = '' + timeout: float = 5.0 + + +class AsyncWebSocketTransport(BaseAsyncTransport): + """Async WebSocket transport using websockets""" + + def __init__(self, config: AsyncWebSocketTransportConfig): + super().__init__(config) + if websockets is None: + raise ImportError('websockets package is required. Install with: pip install websockets') + self.ws_config = config + self.websocket = None + self.receive_task: Optional[asyncio.Task] = None + + async def connect(self) -> None: + """Connect WebSocket""" + try: + self.websocket = await asyncio.wait_for( + websockets.connect(self.ws_config.url), + timeout=self.ws_config.timeout + ) + self.connected = True + + # Start receive task + self.receive_task = asyncio.create_task(self._receive_loop()) + + except Exception as e: + self._handle_error(e) + raise + + async def disconnect(self) -> None: + """Disconnect WebSocket""" + self.connected = False + + if self.receive_task: + self.receive_task.cancel() + try: + await self.receive_task + except asyncio.CancelledError: + pass + self.receive_task = None + + if self.websocket: + await self.websocket.close() + self.websocket = None + + async def send(self, data: bytes) -> None: + """Send data via WebSocket""" + if not self.websocket or not self.connected: + raise RuntimeError('WebSocket not connected') + + try: + await self.websocket.send(data) + except Exception as e: + self._handle_error(e) + raise + + async def _receive_loop(self) -> None: + """Receive loop""" + while self.connected and self.websocket: + try: + message = await self.websocket.recv() + if isinstance(message, bytes): + self._handle_data(message) + elif isinstance(message, str): + self._handle_data(message.encode('utf-8')) + except asyncio.CancelledError: + break + except Exception as e: + if self.connected: + self._handle_error(e) + break diff --git a/src/struct_frame/boilerplate/py/sdk/serial_transport.py b/src/struct_frame/boilerplate/py/sdk/serial_transport.py new file mode 100644 index 00000000..00247417 --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/serial_transport.py @@ -0,0 +1,103 @@ +"""Serial Port Transport implementation using pyserial""" + +import threading +from dataclasses import dataclass +from typing import Optional +try: + import serial +except ImportError: + serial = None + +from .transport import BaseTransport, TransportConfig + + +@dataclass +class SerialTransportConfig(TransportConfig): + """Serial transport configuration""" + port: str = '' + baudrate: int = 9600 + bytesize: int = 8 + parity: str = 'N' # 'N', 'E', 'O', 'M', 'S' + stopbits: float = 1 # 1, 1.5, 2 + timeout: float = 1.0 + xonxoff: bool = False + rtscts: bool = False + dsrdtr: bool = False + + +class SerialTransport(BaseTransport): + """Serial transport using pyserial""" + + def __init__(self, config: SerialTransportConfig): + super().__init__(config) + if serial is None: + raise ImportError('pyserial package is required. Install with: pip install pyserial') + self.serial_config = config + self.serial_port: Optional[serial.Serial] = None + self.receive_thread: Optional[threading.Thread] = None + self.running = False + + def connect(self) -> None: + """Connect serial port""" + try: + self.serial_port = serial.Serial( + port=self.serial_config.port, + baudrate=self.serial_config.baudrate, + bytesize=self.serial_config.bytesize, + parity=self.serial_config.parity, + stopbits=self.serial_config.stopbits, + timeout=self.serial_config.timeout, + xonxoff=self.serial_config.xonxoff, + rtscts=self.serial_config.rtscts, + dsrdtr=self.serial_config.dsrdtr + ) + + if not self.serial_port.is_open: + self.serial_port.open() + + self.connected = True + + # Start receive thread + self.running = True + self.receive_thread = threading.Thread(target=self._receive_loop, daemon=True) + self.receive_thread.start() + + except Exception as e: + self._handle_error(e) + raise + + def disconnect(self) -> None: + """Disconnect serial port""" + self.running = False + if self.serial_port and self.serial_port.is_open: + self.serial_port.close() + self.serial_port = None + if self.receive_thread: + self.receive_thread.join(timeout=1.0) + self.receive_thread = None + self.connected = False + + def send(self, data: bytes) -> None: + """Send data via serial port""" + if not self.serial_port or not self.connected or not self.serial_port.is_open: + raise RuntimeError('Serial port not connected') + + try: + self.serial_port.write(data) + self.serial_port.flush() + except Exception as e: + self._handle_error(e) + raise + + def _receive_loop(self) -> None: + """Receive loop running in separate thread""" + while self.running and self.serial_port and self.serial_port.is_open: + try: + if self.serial_port.in_waiting > 0: + data = self.serial_port.read(self.serial_port.in_waiting) + if data: + self._handle_data(data) + except Exception as e: + if self.running: # Only handle error if still running + self._handle_error(e) + break diff --git a/src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py b/src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py new file mode 100644 index 00000000..a5a36faa --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py @@ -0,0 +1,173 @@ +"""Struct Frame SDK Client +High-level interface for sending and receiving framed messages +""" + +from typing import Callable, Dict, List, Optional, Any, Protocol +from dataclasses import dataclass +from .transport import ITransport + + +class IFrameParser(Protocol): + """Frame parser interface - must be implemented by generated frame parsers""" + + def parse(self, data: bytes): + """Parse incoming data and extract message + Returns FrameMsgInfo with valid=True if message found + """ + ... + + def frame(self, msg_id: int, data: bytes) -> bytes: + """Frame a message for sending""" + ... + + +class IMessageCodec(Protocol): + """Message codec interface - deserializes raw bytes into message objects""" + + @property + def msg_id(self) -> int: + """Get message ID for this codec""" + ... + + def create_unpack(self, data: bytes) -> Any: + """Deserialize bytes into message object""" + ... + + +MessageHandler = Callable[[Any, int], None] + + +@dataclass +class StructFrameSdkConfig: + """Struct Frame SDK Configuration""" + transport: ITransport + frame_parser: IFrameParser + debug: bool = False + + +class StructFrameSdk: + """Main SDK Client for synchronous operations""" + + def __init__(self, config: StructFrameSdkConfig): + self.transport = config.transport + self.frame_parser = config.frame_parser + self.debug = config.debug + self.message_handlers: Dict[int, List[MessageHandler]] = {} + self.message_codecs: Dict[int, IMessageCodec] = {} + self.buffer = b'' + + # Set up transport callbacks + self.transport.set_data_callback(self._handle_incoming_data) + self.transport.set_error_callback(self._handle_error) + self.transport.set_close_callback(self._handle_close) + + def connect(self) -> None: + """Connect to the transport""" + self.transport.connect() + self._log('Connected') + + def disconnect(self) -> None: + """Disconnect from the transport""" + self.transport.disconnect() + self._log('Disconnected') + + def register_codec(self, codec: IMessageCodec) -> None: + """Register a message codec for automatic deserialization""" + self.message_codecs[codec.msg_id] = codec + + def subscribe(self, msg_id: int, handler: MessageHandler) -> Callable[[], None]: + """Subscribe to messages with a specific message ID + + Returns an unsubscribe function + """ + if msg_id not in self.message_handlers: + self.message_handlers[msg_id] = [] + self.message_handlers[msg_id].append(handler) + self._log(f'Subscribed to message ID {msg_id}') + + # Return unsubscribe function + def unsubscribe(): + handlers = self.message_handlers.get(msg_id) + if handlers and handler in handlers: + handlers.remove(handler) + + return unsubscribe + + def send_raw(self, msg_id: int, data: bytes) -> None: + """Send a raw message (already serialized)""" + framed_data = self.frame_parser.frame(msg_id, data) + self.transport.send(framed_data) + self._log(f'Sent message ID {msg_id}, {len(data)} bytes') + + def send(self, message: Any) -> None: + """Send a message object (requires pack() method and msg_id attribute)""" + data = message.pack() + self.send_raw(message.msg_id, data) + + def is_connected(self) -> bool: + """Check if connected""" + return self.transport.is_connected() + + def _handle_incoming_data(self, data: bytes) -> None: + """Handle incoming data from transport""" + # Append to buffer + self.buffer += data + + # Try to parse messages from buffer + self._parse_buffer() + + def _parse_buffer(self) -> None: + """Parse messages from buffer""" + while len(self.buffer) > 0: + result = self.frame_parser.parse(self.buffer) + + if not result.valid: + # No valid frame found, keep buffer as is + break + + # Valid message found + self._log(f'Received message ID {result.msg_id}, {result.msg_len} bytes') + + # Notify handlers + handlers = self.message_handlers.get(result.msg_id, []) + if handlers: + # Try to deserialize with registered codec + message: Any = result.msg_data + codec = self.message_codecs.get(result.msg_id) + if codec: + try: + message = codec.create_unpack(result.msg_data) + except Exception as e: + self._log(f'Failed to deserialize message ID {result.msg_id}: {e}') + + # Call all handlers + for handler in handlers: + try: + handler(message, result.msg_id) + except Exception as e: + self._log(f'Handler error for message ID {result.msg_id}: {e}') + + # Remove parsed data from buffer + total_frame_size = self._calculate_frame_size(result) + self.buffer = self.buffer[total_frame_size:] + + def _calculate_frame_size(self, result) -> int: + """Calculate total frame size including headers and footers""" + # This is a heuristic - actual size depends on frame format + # For most formats: start bytes + header + payload + crc + # Conservative estimate + return result.msg_len + 10 # Adjust based on frame format + + def _handle_error(self, error: Exception) -> None: + """Handle transport error""" + self._log(f'Transport error: {error}') + + def _handle_close(self) -> None: + """Handle transport close""" + self._log('Transport closed') + self.buffer = b'' + + def _log(self, message: str) -> None: + """Log debug message""" + if self.debug: + print(f'[StructFrameSdk] {message}') diff --git a/src/struct_frame/boilerplate/py/sdk/tcp_transport.py b/src/struct_frame/boilerplate/py/sdk/tcp_transport.py new file mode 100644 index 00000000..d295a204 --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/tcp_transport.py @@ -0,0 +1,87 @@ +"""TCP Transport implementation using socket""" + +import socket +import threading +from dataclasses import dataclass +from typing import Optional +from .transport import BaseTransport, TransportConfig + + +@dataclass +class TcpTransportConfig(TransportConfig): + """TCP transport configuration""" + host: str = '' + port: int = 0 + timeout: float = 5.0 + buffer_size: int = 4096 + + +class TcpTransport(BaseTransport): + """TCP transport using socket""" + + def __init__(self, config: TcpTransportConfig): + super().__init__(config) + self.tcp_config = config + self.socket: Optional[socket.socket] = None + self.receive_thread: Optional[threading.Thread] = None + self.running = False + + def connect(self) -> None: + """Connect TCP socket""" + try: + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.settimeout(self.tcp_config.timeout) + self.socket.connect((self.tcp_config.host, self.tcp_config.port)) + self.connected = True + + # Start receive thread + self.running = True + self.receive_thread = threading.Thread(target=self._receive_loop, daemon=True) + self.receive_thread.start() + + except Exception as e: + self._handle_error(e) + raise + + def disconnect(self) -> None: + """Disconnect TCP socket""" + self.running = False + if self.socket: + try: + self.socket.shutdown(socket.SHUT_RDWR) + except: + pass + self.socket.close() + self.socket = None + if self.receive_thread: + self.receive_thread.join(timeout=1.0) + self.receive_thread = None + self.connected = False + + def send(self, data: bytes) -> None: + """Send data via TCP""" + if not self.socket or not self.connected: + raise RuntimeError('TCP socket not connected') + + try: + self.socket.sendall(data) + except Exception as e: + self._handle_error(e) + raise + + def _receive_loop(self) -> None: + """Receive loop running in separate thread""" + while self.running and self.socket: + try: + data = self.socket.recv(self.tcp_config.buffer_size) + if not data: + # Connection closed + self._handle_close() + break + self._handle_data(data) + except socket.timeout: + continue + except Exception as e: + if self.running: # Only handle error if still running + self._handle_error(e) + break diff --git a/src/struct_frame/boilerplate/py/sdk/transport.py b/src/struct_frame/boilerplate/py/sdk/transport.py new file mode 100644 index 00000000..0c7aaff2 --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/transport.py @@ -0,0 +1,115 @@ +"""Transport interface for struct-frame SDK +Provides abstraction for various communication channels +""" + +from abc import ABC, abstractmethod +from typing import Callable, Optional +from dataclasses import dataclass + + +@dataclass +class TransportConfig: + """Configuration for transport layer""" + auto_reconnect: bool = False + reconnect_delay: float = 1.0 # seconds + max_reconnect_attempts: int = 0 # 0 = infinite + + +class ITransport(ABC): + """Transport interface for sending and receiving data""" + + @abstractmethod + def connect(self) -> None: + """Connect to the transport endpoint""" + pass + + @abstractmethod + def disconnect(self) -> None: + """Disconnect from the transport endpoint""" + pass + + @abstractmethod + def send(self, data: bytes) -> None: + """Send data through the transport""" + pass + + @abstractmethod + def set_data_callback(self, callback: Callable[[bytes], None]) -> None: + """Set callback for receiving data""" + pass + + @abstractmethod + def set_error_callback(self, callback: Callable[[Exception], None]) -> None: + """Set callback for connection errors""" + pass + + @abstractmethod + def set_close_callback(self, callback: Callable[[], None]) -> None: + """Set callback for connection close""" + pass + + @abstractmethod + def is_connected(self) -> bool: + """Check if transport is connected""" + pass + + +class BaseTransport(ITransport): + """Base transport with common functionality""" + + def __init__(self, config: Optional[TransportConfig] = None): + self.config = config or TransportConfig() + self.connected = False + self.data_callback: Optional[Callable[[bytes], None]] = None + self.error_callback: Optional[Callable[[Exception], None]] = None + self.close_callback: Optional[Callable[[], None]] = None + self.reconnect_attempts = 0 + + def set_data_callback(self, callback: Callable[[bytes], None]) -> None: + self.data_callback = callback + + def set_error_callback(self, callback: Callable[[Exception], None]) -> None: + self.error_callback = callback + + def set_close_callback(self, callback: Callable[[], None]) -> None: + self.close_callback = callback + + def is_connected(self) -> bool: + return self.connected + + def _handle_data(self, data: bytes) -> None: + """Internal method to handle received data""" + if self.data_callback: + self.data_callback(data) + + def _handle_error(self, error: Exception) -> None: + """Internal method to handle errors""" + if self.error_callback: + self.error_callback(error) + if self.config.auto_reconnect and self.connected: + self._attempt_reconnect() + + def _handle_close(self) -> None: + """Internal method to handle connection close""" + self.connected = False + if self.close_callback: + self.close_callback() + if self.config.auto_reconnect: + self._attempt_reconnect() + + def _attempt_reconnect(self) -> None: + """Attempt to reconnect with backoff""" + import time + + if self.config.max_reconnect_attempts > 0 and \ + self.reconnect_attempts >= self.config.max_reconnect_attempts: + return + + self.reconnect_attempts += 1 + time.sleep(self.config.reconnect_delay) + + try: + self.connect() + self.reconnect_attempts = 0 + except Exception as e: + self._handle_error(e) diff --git a/src/struct_frame/boilerplate/py/sdk/udp_transport.py b/src/struct_frame/boilerplate/py/sdk/udp_transport.py new file mode 100644 index 00000000..46c355af --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/udp_transport.py @@ -0,0 +1,82 @@ +"""UDP Transport implementation using socket""" + +import socket +import threading +from dataclasses import dataclass +from typing import Optional +from .transport import BaseTransport, TransportConfig + + +@dataclass +class UdpTransportConfig(TransportConfig): + """UDP transport configuration""" + local_port: int = 0 + local_address: str = '0.0.0.0' + remote_host: str = '' + remote_port: int = 0 + buffer_size: int = 4096 + enable_broadcast: bool = False + + +class UdpTransport(BaseTransport): + """UDP transport using socket""" + + def __init__(self, config: UdpTransportConfig): + super().__init__(config) + self.udp_config = config + self.socket: Optional[socket.socket] = None + self.receive_thread: Optional[threading.Thread] = None + self.running = False + + def connect(self) -> None: + """Connect (bind) UDP socket""" + try: + self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + if self.udp_config.enable_broadcast: + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + + self.socket.bind((self.udp_config.local_address, self.udp_config.local_port)) + self.connected = True + + # Start receive thread + self.running = True + self.receive_thread = threading.Thread(target=self._receive_loop, daemon=True) + self.receive_thread.start() + + except Exception as e: + self._handle_error(e) + raise + + def disconnect(self) -> None: + """Disconnect UDP socket""" + self.running = False + if self.socket: + self.socket.close() + self.socket = None + if self.receive_thread: + self.receive_thread.join(timeout=1.0) + self.receive_thread = None + self.connected = False + + def send(self, data: bytes) -> None: + """Send data via UDP""" + if not self.socket or not self.connected: + raise RuntimeError('UDP socket not connected') + + try: + self.socket.sendto(data, (self.udp_config.remote_host, self.udp_config.remote_port)) + except Exception as e: + self._handle_error(e) + raise + + def _receive_loop(self) -> None: + """Receive loop running in separate thread""" + while self.running and self.socket: + try: + data, addr = self.socket.recvfrom(self.udp_config.buffer_size) + self._handle_data(data) + except Exception as e: + if self.running: # Only handle error if still running + self._handle_error(e) + break diff --git a/src/struct_frame/boilerplate/py/sdk/websocket_transport.py b/src/struct_frame/boilerplate/py/sdk/websocket_transport.py new file mode 100644 index 00000000..6caf6f3a --- /dev/null +++ b/src/struct_frame/boilerplate/py/sdk/websocket_transport.py @@ -0,0 +1,104 @@ +"""WebSocket Transport implementation using websocket-client""" + +import threading +from dataclasses import dataclass +from typing import Optional +try: + import websocket +except ImportError: + websocket = None + +from .transport import BaseTransport, TransportConfig + + +@dataclass +class WebSocketTransportConfig(TransportConfig): + """WebSocket transport configuration""" + url: str = '' + timeout: float = 5.0 + + +class WebSocketTransport(BaseTransport): + """WebSocket transport using websocket-client""" + + def __init__(self, config: WebSocketTransportConfig): + super().__init__(config) + if websocket is None: + raise ImportError('websocket-client package is required. Install with: pip install websocket-client') + self.ws_config = config + self.ws: Optional[websocket.WebSocketApp] = None + self.ws_thread: Optional[threading.Thread] = None + + def connect(self) -> None: + """Connect WebSocket""" + try: + self.ws = websocket.WebSocketApp( + self.ws_config.url, + on_open=self._on_open, + on_message=self._on_message, + on_error=self._on_error, + on_close=self._on_close + ) + + # Run WebSocket in separate thread + self.ws_thread = threading.Thread( + target=self.ws.run_forever, + kwargs={'ping_interval': 30, 'ping_timeout': 10}, + daemon=True + ) + self.ws_thread.start() + + # Wait for connection (with timeout) + import time + timeout = self.ws_config.timeout + start = time.time() + while not self.connected and time.time() - start < timeout: + time.sleep(0.1) + + if not self.connected: + raise TimeoutError('WebSocket connection timeout') + + except Exception as e: + self._handle_error(e) + raise + + def disconnect(self) -> None: + """Disconnect WebSocket""" + if self.ws: + self.ws.close() + self.ws = None + if self.ws_thread: + self.ws_thread.join(timeout=1.0) + self.ws_thread = None + self.connected = False + + def send(self, data: bytes) -> None: + """Send data via WebSocket""" + if not self.ws or not self.connected: + raise RuntimeError('WebSocket not connected') + + try: + self.ws.send(data, opcode=websocket.ABNF.OPCODE_BINARY) + except Exception as e: + self._handle_error(e) + raise + + def _on_open(self, ws) -> None: + """Called when WebSocket opens""" + self.connected = True + + def _on_message(self, ws, message) -> None: + """Called when WebSocket receives message""" + if isinstance(message, bytes): + self._handle_data(message) + elif isinstance(message, str): + self._handle_data(message.encode('utf-8')) + + def _on_error(self, ws, error) -> None: + """Called when WebSocket encounters error""" + if isinstance(error, Exception): + self._handle_error(error) + + def _on_close(self, ws, close_status_code, close_msg) -> None: + """Called when WebSocket closes""" + self._handle_close() diff --git a/src/struct_frame/boilerplate/ts/sdk/index.ts b/src/struct_frame/boilerplate/ts/sdk/index.ts new file mode 100644 index 00000000..5a4ed9a4 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/sdk/index.ts @@ -0,0 +1,15 @@ +// Struct Frame SDK - TypeScript/JavaScript +// Export all SDK components + +export { ITransport, TransportConfig, BaseTransport } from './transport'; +export { UdpTransport, UdpTransportConfig } from './udp_transport'; +export { TcpTransport, TcpTransportConfig } from './tcp_transport'; +export { WebSocketTransport, WebSocketTransportConfig } from './websocket_transport'; +export { SerialTransport, SerialTransportConfig } from './serial_transport'; +export { + StructFrameSdk, + StructFrameSdkConfig, + MessageHandler, + IFrameParser, + IMessageCodec, +} from './struct_frame_sdk'; diff --git a/src/struct_frame/boilerplate/ts/sdk/serial_transport.ts b/src/struct_frame/boilerplate/ts/sdk/serial_transport.ts new file mode 100644 index 00000000..631bae1d --- /dev/null +++ b/src/struct_frame/boilerplate/ts/sdk/serial_transport.ts @@ -0,0 +1,121 @@ +// Serial Port Transport implementation using serialport +import { SerialPort } from 'serialport'; +import { BaseTransport, TransportConfig } from './transport'; + +export interface SerialTransportConfig extends TransportConfig { + /** Serial port path (e.g., '/dev/ttyUSB0', 'COM3') */ + path: string; + /** Baud rate */ + baudRate: number; + /** Data bits (5, 6, 7, or 8) */ + dataBits?: 5 | 6 | 7 | 8; + /** Stop bits (1 or 2) */ + stopBits?: 1 | 2; + /** Parity ('none', 'even', 'odd', 'mark', or 'space') */ + parity?: 'none' | 'even' | 'odd' | 'mark' | 'space'; + /** Flow control */ + rtscts?: boolean; + /** XON/XOFF flow control */ + xon?: boolean; + xoff?: boolean; +} + +export class SerialTransport extends BaseTransport { + private port?: SerialPort; + private serialConfig: Required; + + constructor(config: SerialTransportConfig) { + super(config); + this.serialConfig = { + ...this.config, + path: config.path, + baudRate: config.baudRate, + dataBits: config.dataBits ?? 8, + stopBits: config.stopBits ?? 1, + parity: config.parity ?? 'none', + rtscts: config.rtscts ?? false, + xon: config.xon ?? false, + xoff: config.xoff ?? false, + }; + } + + async connect(): Promise { + return new Promise((resolve, reject) => { + try { + this.port = new SerialPort({ + path: this.serialConfig.path, + baudRate: this.serialConfig.baudRate, + dataBits: this.serialConfig.dataBits, + stopBits: this.serialConfig.stopBits, + parity: this.serialConfig.parity, + rtscts: this.serialConfig.rtscts, + xon: this.serialConfig.xon, + xoff: this.serialConfig.xoff, + }); + + this.port.on('open', () => { + this.connected = true; + resolve(); + }); + + this.port.on('data', (data: Buffer) => { + this.handleData(new Uint8Array(data)); + }); + + this.port.on('error', (err) => { + this.handleError(err); + if (!this.connected) { + reject(err); + } + }); + + this.port.on('close', () => { + this.handleClose(); + }); + } catch (error) { + reject(error); + } + }); + } + + async disconnect(): Promise { + return new Promise((resolve, reject) => { + if (this.port && this.port.isOpen) { + this.port.close((err) => { + if (err) { + reject(err); + } else { + this.connected = false; + resolve(); + } + }); + } else { + resolve(); + } + }); + } + + async send(data: Uint8Array): Promise { + return new Promise((resolve, reject) => { + if (!this.port || !this.connected || !this.port.isOpen) { + reject(new Error('Serial port not connected')); + return; + } + + this.port.write(Buffer.from(data), (err) => { + if (err) { + reject(err); + } else { + // Wait for drain to ensure data is sent + this.port!.drain((drainErr) => { + if (drainErr) { + reject(drainErr); + } else { + resolve(); + } + }); + } + }); + }); + } +} diff --git a/src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts b/src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts new file mode 100644 index 00000000..32f4cdc4 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts @@ -0,0 +1,220 @@ +// Struct Frame SDK Client +// High-level interface for sending and receiving framed messages + +import { ITransport } from './transport'; +import { FrameMsgInfo } from '../frame_base'; + +/** + * Message handler callback type + */ +export type MessageHandler = (message: T, msgId: number) => void; + +/** + * Frame parser interface - must be implemented by generated frame parsers + */ +export interface IFrameParser { + /** + * Parse incoming data and extract message + */ + parse(data: Uint8Array): FrameMsgInfo; + + /** + * Frame a message for sending + */ + frame(msgId: number, data: Uint8Array): Uint8Array; +} + +/** + * Message codec interface - deserializes raw bytes into message objects + */ +export interface IMessageCodec { + /** + * Get message ID for this codec + */ + getMsgId(): number; + + /** + * Deserialize bytes into message object + */ + deserialize(data: Uint8Array): T; +} + +/** + * Struct Frame SDK Configuration + */ +export interface StructFrameSdkConfig { + /** Transport layer */ + transport: ITransport; + /** Frame parser */ + frameParser: IFrameParser; + /** Enable debug logging */ + debug?: boolean; +} + +/** + * Main SDK Client + */ +export class StructFrameSdk { + private transport: ITransport; + private frameParser: IFrameParser; + private debug: boolean; + private messageHandlers: Map = new Map(); + private messageCodecs: Map = new Map(); + private buffer: Uint8Array = new Uint8Array(0); + + constructor(config: StructFrameSdkConfig) { + this.transport = config.transport; + this.frameParser = config.frameParser; + this.debug = config.debug ?? false; + + // Set up transport callbacks + this.transport.onData((data) => this.handleIncomingData(data)); + this.transport.onError((error) => this.handleError(error)); + this.transport.onClose(() => this.handleClose()); + } + + /** + * Connect to the transport + */ + async connect(): Promise { + await this.transport.connect(); + this.log('Connected'); + } + + /** + * Disconnect from the transport + */ + async disconnect(): Promise { + await this.transport.disconnect(); + this.log('Disconnected'); + } + + /** + * Register a message codec for automatic deserialization + */ + registerCodec(codec: IMessageCodec): void { + this.messageCodecs.set(codec.getMsgId(), codec); + } + + /** + * Subscribe to messages with a specific message ID + */ + subscribe(msgId: number, handler: MessageHandler): () => void { + if (!this.messageHandlers.has(msgId)) { + this.messageHandlers.set(msgId, []); + } + this.messageHandlers.get(msgId)!.push(handler); + this.log(`Subscribed to message ID ${msgId}`); + + // Return unsubscribe function + return () => { + const handlers = this.messageHandlers.get(msgId); + if (handlers) { + const index = handlers.indexOf(handler); + if (index > -1) { + handlers.splice(index, 1); + } + } + }; + } + + /** + * Send a raw message (already serialized) + */ + async sendRaw(msgId: number, data: Uint8Array): Promise { + const framedData = this.frameParser.frame(msgId, data); + await this.transport.send(framedData); + this.log(`Sent message ID ${msgId}, ${data.length} bytes`); + } + + /** + * Send a message object (requires pack() method) + */ + async send(message: T): Promise { + const data = message.pack(); + await this.sendRaw(message.msg_id, data); + } + + /** + * Check if connected + */ + isConnected(): boolean { + return this.transport.isConnected(); + } + + private handleIncomingData(data: Uint8Array): void { + // Append to buffer + const newBuffer = new Uint8Array(this.buffer.length + data.length); + newBuffer.set(this.buffer); + newBuffer.set(data, this.buffer.length); + this.buffer = newBuffer; + + // Try to parse messages from buffer + this.parseBuffer(); + } + + private parseBuffer(): void { + while (this.buffer.length > 0) { + const result = this.frameParser.parse(this.buffer); + + if (!result.valid) { + // No valid frame found, keep buffer as is + break; + } + + // Valid message found + this.log(`Received message ID ${result.msg_id}, ${result.msg_len} bytes`); + + // Notify handlers + const handlers = this.messageHandlers.get(result.msg_id); + if (handlers && handlers.length > 0) { + // Try to deserialize with registered codec + let message: any = result.msg_data; + const codec = this.messageCodecs.get(result.msg_id); + if (codec) { + try { + message = codec.deserialize(result.msg_data); + } catch (error) { + this.log(`Failed to deserialize message ID ${result.msg_id}: ${error}`); + } + } + + // Call all handlers + handlers.forEach(handler => { + try { + handler(message, result.msg_id); + } catch (error) { + this.log(`Handler error for message ID ${result.msg_id}: ${error}`); + } + }); + } + + // Remove parsed data from buffer + const totalFrameSize = this.calculateFrameSize(result); + this.buffer = this.buffer.slice(totalFrameSize); + } + } + + private calculateFrameSize(result: FrameMsgInfo): number { + // This is a heuristic - actual size depends on frame format + // For most formats: start bytes + header + payload + crc + // The parser should ideally tell us the exact frame size + // For now, we'll use a conservative estimate + return result.msg_len + 10; // Adjust based on frame format + } + + private handleError(error: Error): void { + this.log(`Transport error: ${error.message}`); + } + + private handleClose(): void { + this.log('Transport closed'); + this.buffer = new Uint8Array(0); + } + + private log(message: string): void { + if (this.debug) { + console.log(`[StructFrameSdk] ${message}`); + } + } +} diff --git a/src/struct_frame/boilerplate/ts/sdk/tcp_transport.ts b/src/struct_frame/boilerplate/ts/sdk/tcp_transport.ts new file mode 100644 index 00000000..16089a19 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/sdk/tcp_transport.ts @@ -0,0 +1,95 @@ +// TCP Transport implementation using Node.js net +import * as net from 'net'; +import { BaseTransport, TransportConfig } from './transport'; + +export interface TcpTransportConfig extends TransportConfig { + /** Remote host to connect to */ + host: string; + /** Remote port to connect to */ + port: number; + /** Connection timeout in milliseconds */ + timeout?: number; +} + +export class TcpTransport extends BaseTransport { + private socket?: net.Socket; + private tcpConfig: Required; + + constructor(config: TcpTransportConfig) { + super(config); + this.tcpConfig = { + ...this.config, + host: config.host, + port: config.port, + timeout: config.timeout ?? 5000, + }; + } + + async connect(): Promise { + return new Promise((resolve, reject) => { + try { + this.socket = new net.Socket(); + this.socket.setTimeout(this.tcpConfig.timeout); + + this.socket.on('connect', () => { + this.connected = true; + resolve(); + }); + + this.socket.on('data', (data) => { + this.handleData(new Uint8Array(data)); + }); + + this.socket.on('error', (err) => { + this.handleError(err); + if (!this.connected) { + reject(err); + } + }); + + this.socket.on('close', () => { + this.handleClose(); + }); + + this.socket.on('timeout', () => { + this.handleError(new Error('TCP connection timeout')); + this.socket?.destroy(); + }); + + this.socket.connect(this.tcpConfig.port, this.tcpConfig.host); + } catch (error) { + reject(error); + } + }); + } + + async disconnect(): Promise { + return new Promise((resolve) => { + if (this.socket) { + this.socket.end(() => { + this.connected = false; + resolve(); + }); + } else { + resolve(); + } + }); + } + + async send(data: Uint8Array): Promise { + return new Promise((resolve, reject) => { + if (!this.socket || !this.connected) { + reject(new Error('TCP socket not connected')); + return; + } + + this.socket.write(Buffer.from(data), (err) => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + } +} diff --git a/src/struct_frame/boilerplate/ts/sdk/transport.ts b/src/struct_frame/boilerplate/ts/sdk/transport.ts new file mode 100644 index 00000000..eab7533c --- /dev/null +++ b/src/struct_frame/boilerplate/ts/sdk/transport.ts @@ -0,0 +1,131 @@ +// Transport interface for struct-frame SDK +// Provides abstraction for various communication channels + +export interface ITransport { + /** + * Connect to the transport endpoint + */ + connect(): Promise; + + /** + * Disconnect from the transport endpoint + */ + disconnect(): Promise; + + /** + * Send data through the transport + * @param data - Data to send + */ + send(data: Uint8Array): Promise; + + /** + * Set callback for receiving data + * @param callback - Function to call when data is received + */ + onData(callback: (data: Uint8Array) => void): void; + + /** + * Set callback for connection errors + * @param callback - Function to call when error occurs + */ + onError(callback: (error: Error) => void): void; + + /** + * Set callback for connection close + * @param callback - Function to call when connection closes + */ + onClose(callback: () => void): void; + + /** + * Check if transport is connected + */ + isConnected(): boolean; +} + +export interface TransportConfig { + /** Auto-reconnect on connection loss */ + autoReconnect?: boolean; + /** Reconnection delay in milliseconds */ + reconnectDelay?: number; + /** Maximum reconnection attempts (0 = infinite) */ + maxReconnectAttempts?: number; +} + +export abstract class BaseTransport implements ITransport { + protected connected: boolean = false; + protected dataCallback?: (data: Uint8Array) => void; + protected errorCallback?: (error: Error) => void; + protected closeCallback?: () => void; + protected config: Required; + protected reconnectAttempts: number = 0; + + constructor(config?: TransportConfig) { + this.config = { + autoReconnect: config?.autoReconnect ?? false, + reconnectDelay: config?.reconnectDelay ?? 1000, + maxReconnectAttempts: config?.maxReconnectAttempts ?? 0, + }; + } + + abstract connect(): Promise; + abstract disconnect(): Promise; + abstract send(data: Uint8Array): Promise; + + onData(callback: (data: Uint8Array) => void): void { + this.dataCallback = callback; + } + + onError(callback: (error: Error) => void): void { + this.errorCallback = callback; + } + + onClose(callback: () => void): void { + this.closeCallback = callback; + } + + isConnected(): boolean { + return this.connected; + } + + protected handleData(data: Uint8Array): void { + if (this.dataCallback) { + this.dataCallback(data); + } + } + + protected handleError(error: Error): void { + if (this.errorCallback) { + this.errorCallback(error); + } + if (this.config.autoReconnect && this.connected) { + this.attemptReconnect(); + } + } + + protected handleClose(): void { + this.connected = false; + if (this.closeCallback) { + this.closeCallback(); + } + if (this.config.autoReconnect) { + this.attemptReconnect(); + } + } + + protected async attemptReconnect(): Promise { + if (this.config.maxReconnectAttempts > 0 && + this.reconnectAttempts >= this.config.maxReconnectAttempts) { + return; + } + + this.reconnectAttempts++; + await new Promise(resolve => setTimeout(resolve, this.config.reconnectDelay)); + + try { + await this.connect(); + this.reconnectAttempts = 0; + } catch (error) { + this.handleError(error as Error); + } + } +} diff --git a/src/struct_frame/boilerplate/ts/sdk/udp_transport.ts b/src/struct_frame/boilerplate/ts/sdk/udp_transport.ts new file mode 100644 index 00000000..3f68d8cc --- /dev/null +++ b/src/struct_frame/boilerplate/ts/sdk/udp_transport.ts @@ -0,0 +1,102 @@ +// UDP Transport implementation using Node.js dgram +import * as dgram from 'dgram'; +import { BaseTransport, TransportConfig } from './transport'; + +export interface UdpTransportConfig extends TransportConfig { + /** Local port to bind to */ + localPort?: number; + /** Local address to bind to */ + localAddress?: string; + /** Remote host to send to */ + remoteHost: string; + /** Remote port to send to */ + remotePort: number; + /** Socket type: 'udp4' or 'udp6' */ + socketType?: 'udp4' | 'udp6'; + /** Enable broadcast */ + broadcast?: boolean; +} + +export class UdpTransport extends BaseTransport { + private socket?: dgram.Socket; + private udpConfig: Required; + + constructor(config: UdpTransportConfig) { + super(config); + this.udpConfig = { + ...this.config, + localPort: config.localPort ?? 0, + localAddress: config.localAddress ?? '0.0.0.0', + remoteHost: config.remoteHost, + remotePort: config.remotePort, + socketType: config.socketType ?? 'udp4', + broadcast: config.broadcast ?? false, + }; + } + + async connect(): Promise { + return new Promise((resolve, reject) => { + try { + this.socket = dgram.createSocket(this.udpConfig.socketType); + + this.socket.on('message', (msg) => { + this.handleData(new Uint8Array(msg)); + }); + + this.socket.on('error', (err) => { + this.handleError(err); + reject(err); + }); + + this.socket.on('close', () => { + this.handleClose(); + }); + + this.socket.bind(this.udpConfig.localPort, this.udpConfig.localAddress, () => { + if (this.socket && this.udpConfig.broadcast) { + this.socket.setBroadcast(true); + } + this.connected = true; + resolve(); + }); + } catch (error) { + reject(error); + } + }); + } + + async disconnect(): Promise { + return new Promise((resolve) => { + if (this.socket) { + this.socket.close(() => { + this.connected = false; + resolve(); + }); + } else { + resolve(); + } + }); + } + + async send(data: Uint8Array): Promise { + return new Promise((resolve, reject) => { + if (!this.socket || !this.connected) { + reject(new Error('UDP socket not connected')); + return; + } + + this.socket.send( + Buffer.from(data), + this.udpConfig.remotePort, + this.udpConfig.remoteHost, + (err) => { + if (err) { + reject(err); + } else { + resolve(); + } + } + ); + }); + } +} diff --git a/src/struct_frame/boilerplate/ts/sdk/websocket_transport.ts b/src/struct_frame/boilerplate/ts/sdk/websocket_transport.ts new file mode 100644 index 00000000..8f5c97ee --- /dev/null +++ b/src/struct_frame/boilerplate/ts/sdk/websocket_transport.ts @@ -0,0 +1,100 @@ +// WebSocket Transport implementation using WebSocket API +import { BaseTransport, TransportConfig } from './transport'; + +export interface WebSocketTransportConfig extends TransportConfig { + /** WebSocket URL (ws:// or wss://) */ + url: string; + /** WebSocket protocols */ + protocols?: string | string[]; +} + +export class WebSocketTransport extends BaseTransport { + private ws?: WebSocket; + private wsConfig: Required; + + constructor(config: WebSocketTransportConfig) { + super(config); + this.wsConfig = { + ...this.config, + url: config.url, + protocols: config.protocols ?? [], + }; + } + + async connect(): Promise { + return new Promise((resolve, reject) => { + try { + // Use global WebSocket (works in both browser and Node.js with ws package) + this.ws = new WebSocket(this.wsConfig.url, this.wsConfig.protocols); + this.ws.binaryType = 'arraybuffer'; + + this.ws.onopen = () => { + this.connected = true; + resolve(); + }; + + this.ws.onmessage = (event) => { + let data: Uint8Array; + if (event.data instanceof ArrayBuffer) { + data = new Uint8Array(event.data); + } else if (event.data instanceof Blob) { + // Handle blob asynchronously + event.data.arrayBuffer().then(buffer => { + this.handleData(new Uint8Array(buffer)); + }); + return; + } else { + // String data - convert to bytes + const encoder = new TextEncoder(); + data = encoder.encode(event.data); + } + this.handleData(data); + }; + + this.ws.onerror = (event) => { + const error = new Error('WebSocket error'); + this.handleError(error); + if (!this.connected) { + reject(error); + } + }; + + this.ws.onclose = () => { + this.handleClose(); + }; + } catch (error) { + reject(error); + } + }); + } + + async disconnect(): Promise { + return new Promise((resolve) => { + if (this.ws) { + if (this.ws.readyState === WebSocket.OPEN) { + this.ws.close(); + } + this.connected = false; + resolve(); + } else { + resolve(); + } + }); + } + + async send(data: Uint8Array): Promise { + return new Promise((resolve, reject) => { + if (!this.ws || !this.connected || this.ws.readyState !== WebSocket.OPEN) { + reject(new Error('WebSocket not connected')); + return; + } + + try { + this.ws.send(data); + resolve(); + } catch (error) { + reject(error); + } + }); + } +} From 938717f0867ff4bec6186cddb54e4a897548bd42 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:55:06 +0000 Subject: [PATCH 3/9] Add comprehensive SDK documentation for all languages Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- README.md | 11 + docs/user-guide/cpp-sdk.md | 439 +++++++++++++++++++++++++++ docs/user-guide/csharp-sdk.md | 487 ++++++++++++++++++++++++++++++ docs/user-guide/python-sdk.md | 396 ++++++++++++++++++++++++ docs/user-guide/sdk-overview.md | 191 ++++++++++++ docs/user-guide/typescript-sdk.md | 284 +++++++++++++++++ mkdocs.yml | 5 + 7 files changed, 1813 insertions(+) create mode 100644 docs/user-guide/cpp-sdk.md create mode 100644 docs/user-guide/csharp-sdk.md create mode 100644 docs/user-guide/python-sdk.md create mode 100644 docs/user-guide/sdk-overview.md create mode 100644 docs/user-guide/typescript-sdk.md diff --git a/README.md b/README.md index 0d22f3c2..3467343d 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,17 @@ The CI pipeline: You can view test results in the "Actions" tab of the GitHub repository. Test artifacts (generated code and binary files) are available for download for 5 days after each run. +## Higher-Level SDK + +Struct Frame provides high-level SDKs for simplified message communication: + +- **TypeScript/JavaScript**: Promise-based with UDP, TCP, WebSocket, and Serial transports +- **Python**: Both sync and async implementations with socket, pyserial, websockets support +- **C++**: Header-only with observer/subscriber pattern, ideal for embedded systems +- **C#**: Async/await-based for .NET Core, Xamarin, and MAUI applications + +See the [SDK Overview](https://struct-frame.mylonics.com/user-guide/sdk-overview/) for details. + ## Framing System Struct Frame provides a message framing system for reliable communication over serial links, network sockets, or any byte stream. Framing solves the fundamental problem of determining where messages begin and end in a continuous data stream. diff --git a/docs/user-guide/cpp-sdk.md b/docs/user-guide/cpp-sdk.md new file mode 100644 index 00000000..c6d17ca6 --- /dev/null +++ b/docs/user-guide/cpp-sdk.md @@ -0,0 +1,439 @@ +# C++ SDK + +The C++ SDK is a header-only library that provides structured message communication with an observer/subscriber pattern for message handling. + +## Features + +- **Header-only**: No linking required, just include headers +- **Zero dependencies**: Core SDK has no external dependencies +- **Observer pattern**: Type-safe message subscription inspired by ETLCPP +- **Embedded-friendly**: Generic serial interface for bare-metal systems +- **Network support**: UDP, TCP, WebSocket via optional ASIO integration + +## Installation + +The SDK is automatically included when you generate C++ code: + +```bash +python -m struct_frame your_messages.proto --build_cpp --cpp_path generated/cpp +``` + +Include the SDK in your project: + +```cpp +#include "sdk/sdk.hpp" +``` + +## Observer/Subscriber Pattern + +The C++ SDK uses an observer pattern for handling messages, providing type-safe subscriptions without dynamic allocation overhead. + +### Basic Observer + +```cpp +#include "sdk/observer.hpp" +#include "my_messages.hpp" + +using namespace StructFrame; + +class StatusObserver : public IObserver { +public: + void onMessage(const StatusMessage& message, uint8_t msgId) override { + // Handle message + std::cout << "Temperature: " << message.temperature << std::endl; + } +}; + +// Usage +StatusObserver observer; +auto* observable = sdk.getObservable(StatusMessage::msg_id); +observable->subscribe(&observer); +``` + +### Lambda Observer + +For simpler use cases, use lambda-based observers: + +```cpp +auto subscription = sdk.subscribe( + StatusMessage::msg_id, + [](const StatusMessage& msg, uint8_t msgId) { + std::cout << "Battery: " << msg.battery << "%" << std::endl; + } +); +// Subscription is automatically cleaned up when 'subscription' goes out of scope +``` + +### RAII Subscription + +The `Subscription` class provides automatic unsubscription: + +```cpp +{ + auto subscription = sdk.subscribe( + StatusMessage::msg_id, + [](const StatusMessage& msg, uint8_t msgId) { + // Handle message + } + ); + + // subscription automatically unsubscribes when it goes out of scope +} +``` + +## Transport Layers + +### Generic Serial Transport (Embedded Systems) + +The generic serial interface allows you to implement platform-specific serial I/O: + +```cpp +#include "sdk/serial_transport.hpp" + +// Implement for your platform +class STM32SerialPort : public StructFrame::ISerialPort { +private: + UART_HandleTypeDef* huart_; + +public: + STM32SerialPort(UART_HandleTypeDef* huart) : huart_(huart) {} + + bool open() override { + // Already initialized in HAL_UART_MspInit + return true; + } + + void close() override { + // Optionally deinitialize + } + + size_t write(const uint8_t* data, size_t length) override { + HAL_StatusTypeDef status = HAL_UART_Transmit( + huart_, + const_cast(data), + length, + HAL_MAX_DELAY + ); + return (status == HAL_OK) ? length : 0; + } + + size_t read(uint8_t* buffer, size_t maxLength) override { + // Non-blocking read + size_t available = __HAL_UART_GET_FLAG(huart_, UART_FLAG_RXNE) ? 1 : 0; + if (available > 0 && maxLength > 0) { + HAL_UART_Receive(huart_, buffer, 1, 0); + return 1; + } + return 0; + } + + bool isOpen() const override { + return true; + } + + size_t available() const override { + return __HAL_UART_GET_FLAG(huart_, UART_FLAG_RXNE) ? 1 : 0; + } +}; + +// Usage +STM32SerialPort serialPort(&huart1); +StructFrame::SerialTransport transport(&serialPort); +``` + +### Poll-Based Operation (Embedded) + +For embedded systems without threading, use poll-based message handling: + +```cpp +#include "sdk/struct_frame_sdk.hpp" +#include "BasicDefault.hpp" +#include "my_messages.hpp" + +using namespace StructFrame; + +int main() { + // Setup + STM32SerialPort serialPort(&huart1); + SerialTransport transport(&serialPort); + BasicDefault frameParser; + + StructFrameSdk sdk({ + .transport = &transport, + .frameParser = &frameParser, + .debug = false, + }); + + // Subscribe to messages + auto sub = sdk.subscribe( + StatusMessage::msg_id, + [](const StatusMessage& msg, uint8_t id) { + // Handle status + } + ); + + sdk.connect(); + + // Main loop + while (1) { + // Poll for incoming data + transport.poll(); + + // Your other application logic + HAL_Delay(1); + } +} +``` + +## Network Transports (ASIO) + +For desktop/server applications, network transports use ASIO. These require external libraries. + +### UDP Transport (with ASIO) + +```cpp +// Requires: ASIO standalone or Boost.Asio +// Not included in generated code - implement based on network_transports.hpp + +#include +#include "sdk/transport.hpp" + +class UdpTransport : public StructFrame::BaseTransport { +private: + asio::io_context io_context_; + asio::ip::udp::socket socket_; + asio::ip::udp::endpoint remote_endpoint_; + +public: + UdpTransport(const std::string& host, uint16_t port) + : socket_(io_context_, asio::ip::udp::endpoint(asio::ip::udp::v4(), 0)) { + remote_endpoint_ = asio::ip::udp::endpoint( + asio::ip::address::from_string(host), port); + } + + void connect() override { + connected_ = true; + startReceive(); + } + + void send(const uint8_t* data, size_t length) override { + socket_.send_to(asio::buffer(data, length), remote_endpoint_); + } + + // ... implement startReceive() with async operations +}; +``` + +### TCP Transport (with ASIO) + +See `network_transports.hpp` for implementation guidelines. + +### WebSocket Transport (with Simple-WebSocket-Server) + +```cpp +// Requires: Simple-WebSocket-Server and ASIO +#include "client_ws.hpp" + +using WsClient = SimpleWeb::SocketClient; + +class WebSocketTransport : public StructFrame::BaseTransport { + // Implement based on Simple-WebSocket-Server documentation +}; +``` + +## Complete Example + +```cpp +#include "sdk/sdk.hpp" +#include "BasicDefault.hpp" +#include "robot_messages.hpp" + +using namespace StructFrame; +using namespace RobotMessages; + +int main() { + // Platform-specific serial port + MySerialPort serialPort("/dev/ttyUSB0", 115200); + SerialTransport transport(&serialPort); + + // Frame parser + BasicDefault frameParser; + + // Create SDK + StructFrameSdk sdk({ + .transport = &transport, + .frameParser = &frameParser, + .debug = true, + .maxBufferSize = 8192, + }); + + // Subscribe to status messages + auto statusSub = sdk.subscribe( + StatusMessage::msg_id, + [](const StatusMessage& msg, uint8_t msgId) { + std::cout << "Temp: " << msg.temperature << "°C" << std::endl; + std::cout << "Battery: " << msg.battery << "%" << std::endl; + } + ); + + // Subscribe to telemetry + auto telemetrySub = sdk.subscribe( + TelemetryMessage::msg_id, + [](const TelemetryMessage& msg, uint8_t msgId) { + std::cout << "Position: (" << msg.x << ", " << msg.y << ")" << std::endl; + } + ); + + // Connect + sdk.connect(); + + // Send command + CommandMessage cmd; + cmd.command = Command::MOVE_FORWARD; + cmd.speed = 50; + + std::vector packed(cmd.msg_size); + cmd.pack(packed.data()); + sdk.sendRaw(CommandMessage::msg_id, packed.data(), packed.size()); + + // Main loop (embedded systems) + while (true) { + transport.poll(); + + // ... other application logic + } + + return 0; +} +``` + +## Memory Considerations + +The C++ SDK is designed for resource-constrained systems: + +- **No dynamic allocation in message handling**: Observer pattern uses vectors allocated at initialization +- **Configurable buffer size**: Set `maxBufferSize` based on your requirements +- **Header-only**: No linking overhead +- **Small footprint**: Core SDK is ~10KB compiled + +```cpp +// Configure buffer size for your application +StructFrameSdk sdk({ + .transport = &transport, + .frameParser = &frameParser, + .maxBufferSize = 1024, // Smaller buffer for constrained systems +}); +``` + +## Platform Support + +The SDK works on: + +- **Embedded**: ARM Cortex-M, AVR, ESP32, etc. +- **Desktop**: Linux, Windows, macOS +- **Real-time OS**: FreeRTOS, Zephyr, etc. +- **Bare-metal**: Any platform with C++14 support + +## Dependencies + +### Core SDK +- C++14 or later +- No external dependencies + +### Network Transports (Optional) +- **UDP/TCP**: ASIO standalone or Boost.Asio +- **WebSocket**: Simple-WebSocket-Server (requires ASIO) +- **Serial (ASIO)**: ASIO standalone or Boost.Asio + +```bash +# Install ASIO (standalone, header-only) +wget https://github.com/chriskohlhoff/asio/archive/asio-1-28-0.tar.gz +tar xzf asio-1-28-0.tar.gz +cp -r asio-asio-1-28-0/asio/include/asio* /usr/local/include/ + +# Or use package manager +# Ubuntu/Debian: +sudo apt-get install libasio-dev + +# macOS: +brew install asio +``` + +## Compiler Flags + +```bash +# Minimum flags +g++ -std=c++14 main.cpp -o app + +# With ASIO +g++ -std=c++14 -DASIO_STANDALONE main.cpp -o app -lpthread + +# Optimized for embedded +arm-none-eabi-g++ -std=c++14 -Os -fno-exceptions -fno-rtti main.cpp -o app.elf +``` + +## Best Practices + +1. **Use RAII**: Let `Subscription` handle unsubscription automatically +2. **Minimize copies**: Pass messages by const reference in observers +3. **Poll regularly**: Call `transport.poll()` frequently in main loop for embedded systems +4. **Buffer management**: Size buffer appropriately for your message sizes +5. **Error handling**: Check connection status and handle errors in callbacks + +## Example Platform Implementations + +### Arduino/ESP32 + +```cpp +#include +#include "sdk/serial_transport.hpp" + +class ArduinoSerialPort : public StructFrame::ISerialPort { +private: + HardwareSerial* serial_; + +public: + ArduinoSerialPort(HardwareSerial* serial) : serial_(serial) {} + + bool open() override { + // Already opened in setup() + return true; + } + + size_t write(const uint8_t* data, size_t length) override { + return serial_->write(data, length); + } + + size_t read(uint8_t* buffer, size_t maxLength) override { + return serial_->readBytes(buffer, maxLength); + } + + size_t available() const override { + return serial_->available(); + } +}; + +void setup() { + Serial.begin(115200); + ArduinoSerialPort port(&Serial); + // ... setup SDK +} + +void loop() { + transport.poll(); + delay(1); +} +``` + +### Linux + +```cpp +#include +#include +#include + +class LinuxSerialPort : public StructFrame::ISerialPort { + // Implement using POSIX serial I/O + // See termios documentation +}; +``` diff --git a/docs/user-guide/csharp-sdk.md b/docs/user-guide/csharp-sdk.md new file mode 100644 index 00000000..f91380a3 --- /dev/null +++ b/docs/user-guide/csharp-sdk.md @@ -0,0 +1,487 @@ +# C# SDK + +The C# SDK provides an async/await-based interface for structured message communication using .NET Standard 2.0+. + +## Features + +- **Async/await**: Modern C# asynchronous patterns +- **Event-based**: Standard .NET event model for messages +- **Cross-platform**: Works on .NET Core, .NET 5+, Xamarin, MAUI +- **Mobile-friendly**: Generic serial interface for mobile apps + +## Installation + +The SDK is automatically included when you generate C# code: + +```bash +python -m struct_frame your_messages.proto --build_csharp --csharp_path generated/csharp +``` + +## Available Transports + +### UDP Transport + +Uses standard `UdpClient`: + +```csharp +using StructFrame.Sdk; + +var transport = new UdpTransport(new UdpTransportConfig +{ + RemoteHost = "192.168.1.100", + RemotePort = 5000, + LocalPort = 5001, + LocalAddress = "0.0.0.0", + EnableBroadcast = false, + AutoReconnect = true, + ReconnectDelayMs = 1000, + MaxReconnectAttempts = 5, +}); +``` + +### TCP Transport + +Uses standard `TcpClient`: + +```csharp +var transport = new TcpTransport(new TcpTransportConfig +{ + Host = "192.168.1.100", + Port = 5000, + TimeoutMs = 5000, + AutoReconnect = true, +}); +``` + +### WebSocket Transport + +Requires `NetCoreServer` NuGet package: + +```csharp +var transport = new WebSocketTransport(new WebSocketTransportConfig +{ + Url = "ws://localhost:8080", + TimeoutMs = 5000, +}); +``` + +### Serial Transport + +Uses `System.IO.Ports.SerialPort`: + +```csharp +var transport = new SerialTransport(new SerialTransportConfig +{ + PortName = "COM3", // or "/dev/ttyUSB0" on Linux + BaudRate = 115200, + DataBits = 8, + Parity = System.IO.Ports.Parity.None, + StopBits = System.IO.Ports.StopBits.One, +}); +``` + +### Generic Serial Transport (Mobile) + +For Xamarin/MAUI applications, implement `IGenericSerialPort`: + +```csharp +// Your platform-specific implementation +public class XamarinSerialPort : IGenericSerialPort +{ + // Implement serial I/O for your platform +} + +var serialPort = new XamarinSerialPort(); +var transport = new GenericSerialTransport(serialPort); +``` + +## SDK Usage + +### Creating the SDK + +```csharp +using StructFrame.Sdk; + +var sdk = new StructFrameSdk(new StructFrameSdkConfig +{ + Transport = transport, + FrameParser = new BasicDefault(), + Debug = true, +}); +``` + +### Connecting and Disconnecting + +```csharp +// Connect +await sdk.ConnectAsync(); + +// Check connection status +if (sdk.IsConnected) +{ + Console.WriteLine("Connected!"); +} + +// Disconnect +await sdk.DisconnectAsync(); +``` + +### Subscribing to Messages + +```csharp +using RobotMessages; + +// Subscribe to messages +Action unsubscribe = sdk.Subscribe( + StatusMessage.MsgId, + (message, msgId) => + { + Console.WriteLine($"Temperature: {message.Temperature}°C"); + Console.WriteLine($"Battery: {message.Battery}%"); + } +); + +// Unsubscribe when done +unsubscribe(); +``` + +### Sending Messages + +```csharp +using RobotMessages; + +// Create and send message +var cmd = new CommandMessage +{ + Command = "MOVE_FORWARD", + Speed = 50, +}; + +await sdk.SendAsync(cmd); + +// Or send raw bytes +byte[] rawData = new byte[] { 1, 2, 3, 4 }; +await sdk.SendRawAsync(CommandMessage.MsgId, rawData); +``` + +### Automatic Message Deserialization + +Register codecs for automatic deserialization: + +```csharp +// Create a codec wrapper +public class StatusMessageCodec : IMessageCodec +{ + public byte MsgId => StatusMessage.MsgId; + + public StatusMessage Deserialize(byte[] data) + { + return StatusMessage.CreateUnpack(data); + } +} + +sdk.RegisterCodec(new StatusMessageCodec()); + +// Now messages are automatically deserialized +sdk.Subscribe(StatusMessage.MsgId, (message, msgId) => +{ + // message is already a StatusMessage instance + Console.WriteLine(message); +}); +``` + +## Complete Example + +```csharp +using System; +using System.Threading.Tasks; +using StructFrame.Sdk; +using RobotMessages; + +public class RobotClient +{ + public static async Task Main(string[] args) + { + // Create transport + var transport = new TcpTransport(new TcpTransportConfig + { + Host = "localhost", + Port = 8080, + AutoReconnect = true, + ReconnectDelayMs = 2000, + MaxReconnectAttempts = 10, + }); + + // Create SDK + var sdk = new StructFrameSdk(new StructFrameSdkConfig + { + Transport = transport, + FrameParser = new BasicDefault(), + Debug = true, + }); + + // Subscribe to status messages + sdk.Subscribe(StatusMessage.MsgId, (msg, id) => + { + Console.WriteLine($"[Status] Temp: {msg.Temperature}°C, Battery: {msg.Battery}%"); + }); + + // Connect + await sdk.ConnectAsync(); + Console.WriteLine("Connected to robot"); + + // Send command + var cmd = new CommandMessage + { + Command = "MOVE_FORWARD", + Speed = 50, + }; + await sdk.SendAsync(cmd); + + // Handle errors + transport.ErrorOccurred += (sender, error) => + { + Console.WriteLine($"Transport error: {error.Message}"); + }; + + // Handle close + transport.ConnectionClosed += (sender, args) => + { + Console.WriteLine("Connection closed"); + }; + + // Keep alive + Console.WriteLine("Press Ctrl+C to exit"); + await Task.Delay(-1); + } +} +``` + +## ASP.NET Core Integration + +Integrate with ASP.NET Core dependency injection: + +```csharp +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + // Register transport + services.AddSingleton(sp => + { + return new TcpTransport(new TcpTransportConfig + { + Host = "localhost", + Port = 8080, + }); + }); + + // Register SDK + services.AddSingleton(sp => + { + var transport = sp.GetRequiredService(); + return new StructFrameSdk(new StructFrameSdkConfig + { + Transport = transport, + FrameParser = new BasicDefault(), + }); + }); + + // Register as hosted service + services.AddHostedService(); + } +} + +public class RobotService : BackgroundService +{ + private readonly StructFrameSdk _sdk; + + public RobotService(StructFrameSdk sdk) + { + _sdk = sdk; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await _sdk.ConnectAsync(); + + // Subscribe to messages + _sdk.Subscribe(StatusMessage.MsgId, HandleStatus); + + // Wait for cancellation + await Task.Delay(-1, stoppingToken); + + await _sdk.DisconnectAsync(); + } + + private void HandleStatus(StatusMessage msg, byte msgId) + { + // Handle status + } +} +``` + +## Xamarin/MAUI Example + +```csharp +using Xamarin.Forms; +using StructFrame.Sdk; + +public class RobotPage : ContentPage +{ + private StructFrameSdk _sdk; + + public RobotPage() + { + InitializeComponent(); + InitializeSdk(); + } + + private async void InitializeSdk() + { + // Platform-specific serial port + var serialPort = DependencyService.Get(); + var transport = new GenericSerialTransport(serialPort); + + _sdk = new StructFrameSdk(new StructFrameSdkConfig + { + Transport = transport, + FrameParser = new BasicDefault(), + }); + + // Subscribe + _sdk.Subscribe(StatusMessage.MsgId, (msg, id) => + { + Device.BeginInvokeOnMainThread(() => + { + // Update UI + TempLabel.Text = $"{msg.Temperature}°C"; + BatteryLabel.Text = $"{msg.Battery}%"; + }); + }); + + await _sdk.ConnectAsync(); + } + + private async void SendCommand_Clicked(object sender, EventArgs e) + { + var cmd = new CommandMessage { Command = "START" }; + await _sdk.SendAsync(cmd); + } +} +``` + +## Error Handling + +```csharp +try +{ + await sdk.ConnectAsync(); +} +catch (Exception ex) +{ + Console.WriteLine($"Failed to connect: {ex.Message}"); +} + +// Event-based error handling +transport.ErrorOccurred += (sender, error) => +{ + Console.WriteLine($"Transport error: {error.Message}"); +}; + +transport.ConnectionClosed += (sender, args) => +{ + Console.WriteLine("Connection closed"); +}; +``` + +## NuGet Dependencies + +### Required +- .NET Standard 2.0+ +- System.IO.Ports (for SerialTransport) + +### Optional +- NetCoreServer (for WebSocket and enhanced TCP/UDP) + +```bash +# Install via NuGet +dotnet add package System.IO.Ports +dotnet add package NetCoreServer +``` + +## Best Practices + +1. **Use async/await consistently**: + ```csharp + await sdk.ConnectAsync(); + await sdk.SendAsync(message); + ``` + +2. **Dispose properly**: + ```csharp + try + { + await sdk.ConnectAsync(); + // Use SDK + } + finally + { + await sdk.DisconnectAsync(); + } + ``` + +3. **Handle UI thread marshalling** (Xamarin/WPF/WinForms): + ```csharp + sdk.Subscribe(StatusMessage.MsgId, (msg, id) => + { + // Xamarin + Device.BeginInvokeOnMainThread(() => UpdateUI(msg)); + + // WPF + Dispatcher.Invoke(() => UpdateUI(msg)); + + // WinForms + BeginInvoke(new Action(() => UpdateUI(msg))); + }); + ``` + +4. **Use CancellationToken**: + ```csharp + public async Task RunAsync(CancellationToken ct) + { + await sdk.ConnectAsync(); + + while (!ct.IsCancellationRequested) + { + await Task.Delay(100, ct); + } + + await sdk.DisconnectAsync(); + } + ``` + +## Platform-Specific Notes + +### .NET Framework +- Requires .NET Framework 4.7.2+ for .NET Standard 2.0 support +- Use `System.IO.Ports` for serial communication + +### .NET Core / .NET 5+ +- Full support for all features +- Cross-platform serial port support + +### Xamarin +- Implement `IGenericSerialPort` for platform-specific serial I/O +- Use `Device.BeginInvokeOnMainThread` for UI updates + +### MAUI +- Similar to Xamarin, use platform-specific implementations +- Use `MainThread.BeginInvokeOnMainThread` for UI updates + +### UWP +- Serial port access requires capabilities in Package.appxmanifest +- Limited network socket support (use UWP-specific APIs) diff --git a/docs/user-guide/python-sdk.md b/docs/user-guide/python-sdk.md new file mode 100644 index 00000000..fab32478 --- /dev/null +++ b/docs/user-guide/python-sdk.md @@ -0,0 +1,396 @@ +# Python SDK + +The Python SDK provides both synchronous and asynchronous interfaces for structured message communication. + +## Installation + +The SDK is automatically included when you generate Python code: + +```bash +python -m struct_frame your_messages.proto --build_py --py_path generated/py +``` + +## Available Transports + +### Synchronous Transports + +#### UDP Transport + +```python +from sdk import UdpTransport, UdpTransportConfig + +transport = UdpTransport(UdpTransportConfig( + remote_host='192.168.1.100', + remote_port=5000, + local_port=5001, + local_address='0.0.0.0', + enable_broadcast=False, + auto_reconnect=True, + reconnect_delay=1.0, + max_reconnect_attempts=5, +)) +``` + +#### TCP Transport + +```python +from sdk import TcpTransport, TcpTransportConfig + +transport = TcpTransport(TcpTransportConfig( + host='192.168.1.100', + port=5000, + timeout=5.0, + auto_reconnect=True, +)) +``` + +#### WebSocket Transport + +Requires `websocket-client` package: + +```python +from sdk import WebSocketTransport, WebSocketTransportConfig + +transport = WebSocketTransport(WebSocketTransportConfig( + url='ws://localhost:8080', + timeout=5.0, +)) +``` + +#### Serial Transport + +Requires `pyserial` package: + +```python +from sdk import SerialTransport, SerialTransportConfig + +transport = SerialTransport(SerialTransportConfig( + port='/dev/ttyUSB0', # or 'COM3' on Windows + baudrate=115200, + bytesize=8, + parity='N', + stopbits=1, +)) +``` + +### Asynchronous Transports + +All transports have async versions with `Async` prefix: + +```python +from sdk import ( + AsyncUdpTransport, AsyncUdpTransportConfig, + AsyncTcpTransport, AsyncTcpTransportConfig, + AsyncWebSocketTransport, AsyncWebSocketTransportConfig, + AsyncSerialTransport, AsyncSerialTransportConfig, +) +``` + +## Synchronous SDK Usage + +### Creating the SDK + +```python +from sdk import StructFrameSdk, StructFrameSdkConfig +from basic_default import BasicDefault + +sdk = StructFrameSdk(StructFrameSdkConfig( + transport=transport, + frame_parser=BasicDefault(), + debug=True, +)) +``` + +### Connecting and Disconnecting + +```python +# Connect +sdk.connect() + +# Check connection status +if sdk.is_connected(): + print('Connected!') + +# Disconnect +sdk.disconnect() +``` + +### Subscribing to Messages + +```python +from my_messages import StatusMessage + +def on_status(message, msg_id): + print(f'Temperature: {message.temperature}') + print(f'Battery: {message.battery}') + +# Subscribe +unsubscribe = sdk.subscribe(StatusMessage.msg_id, on_status) + +# Unsubscribe when done +unsubscribe() +``` + +### Sending Messages + +```python +from my_messages import CommandMessage + +# Create and send message +cmd = CommandMessage(command='START', value=100) +sdk.send(cmd) + +# Or send raw bytes +raw_data = b'\x01\x02\x03\x04' +sdk.send_raw(CommandMessage.msg_id, raw_data) +``` + +### Complete Synchronous Example + +```python +import time +from sdk import StructFrameSdk, StructFrameSdkConfig, TcpTransport, TcpTransportConfig +from basic_default import BasicDefault +from robot_messages import StatusMessage, CommandMessage + +def main(): + # Create transport + transport = TcpTransport(TcpTransportConfig( + host='localhost', + port=8080, + auto_reconnect=True, + reconnect_delay=2.0, + )) + + # Create SDK + sdk = StructFrameSdk(StructFrameSdkConfig( + transport=transport, + frame_parser=BasicDefault(), + debug=True, + )) + + # Subscribe to status messages + def on_status(msg, msg_id): + print(f'[Status] Temp: {msg.temperature}°C, Battery: {msg.battery}%') + + sdk.subscribe(StatusMessage.msg_id, on_status) + + # Connect + sdk.connect() + print('Connected to robot') + + # Send command + cmd = CommandMessage(command='MOVE_FORWARD', speed=50) + sdk.send(cmd) + + # Keep running + try: + while True: + time.sleep(0.1) + except KeyboardInterrupt: + sdk.disconnect() + +if __name__ == '__main__': + main() +``` + +## Asynchronous SDK Usage + +### Creating the Async SDK + +```python +import asyncio +from sdk import AsyncStructFrameSdk, AsyncStructFrameSdkConfig +from basic_default import BasicDefault + +async def main(): + sdk = AsyncStructFrameSdk(AsyncStructFrameSdkConfig( + transport=transport, + frame_parser=BasicDefault(), + debug=True, + )) +``` + +### Async Operations + +```python +# Connect +await sdk.connect() + +# Send message +cmd = CommandMessage(command='START', value=100) +await sdk.send(cmd) + +# Disconnect +await sdk.disconnect() +``` + +### Complete Asynchronous Example + +```python +import asyncio +from sdk import ( + AsyncStructFrameSdk, + AsyncStructFrameSdkConfig, + AsyncTcpTransport, + AsyncTcpTransportConfig, +) +from basic_default import BasicDefault +from robot_messages import StatusMessage, CommandMessage + +async def main(): + # Create transport + transport = AsyncTcpTransport(AsyncTcpTransportConfig( + host='localhost', + port=8080, + auto_reconnect=True, + )) + + # Create SDK + sdk = AsyncStructFrameSdk(AsyncStructFrameSdkConfig( + transport=transport, + frame_parser=BasicDefault(), + debug=True, + )) + + # Subscribe to status messages + def on_status(msg, msg_id): + print(f'[Status] Temp: {msg.temperature}°C, Battery: {msg.battery}%') + + sdk.subscribe(StatusMessage.msg_id, on_status) + + # Connect + await sdk.connect() + print('Connected to robot') + + # Send command + cmd = CommandMessage(command='MOVE_FORWARD', speed=50) + await sdk.send(cmd) + + # Keep running + try: + while True: + await asyncio.sleep(0.1) + except KeyboardInterrupt: + await sdk.disconnect() + +if __name__ == '__main__': + asyncio.run(main()) +``` + +## Automatic Message Deserialization + +Register codecs for automatic deserialization: + +```python +from my_messages import StatusMessage + +# The message class itself can act as a codec +sdk.register_codec(StatusMessage) + +# Now messages are automatically deserialized +sdk.subscribe(StatusMessage.msg_id, lambda msg, id: print(msg)) +``` + +## Error Handling + +```python +# Synchronous +try: + sdk.connect() +except Exception as e: + print(f'Failed to connect: {e}') + +# Asynchronous +try: + await sdk.connect() +except Exception as e: + print(f'Failed to connect: {e}') + +# Transport-level error handling +def on_error(error): + print(f'Transport error: {error}') + +transport.set_error_callback(on_error) +``` + +## Dependencies + +Install optional dependencies based on transports used: + +```bash +# WebSocket support +pip install websocket-client # Sync +pip install websockets # Async + +# Serial port support +pip install pyserial +``` + +## Type Hints + +The SDK is fully type-hinted for better IDE support: + +```python +from typing import Callable, Protocol +from abc import ABC, abstractmethod + +class ITransport(ABC): + @abstractmethod + def connect(self) -> None: ... + + @abstractmethod + def disconnect(self) -> None: ... + + @abstractmethod + def send(self, data: bytes) -> None: ... + +class IFrameParser(Protocol): + def parse(self, data: bytes): ... + def frame(self, msg_id: int, data: bytes) -> bytes: ... + +MessageHandler = Callable[[Any, int], None] +``` + +## Threading Considerations + +The synchronous SDK uses background threads for receiving data. This is handled automatically, but be aware: + +- Callbacks are executed in the receive thread +- Use thread-safe operations in callbacks if needed +- The async SDK uses asyncio event loop instead of threads + +```python +import threading + +def on_message(msg, msg_id): + # This runs in a background thread + print(f'Thread: {threading.current_thread().name}') + # Use locks if accessing shared data +``` + +## Best Practices + +1. **Always disconnect properly**: + ```python + try: + sdk.connect() + # ... use SDK + finally: + sdk.disconnect() + ``` + +2. **Use async SDK for async applications**: + - Web servers (FastAPI, aiohttp) + - Concurrent I/O operations + - Better resource usage + +3. **Use sync SDK for**: + - Simple scripts + - Legacy codebases + - Easier debugging + +4. **Error handling**: + - Always handle connection errors + - Set error callbacks for transport issues + - Implement reconnection logic if needed diff --git a/docs/user-guide/sdk-overview.md b/docs/user-guide/sdk-overview.md new file mode 100644 index 00000000..7ed3dbce --- /dev/null +++ b/docs/user-guide/sdk-overview.md @@ -0,0 +1,191 @@ +# SDK Overview + +Struct Frame provides high-level SDKs for TypeScript/JavaScript, Python, C++, and C# that simplify sending and receiving framed messages over various transport layers. + +## Features + +- **Multiple Transport Layers**: UDP, TCP, WebSocket, and Serial +- **Automatic Framing**: Messages are automatically framed and parsed +- **Type-Safe Message Handling**: Subscribe to specific message types +- **Auto-Reconnection**: Configurable automatic reconnection on connection loss +- **Cross-Platform**: Works across embedded systems, desktop, and mobile platforms + +## Available SDKs + +| Language | Sync/Async | Transports | Observer Pattern | +|----------|------------|------------|------------------| +| **TypeScript/JavaScript** | Async (Promise-based) | UDP, TCP, WebSocket, Serial | Callback-based | +| **Python** | Both Sync & Async | UDP, TCP, WebSocket, Serial | Callback-based | +| **C++** | Sync (poll-based) | UDP*, TCP*, WebSocket*, Serial | Observer/Subscriber | +| **C#** | Async (Task-based) | UDP, TCP, WebSocket*, Serial | Event-based | + +*UDP, TCP, WebSocket transports in C++ require ASIO and Simple-WebSocket-Server libraries. See [C++ SDK documentation](cpp-sdk.md) for details. + +## Quick Start + +### TypeScript/JavaScript + +```typescript +import { + StructFrameSdk, + UdpTransport, +} from './sdk'; +import { BasicDefault } from './BasicDefault'; +import { MyMessage } from './my_messages'; + +// Create transport +const transport = new UdpTransport({ + remoteHost: '192.168.1.100', + remotePort: 5000, + localPort: 5001, +}); + +// Create SDK with frame parser +const sdk = new StructFrameSdk({ + transport, + frameParser: new BasicDefault(), + debug: true, +}); + +// Subscribe to messages +sdk.subscribe(MyMessage.msg_id, (message, msgId) => { + console.log('Received:', message); +}); + +// Connect and send +await sdk.connect(); +const msg = new MyMessage(); +msg.value = 42; +await sdk.send(msg); +``` + +### Python (Async) + +```python +import asyncio +from sdk import AsyncStructFrameSdk, AsyncUdpTransport, AsyncUdpTransportConfig +from basic_default import BasicDefault +from my_messages import MyMessage + +async def main(): + # Create transport + transport = AsyncUdpTransport(AsyncUdpTransportConfig( + remote_host='192.168.1.100', + remote_port=5000, + local_port=5001, + )) + + # Create SDK with frame parser + sdk = AsyncStructFrameSdk(AsyncStructFrameSdkConfig( + transport=transport, + frame_parser=BasicDefault(), + debug=True, + )) + + # Subscribe to messages + def on_message(message, msg_id): + print(f'Received: {message}') + + sdk.subscribe(MyMessage.msg_id, on_message) + + # Connect and send + await sdk.connect() + msg = MyMessage(value=42) + await sdk.send(msg) + +asyncio.run(main()) +``` + +### C++ (Header-Only) + +```cpp +#include "sdk/sdk.hpp" +#include "BasicDefault.hpp" +#include "my_messages.hpp" + +using namespace StructFrame; + +// Create custom serial port implementation +class MySerialPort : public ISerialPort { + // Implement platform-specific serial I/O +}; + +int main() { + // Create transport + MySerialPort serialPort; + SerialTransport transport(&serialPort); + + // Create SDK + BasicDefault frameParser; + StructFrameSdk sdk({ + .transport = &transport, + .frameParser = &frameParser, + .debug = true, + }); + + // Subscribe with lambda + auto subscription = sdk.subscribe( + MyMessage::msg_id, + [](const MyMessage& msg, uint8_t msgId) { + // Handle message + } + ); + + // Connect and send + sdk.connect(); + MyMessage msg; + msg.value = 42; + sdk.send(msg); + + // Poll for messages (embedded systems) + while (true) { + transport.poll(); + } +} +``` + +### C# + +```csharp +using StructFrame.Sdk; +using System; +using System.Threading.Tasks; + +async Task Main() +{ + // Create transport + var transport = new UdpTransport(new UdpTransportConfig + { + RemoteHost = "192.168.1.100", + RemotePort = 5000, + LocalPort = 5001, + }); + + // Create SDK + var sdk = new StructFrameSdk(new StructFrameSdkConfig + { + Transport = transport, + FrameParser = new BasicDefault(), + Debug = true, + }); + + // Subscribe to messages + sdk.Subscribe(MyMessage.MsgId, (message, msgId) => + { + Console.WriteLine($"Received: {message}"); + }); + + // Connect and send + await sdk.ConnectAsync(); + var msg = new MyMessage { Value = 42 }; + await sdk.SendAsync(msg); +} +``` + +## Next Steps + +- [TypeScript/JavaScript SDK](typescript-sdk.md) - Detailed TypeScript/JavaScript SDK documentation +- [Python SDK](python-sdk.md) - Detailed Python SDK documentation (sync and async) +- [C++ SDK](cpp-sdk.md) - Detailed C++ SDK documentation +- [C# SDK](csharp-sdk.md) - Detailed C# SDK documentation +- [Transport Layers](transports.md) - Transport configuration and options diff --git a/docs/user-guide/typescript-sdk.md b/docs/user-guide/typescript-sdk.md new file mode 100644 index 00000000..2cbde4ec --- /dev/null +++ b/docs/user-guide/typescript-sdk.md @@ -0,0 +1,284 @@ +# TypeScript/JavaScript SDK + +The TypeScript/JavaScript SDK provides a high-level, Promise-based interface for structured message communication. + +## Installation + +The SDK is automatically included when you generate TypeScript code: + +```bash +python -m struct_frame your_messages.proto --build_ts --ts_path generated/ts +``` + +## Available Transports + +### UDP Transport + +Uses Node.js `dgram` module for UDP communication. + +```typescript +import { UdpTransport, UdpTransportConfig } from './sdk'; + +const transport = new UdpTransport({ + remoteHost: '192.168.1.100', + remotePort: 5000, + localPort: 5001, + localAddress: '0.0.0.0', + socketType: 'udp4', // or 'udp6' + broadcast: false, + autoReconnect: true, + reconnectDelay: 1000, + maxReconnectAttempts: 5, +}); +``` + +### TCP Transport + +Uses Node.js `net` module for TCP communication. + +```typescript +import { TcpTransport, TcpTransportConfig } from './sdk'; + +const transport = new TcpTransport({ + host: '192.168.1.100', + port: 5000, + timeout: 5000, + autoReconnect: true, +}); +``` + +### WebSocket Transport + +Uses the WebSocket API (works in both browser and Node.js with `ws` package). + +```typescript +import { WebSocketTransport, WebSocketTransportConfig } from './sdk'; + +const transport = new WebSocketTransport({ + url: 'ws://localhost:8080', + protocols: [], // Optional WebSocket protocols + autoReconnect: true, +}); +``` + +### Serial Transport + +Uses the `serialport` package for serial communication. + +```typescript +import { SerialTransport, SerialTransportConfig } from './sdk'; + +const transport = new SerialTransport({ + path: '/dev/ttyUSB0', // or 'COM3' on Windows + baudRate: 115200, + dataBits: 8, + stopBits: 1, + parity: 'none', +}); +``` + +## SDK Usage + +### Creating the SDK + +```typescript +import { StructFrameSdk, StructFrameSdkConfig } from './sdk'; +import { BasicDefault } from './BasicDefault'; // Frame parser + +const sdk = new StructFrameSdk({ + transport: transport, + frameParser: new BasicDefault(), + debug: true, // Enable debug logging +}); +``` + +### Connecting and Disconnecting + +```typescript +// Connect +await sdk.connect(); + +// Check connection status +if (sdk.isConnected()) { + console.log('Connected!'); +} + +// Disconnect +await sdk.disconnect(); +``` + +### Subscribing to Messages + +```typescript +import { StatusMessage } from './my_messages'; + +// Subscribe with typed handler +const unsubscribe = sdk.subscribe( + StatusMessage.msg_id, + (message, msgId) => { + console.log(`Temperature: ${message.temperature}`); + console.log(`Status: ${message.status}`); + } +); + +// Unsubscribe when done +unsubscribe(); +``` + +### Sending Messages + +```typescript +import { CommandMessage } from './my_messages'; + +// Create and send message +const cmd = new CommandMessage(); +cmd.command = 'START'; +cmd.value = 100; + +await sdk.send(cmd); + +// Or send raw bytes +const rawData = new Uint8Array([1, 2, 3, 4]); +await sdk.sendRaw(CommandMessage.msg_id, rawData); +``` + +### Automatic Message Deserialization + +Register codecs for automatic deserialization: + +```typescript +import { StatusMessage } from './my_messages'; + +// Create a codec wrapper +const statusCodec = { + getMsgId: () => StatusMessage.msg_id, + deserialize: (data: Uint8Array) => StatusMessage.create_unpack(data), +}; + +sdk.registerCodec(statusCodec); + +// Now messages are automatically deserialized +sdk.subscribe(StatusMessage.msg_id, (message, msgId) => { + // message is already a StatusMessage instance + console.log(message); +}); +``` + +## Complete Example + +```typescript +import { + StructFrameSdk, + TcpTransport, +} from './sdk'; +import { BasicDefault } from './BasicDefault'; +import { StatusMessage, CommandMessage } from './robot_messages'; + +async function main() { + // Create transport + const transport = new TcpTransport({ + host: 'localhost', + port: 8080, + autoReconnect: true, + reconnectDelay: 2000, + maxReconnectAttempts: 10, + }); + + // Create SDK + const sdk = new StructFrameSdk({ + transport, + frameParser: new BasicDefault(), + debug: true, + }); + + // Subscribe to status messages + sdk.subscribe(StatusMessage.msg_id, (msg, id) => { + console.log(`[Status] Temp: ${msg.temperature}°C, Battery: ${msg.battery}%`); + }); + + // Connect + await sdk.connect(); + console.log('Connected to robot'); + + // Send command + const cmd = new CommandMessage(); + cmd.command = 'MOVE_FORWARD'; + cmd.speed = 50; + await sdk.send(cmd); + + // Handle errors + transport.onError((error) => { + console.error('Transport error:', error); + }); + + // Handle close + transport.onClose(() => { + console.log('Connection closed'); + }); + + // Keep alive + process.on('SIGINT', async () => { + await sdk.disconnect(); + process.exit(0); + }); +} + +main().catch(console.error); +``` + +## Error Handling + +```typescript +try { + await sdk.connect(); +} catch (error) { + console.error('Failed to connect:', error); +} + +// Transport-level error handling +transport.onError((error) => { + console.error('Transport error:', error); +}); + +transport.onClose(() => { + console.log('Connection closed'); +}); +``` + +## Dependencies + +- **UDP/TCP**: Built-in Node.js modules (`dgram`, `net`) +- **WebSocket**: Global `WebSocket` API (browser) or `ws` package (Node.js) +- **Serial**: `serialport` package (`npm install serialport`) + +Install dependencies: + +```bash +npm install ws serialport @types/ws @types/serialport +``` + +## TypeScript Types + +All SDK components are fully typed: + +```typescript +interface ITransport { + connect(): Promise; + disconnect(): Promise; + send(data: Uint8Array): Promise; + onData(callback: (data: Uint8Array) => void): void; + onError(callback: (error: Error) => void): void; + onClose(callback: () => void): void; + isConnected(): boolean; +} + +interface IFrameParser { + parse(data: Uint8Array): FrameMsgInfo; + frame(msgId: number, data: Uint8Array): Uint8Array; +} + +interface IMessageCodec { + getMsgId(): number; + deserialize(data: Uint8Array): T; +} +``` diff --git a/mkdocs.yml b/mkdocs.yml index fa88fcd7..78dcb660 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,6 +35,11 @@ nav: - User Guide: - Message Definitions: user-guide/message-definitions.md - Framing: user-guide/framing.md + - SDK Overview: user-guide/sdk-overview.md + - TypeScript/JavaScript SDK: user-guide/typescript-sdk.md + - Python SDK: user-guide/python-sdk.md + - C++ SDK: user-guide/cpp-sdk.md + - C# SDK: user-guide/csharp-sdk.md - Reference: - Testing: reference/testing.md - Development: reference/development.md From 316fd5ac2f39babc28aa15cc3f89e3d846510df0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:57:26 +0000 Subject: [PATCH 4/9] Fix SDK directory copying in code generation Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- src/struct_frame/generate.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/struct_frame/generate.py b/src/struct_frame/generate.py index a8363acd..111c67ba 100644 --- a/src/struct_frame/generate.py +++ b/src/struct_frame/generate.py @@ -901,14 +901,17 @@ def copy_files_list(src_dir, dst_dir, files_to_copy): shutil.copy2(src_path, dst_path) def copy_all_files(src_dir, dst_dir): - """Copy all files from src_dir to dst_dir""" + """Copy all files and directories from src_dir to dst_dir""" if not os.path.exists(dst_dir): os.makedirs(dst_dir) if os.path.exists(src_dir): for item in os.listdir(src_dir): src_path = os.path.join(src_dir, item) dst_path = os.path.join(dst_dir, item) - if os.path.isfile(src_path): + if os.path.isdir(src_path): + # Recursively copy directories (e.g., sdk subdirectory) + shutil.copytree(src_path, dst_path, dirs_exist_ok=True) + elif os.path.isfile(src_path): shutil.copy2(src_path, dst_path) if args.frame_formats: From efd5e32ca0a95b44f173503a6c9809732361eb1d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:59:55 +0000 Subject: [PATCH 5/9] Address code review feedback - improve frame size calculation documentation Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- .../boilerplate/cpp/sdk/struct_frame_sdk.hpp | 7 ++++++- .../boilerplate/csharp/sdk/StructFrameSdk.cs | 7 ++++++- .../boilerplate/py/sdk/async_struct_frame_sdk.py | 15 ++++++++++----- .../boilerplate/py/sdk/struct_frame_sdk.py | 15 ++++++++++----- .../boilerplate/ts/sdk/struct_frame_sdk.ts | 11 ++++++----- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp b/src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp index f1265f0d..3c381700 100644 --- a/src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp +++ b/src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp @@ -117,7 +117,12 @@ class StructFrameSdk { } size_t calculateFrameSize(const FrameParsers::FrameMsgInfo& result) const { - // Conservative estimate - adjust based on frame format + // Calculate total frame size including headers and footers + // Frame overhead by format: + // - BasicDefault: 2 start + 1 length + 1 msg_id + payload + 2 crc = 6 + payload + // - TinyDefault: 1 start + 1 length + 1 msg_id + payload + 2 crc = 5 + payload + // Using conservative estimate of 10 bytes to handle all frame formats + // TODO: Query frame parser for exact overhead to avoid buffering issues return result.msg_len + 10; } diff --git a/src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs b/src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs index 59b10caf..e214949f 100644 --- a/src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs +++ b/src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs @@ -228,7 +228,12 @@ private void ParseBuffer() private int CalculateFrameSize(FrameMsgInfo result) { - // Conservative estimate - adjust based on frame format + // Calculate total frame size including headers and footers + // Frame overhead by format: + // - BasicDefault: 2 start + 1 length + 1 msg_id + payload + 2 crc = 6 + payload + // - TinyDefault: 1 start + 1 length + 1 msg_id + payload + 2 crc = 5 + payload + // Using conservative estimate of 10 bytes to handle all frame formats + // TODO: Query frame parser for exact overhead to avoid buffering issues return result.MsgLen + 10; } diff --git a/src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py b/src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py index 4801a248..cbe113eb 100644 --- a/src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py +++ b/src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py @@ -153,11 +153,16 @@ def _parse_buffer(self) -> None: self.buffer = self.buffer[total_frame_size:] def _calculate_frame_size(self, result) -> int: - """Calculate total frame size including headers and footers""" - # This is a heuristic - actual size depends on frame format - # For most formats: start bytes + header + payload + crc - # Conservative estimate - return result.msg_len + 10 # Adjust based on frame format + """Calculate total frame size including headers and footers + + Frame overhead by format: + - BasicDefault: 2 start + 1 length + 1 msg_id + payload + 2 crc = 6 + payload + - TinyDefault: 1 start + 1 length + 1 msg_id + payload + 2 crc = 5 + payload + + Using conservative estimate of 10 bytes to handle all frame formats. + TODO: Query frame parser for exact overhead to avoid buffering issues. + """ + return result.msg_len + 10 def _handle_error(self, error: Exception) -> None: """Handle transport error""" diff --git a/src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py b/src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py index a5a36faa..b2f03dcb 100644 --- a/src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py +++ b/src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py @@ -152,11 +152,16 @@ def _parse_buffer(self) -> None: self.buffer = self.buffer[total_frame_size:] def _calculate_frame_size(self, result) -> int: - """Calculate total frame size including headers and footers""" - # This is a heuristic - actual size depends on frame format - # For most formats: start bytes + header + payload + crc - # Conservative estimate - return result.msg_len + 10 # Adjust based on frame format + """Calculate total frame size including headers and footers + + Frame overhead by format: + - BasicDefault: 2 start + 1 length + 1 msg_id + payload + 2 crc = 6 + payload + - TinyDefault: 1 start + 1 length + 1 msg_id + payload + 2 crc = 5 + payload + + Using conservative estimate of 10 bytes to handle all frame formats. + TODO: Query frame parser for exact overhead to avoid buffering issues. + """ + return result.msg_len + 10 def _handle_error(self, error: Exception) -> None: """Handle transport error""" diff --git a/src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts b/src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts index 32f4cdc4..a62f9502 100644 --- a/src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts +++ b/src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts @@ -196,11 +196,12 @@ export class StructFrameSdk { } private calculateFrameSize(result: FrameMsgInfo): number { - // This is a heuristic - actual size depends on frame format - // For most formats: start bytes + header + payload + crc - // The parser should ideally tell us the exact frame size - // For now, we'll use a conservative estimate - return result.msg_len + 10; // Adjust based on frame format + // Calculate total frame size including headers and footers + // For BasicDefault format: 2 start bytes + 1 length + 1 msg_id + payload + 2 crc = 6 + payload + // For TinyDefault format: 1 start byte + 1 length + 1 msg_id + payload + 2 crc = 5 + payload + // Using conservative estimate of 10 bytes overhead to handle various frame formats + // TODO: Query frame parser for exact overhead to avoid buffering issues + return result.msg_len + 10; } private handleError(error: Error): void { From db5c9abea8610e74e1ae693ec6664d29d49b814d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Dec 2025 20:25:11 +0000 Subject: [PATCH 6/9] Rename SDK directories to struct_frame_sdk for better namespacing Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- docs/user-guide/cpp-sdk.md | 15 +-- docs/user-guide/python-sdk.md | 18 ++-- docs/user-guide/sdk-overview.md | 4 +- docs/user-guide/typescript-sdk.md | 12 +-- .../network_transports.hpp | 0 .../{sdk => struct_frame_sdk}/observer.hpp | 96 +++++++++++++++---- .../cpp/{sdk => struct_frame_sdk}/sdk.hpp | 0 .../serial_transport.hpp | 0 .../struct_frame_sdk.hpp | 32 ++++--- .../{sdk => struct_frame_sdk}/transport.hpp | 0 .../SerialAndWebSocketTransports.cs | 0 .../StructFrameSdk.cs | 0 .../{sdk => struct_frame_sdk}/TcpTransport.cs | 0 .../{sdk => struct_frame_sdk}/Transport.cs | 0 .../{sdk => struct_frame_sdk}/UdpTransport.cs | 0 .../py/{sdk => struct_frame_sdk}/__init__.py | 0 .../async_serial_transport.py | 0 .../async_struct_frame_sdk.py | 0 .../async_tcp_transport.py | 0 .../async_transport.py | 0 .../async_udp_transport.py | 0 .../async_websocket_transport.py | 0 .../serial_transport.py | 0 .../struct_frame_sdk.py | 0 .../tcp_transport.py | 0 .../py/{sdk => struct_frame_sdk}/transport.py | 0 .../udp_transport.py | 0 .../websocket_transport.py | 0 .../ts/{sdk => struct_frame_sdk}/index.ts | 0 .../serial_transport.ts | 0 .../struct_frame_sdk.ts | 0 .../tcp_transport.ts | 0 .../ts/{sdk => struct_frame_sdk}/transport.ts | 0 .../udp_transport.ts | 0 .../websocket_transport.ts | 0 35 files changed, 123 insertions(+), 54 deletions(-) rename src/struct_frame/boilerplate/cpp/{sdk => struct_frame_sdk}/network_transports.hpp (100%) rename src/struct_frame/boilerplate/cpp/{sdk => struct_frame_sdk}/observer.hpp (58%) rename src/struct_frame/boilerplate/cpp/{sdk => struct_frame_sdk}/sdk.hpp (100%) rename src/struct_frame/boilerplate/cpp/{sdk => struct_frame_sdk}/serial_transport.hpp (100%) rename src/struct_frame/boilerplate/cpp/{sdk => struct_frame_sdk}/struct_frame_sdk.hpp (86%) rename src/struct_frame/boilerplate/cpp/{sdk => struct_frame_sdk}/transport.hpp (100%) rename src/struct_frame/boilerplate/csharp/{sdk => struct_frame_sdk}/SerialAndWebSocketTransports.cs (100%) rename src/struct_frame/boilerplate/csharp/{sdk => struct_frame_sdk}/StructFrameSdk.cs (100%) rename src/struct_frame/boilerplate/csharp/{sdk => struct_frame_sdk}/TcpTransport.cs (100%) rename src/struct_frame/boilerplate/csharp/{sdk => struct_frame_sdk}/Transport.cs (100%) rename src/struct_frame/boilerplate/csharp/{sdk => struct_frame_sdk}/UdpTransport.cs (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/__init__.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/async_serial_transport.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/async_struct_frame_sdk.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/async_tcp_transport.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/async_transport.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/async_udp_transport.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/async_websocket_transport.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/serial_transport.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/struct_frame_sdk.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/tcp_transport.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/transport.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/udp_transport.py (100%) rename src/struct_frame/boilerplate/py/{sdk => struct_frame_sdk}/websocket_transport.py (100%) rename src/struct_frame/boilerplate/ts/{sdk => struct_frame_sdk}/index.ts (100%) rename src/struct_frame/boilerplate/ts/{sdk => struct_frame_sdk}/serial_transport.ts (100%) rename src/struct_frame/boilerplate/ts/{sdk => struct_frame_sdk}/struct_frame_sdk.ts (100%) rename src/struct_frame/boilerplate/ts/{sdk => struct_frame_sdk}/tcp_transport.ts (100%) rename src/struct_frame/boilerplate/ts/{sdk => struct_frame_sdk}/transport.ts (100%) rename src/struct_frame/boilerplate/ts/{sdk => struct_frame_sdk}/udp_transport.ts (100%) rename src/struct_frame/boilerplate/ts/{sdk => struct_frame_sdk}/websocket_transport.ts (100%) diff --git a/docs/user-guide/cpp-sdk.md b/docs/user-guide/cpp-sdk.md index c6d17ca6..32387730 100644 --- a/docs/user-guide/cpp-sdk.md +++ b/docs/user-guide/cpp-sdk.md @@ -8,6 +8,7 @@ The C++ SDK is a header-only library that provides structured message communicat - **Zero dependencies**: Core SDK has no external dependencies - **Observer pattern**: Type-safe message subscription inspired by ETLCPP - **Embedded-friendly**: Generic serial interface for bare-metal systems +- **Cross-platform**: Works on Windows, macOS, and Linux - **Network support**: UDP, TCP, WebSocket via optional ASIO integration ## Installation @@ -21,7 +22,7 @@ python -m struct_frame your_messages.proto --build_cpp --cpp_path generated/cpp Include the SDK in your project: ```cpp -#include "sdk/sdk.hpp" +#include "struct_frame_sdk/sdk.hpp" ``` ## Observer/Subscriber Pattern @@ -31,7 +32,7 @@ The C++ SDK uses an observer pattern for handling messages, providing type-safe ### Basic Observer ```cpp -#include "sdk/observer.hpp" +#include "struct_frame_sdk/observer.hpp" #include "my_messages.hpp" using namespace StructFrame; @@ -88,7 +89,7 @@ The `Subscription` class provides automatic unsubscription: The generic serial interface allows you to implement platform-specific serial I/O: ```cpp -#include "sdk/serial_transport.hpp" +#include "struct_frame_sdk/serial_transport.hpp" // Implement for your platform class STM32SerialPort : public StructFrame::ISerialPort { @@ -146,7 +147,7 @@ StructFrame::SerialTransport transport(&serialPort); For embedded systems without threading, use poll-based message handling: ```cpp -#include "sdk/struct_frame_sdk.hpp" +#include "struct_frame_sdk/struct_frame_sdk.hpp" #include "BasicDefault.hpp" #include "my_messages.hpp" @@ -196,7 +197,7 @@ For desktop/server applications, network transports use ASIO. These require exte // Not included in generated code - implement based on network_transports.hpp #include -#include "sdk/transport.hpp" +#include "struct_frame_sdk/transport.hpp" class UdpTransport : public StructFrame::BaseTransport { private: @@ -244,7 +245,7 @@ class WebSocketTransport : public StructFrame::BaseTransport { ## Complete Example ```cpp -#include "sdk/sdk.hpp" +#include "struct_frame_sdk/sdk.hpp" #include "BasicDefault.hpp" #include "robot_messages.hpp" @@ -386,7 +387,7 @@ arm-none-eabi-g++ -std=c++14 -Os -fno-exceptions -fno-rtti main.cpp -o app.elf ```cpp #include -#include "sdk/serial_transport.hpp" +#include "struct_frame_sdk/serial_transport.hpp" class ArduinoSerialPort : public StructFrame::ISerialPort { private: diff --git a/docs/user-guide/python-sdk.md b/docs/user-guide/python-sdk.md index fab32478..08d1b6b2 100644 --- a/docs/user-guide/python-sdk.md +++ b/docs/user-guide/python-sdk.md @@ -17,7 +17,7 @@ python -m struct_frame your_messages.proto --build_py --py_path generated/py #### UDP Transport ```python -from sdk import UdpTransport, UdpTransportConfig +from struct_frame_sdk import UdpTransport, UdpTransportConfig transport = UdpTransport(UdpTransportConfig( remote_host='192.168.1.100', @@ -34,7 +34,7 @@ transport = UdpTransport(UdpTransportConfig( #### TCP Transport ```python -from sdk import TcpTransport, TcpTransportConfig +from struct_frame_sdk import TcpTransport, TcpTransportConfig transport = TcpTransport(TcpTransportConfig( host='192.168.1.100', @@ -49,7 +49,7 @@ transport = TcpTransport(TcpTransportConfig( Requires `websocket-client` package: ```python -from sdk import WebSocketTransport, WebSocketTransportConfig +from struct_frame_sdk import WebSocketTransport, WebSocketTransportConfig transport = WebSocketTransport(WebSocketTransportConfig( url='ws://localhost:8080', @@ -62,7 +62,7 @@ transport = WebSocketTransport(WebSocketTransportConfig( Requires `pyserial` package: ```python -from sdk import SerialTransport, SerialTransportConfig +from struct_frame_sdk import SerialTransport, SerialTransportConfig transport = SerialTransport(SerialTransportConfig( port='/dev/ttyUSB0', # or 'COM3' on Windows @@ -78,7 +78,7 @@ transport = SerialTransport(SerialTransportConfig( All transports have async versions with `Async` prefix: ```python -from sdk import ( +from struct_frame_sdk import ( AsyncUdpTransport, AsyncUdpTransportConfig, AsyncTcpTransport, AsyncTcpTransportConfig, AsyncWebSocketTransport, AsyncWebSocketTransportConfig, @@ -91,7 +91,7 @@ from sdk import ( ### Creating the SDK ```python -from sdk import StructFrameSdk, StructFrameSdkConfig +from struct_frame_sdk import StructFrameSdk, StructFrameSdkConfig from basic_default import BasicDefault sdk = StructFrameSdk(StructFrameSdkConfig( @@ -149,7 +149,7 @@ sdk.send_raw(CommandMessage.msg_id, raw_data) ```python import time -from sdk import StructFrameSdk, StructFrameSdkConfig, TcpTransport, TcpTransportConfig +from struct_frame_sdk import StructFrameSdk, StructFrameSdkConfig, TcpTransport, TcpTransportConfig from basic_default import BasicDefault from robot_messages import StatusMessage, CommandMessage @@ -200,7 +200,7 @@ if __name__ == '__main__': ```python import asyncio -from sdk import AsyncStructFrameSdk, AsyncStructFrameSdkConfig +from struct_frame_sdk import AsyncStructFrameSdk, AsyncStructFrameSdkConfig from basic_default import BasicDefault async def main(): @@ -229,7 +229,7 @@ await sdk.disconnect() ```python import asyncio -from sdk import ( +from struct_frame_sdk import ( AsyncStructFrameSdk, AsyncStructFrameSdkConfig, AsyncTcpTransport, diff --git a/docs/user-guide/sdk-overview.md b/docs/user-guide/sdk-overview.md index 7ed3dbce..219c096c 100644 --- a/docs/user-guide/sdk-overview.md +++ b/docs/user-guide/sdk-overview.md @@ -29,7 +29,7 @@ Struct Frame provides high-level SDKs for TypeScript/JavaScript, Python, C++, an import { StructFrameSdk, UdpTransport, -} from './sdk'; +} from './struct_frame_sdk'; import { BasicDefault } from './BasicDefault'; import { MyMessage } from './my_messages'; @@ -63,7 +63,7 @@ await sdk.send(msg); ```python import asyncio -from sdk import AsyncStructFrameSdk, AsyncUdpTransport, AsyncUdpTransportConfig +from struct_frame_sdk import AsyncStructFrameSdk, AsyncUdpTransport, AsyncUdpTransportConfig from basic_default import BasicDefault from my_messages import MyMessage diff --git a/docs/user-guide/typescript-sdk.md b/docs/user-guide/typescript-sdk.md index 2cbde4ec..95284a89 100644 --- a/docs/user-guide/typescript-sdk.md +++ b/docs/user-guide/typescript-sdk.md @@ -17,7 +17,7 @@ python -m struct_frame your_messages.proto --build_ts --ts_path generated/ts Uses Node.js `dgram` module for UDP communication. ```typescript -import { UdpTransport, UdpTransportConfig } from './sdk'; +import { UdpTransport, UdpTransportConfig } from './struct_frame_sdk'; const transport = new UdpTransport({ remoteHost: '192.168.1.100', @@ -37,7 +37,7 @@ const transport = new UdpTransport({ Uses Node.js `net` module for TCP communication. ```typescript -import { TcpTransport, TcpTransportConfig } from './sdk'; +import { TcpTransport, TcpTransportConfig } from './struct_frame_sdk'; const transport = new TcpTransport({ host: '192.168.1.100', @@ -52,7 +52,7 @@ const transport = new TcpTransport({ Uses the WebSocket API (works in both browser and Node.js with `ws` package). ```typescript -import { WebSocketTransport, WebSocketTransportConfig } from './sdk'; +import { WebSocketTransport, WebSocketTransportConfig } from './struct_frame_sdk'; const transport = new WebSocketTransport({ url: 'ws://localhost:8080', @@ -66,7 +66,7 @@ const transport = new WebSocketTransport({ Uses the `serialport` package for serial communication. ```typescript -import { SerialTransport, SerialTransportConfig } from './sdk'; +import { SerialTransport, SerialTransportConfig } from './struct_frame_sdk'; const transport = new SerialTransport({ path: '/dev/ttyUSB0', // or 'COM3' on Windows @@ -82,7 +82,7 @@ const transport = new SerialTransport({ ### Creating the SDK ```typescript -import { StructFrameSdk, StructFrameSdkConfig } from './sdk'; +import { StructFrameSdk, StructFrameSdkConfig } from './struct_frame_sdk'; import { BasicDefault } from './BasicDefault'; // Frame parser const sdk = new StructFrameSdk({ @@ -170,7 +170,7 @@ sdk.subscribe(StatusMessage.msg_id, (message, msgId) => { import { StructFrameSdk, TcpTransport, -} from './sdk'; +} from './struct_frame_sdk'; import { BasicDefault } from './BasicDefault'; import { StatusMessage, CommandMessage } from './robot_messages'; diff --git a/src/struct_frame/boilerplate/cpp/sdk/network_transports.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/network_transports.hpp similarity index 100% rename from src/struct_frame/boilerplate/cpp/sdk/network_transports.hpp rename to src/struct_frame/boilerplate/cpp/struct_frame_sdk/network_transports.hpp diff --git a/src/struct_frame/boilerplate/cpp/sdk/observer.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/observer.hpp similarity index 58% rename from src/struct_frame/boilerplate/cpp/sdk/observer.hpp rename to src/struct_frame/boilerplate/cpp/struct_frame_sdk/observer.hpp index 0b0f601a..b36abfeb 100644 --- a/src/struct_frame/boilerplate/cpp/sdk/observer.hpp +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/observer.hpp @@ -3,7 +3,6 @@ #pragma once -#include #include #include @@ -13,6 +12,72 @@ namespace StructFrame { template class Observable; +/** + * Fixed-size observer list for embedded systems + * No dynamic allocation, uses static array + * @tparam T The pointer type to store + * @tparam MaxObservers Maximum number of observers + */ +template +class FixedObserverList { +private: + T observers_[MaxObservers]; + size_t count_; + +public: + FixedObserverList() : count_(0) { + for (size_t i = 0; i < MaxObservers; ++i) { + observers_[i] = nullptr; + } + } + + bool add(T observer) { + if (count_ >= MaxObservers || observer == nullptr) { + return false; + } + + // Check if already exists + for (size_t i = 0; i < count_; ++i) { + if (observers_[i] == observer) { + return false; + } + } + + observers_[count_++] = observer; + return true; + } + + bool remove(T observer) { + for (size_t i = 0; i < count_; ++i) { + if (observers_[i] == observer) { + // Shift remaining elements + for (size_t j = i; j < count_ - 1; ++j) { + observers_[j] = observers_[j + 1]; + } + observers_[count_ - 1] = nullptr; + --count_; + return true; + } + } + return false; + } + + void clear() { + for (size_t i = 0; i < count_; ++i) { + observers_[i] = nullptr; + } + count_ = 0; + } + + size_t size() const { + return count_; + } + + T operator[](size_t index) const { + return (index < count_) ? observers_[index] : nullptr; + } +}; + /** * Observer interface for receiving messages * @tparam TMessage The message type to observe @@ -54,29 +119,27 @@ class LambdaObserver : public IObserver { /** * Observable subject that notifies observers of messages * @tparam TMessage The message type + * @tparam MaxObservers Maximum number of observers (default 16) */ -template +template class Observable { public: /** * Subscribe an observer to this observable * @param observer The observer to add + * @return true if successfully subscribed, false if full or already subscribed */ - void subscribe(IObserver* observer) { - if (observer && std::find(observers_.begin(), observers_.end(), observer) == observers_.end()) { - observers_.push_back(observer); - } + bool subscribe(IObserver* observer) { + return observers_.add(observer); } /** * Unsubscribe an observer from this observable * @param observer The observer to remove + * @return true if successfully unsubscribed */ - void unsubscribe(IObserver* observer) { - observers_.erase( - std::remove(observers_.begin(), observers_.end(), observer), - observers_.end() - ); + bool unsubscribe(IObserver* observer) { + return observers_.remove(observer); } /** @@ -85,7 +148,8 @@ class Observable { * @param msgId The message ID */ void notify(const TMessage& message, uint8_t msgId) { - for (auto* observer : observers_) { + for (size_t i = 0; i < observers_.size(); ++i) { + IObserver* observer = observers_[i]; if (observer) { observer->onMessage(message, msgId); } @@ -107,19 +171,19 @@ class Observable { } private: - std::vector*> observers_; + FixedObserverList*, MaxObservers> observers_; }; /** * RAII subscription handle that automatically unsubscribes on destruction * @tparam TMessage The message type */ -template +template class Subscription { public: Subscription() : observable_(nullptr), observer_(nullptr) {} - Subscription(Observable* observable, IObserver* observer) + Subscription(Observable* observable, IObserver* observer) : observable_(observable), observer_(observer) {} ~Subscription() { @@ -157,7 +221,7 @@ class Subscription { } private: - Observable* observable_; + Observable* observable_; IObserver* observer_; }; diff --git a/src/struct_frame/boilerplate/cpp/sdk/sdk.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/sdk.hpp similarity index 100% rename from src/struct_frame/boilerplate/cpp/sdk/sdk.hpp rename to src/struct_frame/boilerplate/cpp/struct_frame_sdk/sdk.hpp diff --git a/src/struct_frame/boilerplate/cpp/sdk/serial_transport.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/serial_transport.hpp similarity index 100% rename from src/struct_frame/boilerplate/cpp/sdk/serial_transport.hpp rename to src/struct_frame/boilerplate/cpp/struct_frame_sdk/serial_transport.hpp diff --git a/src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/struct_frame_sdk.hpp similarity index 86% rename from src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp rename to src/struct_frame/boilerplate/cpp/struct_frame_sdk/struct_frame_sdk.hpp index 3c381700..ca3c1560 100644 --- a/src/struct_frame/boilerplate/cpp/sdk/struct_frame_sdk.hpp +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/struct_frame_sdk.hpp @@ -191,62 +191,66 @@ class StructFrameSdk { /** * Get or create observable for a specific message type * @tparam TMessage The message type + * @tparam MaxObservers Maximum number of observers (default 16) * @param msgId The message ID */ - template - Observable* getObservable(uint8_t msgId) { + template + Observable* getObservable(uint8_t msgId) { auto it = observables_.find(msgId); if (it == observables_.end()) { - auto* observable = new Observable(); + auto* observable = new Observable(); observables_[msgId] = static_cast(observable); return observable; } - return static_cast*>(it->second); + return static_cast*>(it->second); } /** * Subscribe to messages with a specific message ID * @tparam TMessage The message type + * @tparam MaxObservers Maximum number of observers (default 16) * @param msgId The message ID * @param observer The observer to subscribe * @return Subscription handle (RAII) */ - template - Subscription subscribe(uint8_t msgId, IObserver* observer) { - auto* observable = getObservable(msgId); + template + Subscription subscribe(uint8_t msgId, IObserver* observer) { + auto* observable = getObservable(msgId); observable->subscribe(observer); log("Subscribed to message ID " + std::to_string(msgId)); - return Subscription(observable, observer); + return Subscription(observable, observer); } /** * Subscribe with lambda function * @tparam TMessage The message type + * @tparam MaxObservers Maximum number of observers (default 16) * @param msgId The message ID * @param callback Lambda to call when message is received * @return Subscription handle (RAII) - keep alive as long as subscription is needed */ - template - Subscription subscribe(uint8_t msgId, + template + Subscription subscribe(uint8_t msgId, std::function callback) { auto* observer = new LambdaObserver(std::move(callback)); - auto* observable = getObservable(msgId); + auto* observable = getObservable(msgId); observable->subscribe(observer); log("Subscribed to message ID " + std::to_string(msgId)); - return Subscription(observable, observer); + return Subscription(observable, observer); } /** * Notify observers of a parsed message (internal use) * @tparam TMessage The message type + * @tparam MaxObservers Maximum number of observers (default 16) * @param msgId The message ID * @param message The parsed message */ - template + template void notifyObservers(uint8_t msgId, const TMessage& message) { auto it = observables_.find(msgId); if (it != observables_.end()) { - auto* observable = static_cast*>(it->second); + auto* observable = static_cast*>(it->second); observable->notify(message, msgId); } } diff --git a/src/struct_frame/boilerplate/cpp/sdk/transport.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/transport.hpp similarity index 100% rename from src/struct_frame/boilerplate/cpp/sdk/transport.hpp rename to src/struct_frame/boilerplate/cpp/struct_frame_sdk/transport.hpp diff --git a/src/struct_frame/boilerplate/csharp/sdk/SerialAndWebSocketTransports.cs b/src/struct_frame/boilerplate/csharp/struct_frame_sdk/SerialAndWebSocketTransports.cs similarity index 100% rename from src/struct_frame/boilerplate/csharp/sdk/SerialAndWebSocketTransports.cs rename to src/struct_frame/boilerplate/csharp/struct_frame_sdk/SerialAndWebSocketTransports.cs diff --git a/src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs b/src/struct_frame/boilerplate/csharp/struct_frame_sdk/StructFrameSdk.cs similarity index 100% rename from src/struct_frame/boilerplate/csharp/sdk/StructFrameSdk.cs rename to src/struct_frame/boilerplate/csharp/struct_frame_sdk/StructFrameSdk.cs diff --git a/src/struct_frame/boilerplate/csharp/sdk/TcpTransport.cs b/src/struct_frame/boilerplate/csharp/struct_frame_sdk/TcpTransport.cs similarity index 100% rename from src/struct_frame/boilerplate/csharp/sdk/TcpTransport.cs rename to src/struct_frame/boilerplate/csharp/struct_frame_sdk/TcpTransport.cs diff --git a/src/struct_frame/boilerplate/csharp/sdk/Transport.cs b/src/struct_frame/boilerplate/csharp/struct_frame_sdk/Transport.cs similarity index 100% rename from src/struct_frame/boilerplate/csharp/sdk/Transport.cs rename to src/struct_frame/boilerplate/csharp/struct_frame_sdk/Transport.cs diff --git a/src/struct_frame/boilerplate/csharp/sdk/UdpTransport.cs b/src/struct_frame/boilerplate/csharp/struct_frame_sdk/UdpTransport.cs similarity index 100% rename from src/struct_frame/boilerplate/csharp/sdk/UdpTransport.cs rename to src/struct_frame/boilerplate/csharp/struct_frame_sdk/UdpTransport.cs diff --git a/src/struct_frame/boilerplate/py/sdk/__init__.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/__init__.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/__init__.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/__init__.py diff --git a/src/struct_frame/boilerplate/py/sdk/async_serial_transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/async_serial_transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/async_serial_transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/async_serial_transport.py diff --git a/src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/async_struct_frame_sdk.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/async_struct_frame_sdk.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/async_struct_frame_sdk.py diff --git a/src/struct_frame/boilerplate/py/sdk/async_tcp_transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/async_tcp_transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/async_tcp_transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/async_tcp_transport.py diff --git a/src/struct_frame/boilerplate/py/sdk/async_transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/async_transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/async_transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/async_transport.py diff --git a/src/struct_frame/boilerplate/py/sdk/async_udp_transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/async_udp_transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/async_udp_transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/async_udp_transport.py diff --git a/src/struct_frame/boilerplate/py/sdk/async_websocket_transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/async_websocket_transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/async_websocket_transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/async_websocket_transport.py diff --git a/src/struct_frame/boilerplate/py/sdk/serial_transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/serial_transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/serial_transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/serial_transport.py diff --git a/src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/struct_frame_sdk.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/struct_frame_sdk.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/struct_frame_sdk.py diff --git a/src/struct_frame/boilerplate/py/sdk/tcp_transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/tcp_transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/tcp_transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/tcp_transport.py diff --git a/src/struct_frame/boilerplate/py/sdk/transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/transport.py diff --git a/src/struct_frame/boilerplate/py/sdk/udp_transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/udp_transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/udp_transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/udp_transport.py diff --git a/src/struct_frame/boilerplate/py/sdk/websocket_transport.py b/src/struct_frame/boilerplate/py/struct_frame_sdk/websocket_transport.py similarity index 100% rename from src/struct_frame/boilerplate/py/sdk/websocket_transport.py rename to src/struct_frame/boilerplate/py/struct_frame_sdk/websocket_transport.py diff --git a/src/struct_frame/boilerplate/ts/sdk/index.ts b/src/struct_frame/boilerplate/ts/struct_frame_sdk/index.ts similarity index 100% rename from src/struct_frame/boilerplate/ts/sdk/index.ts rename to src/struct_frame/boilerplate/ts/struct_frame_sdk/index.ts diff --git a/src/struct_frame/boilerplate/ts/sdk/serial_transport.ts b/src/struct_frame/boilerplate/ts/struct_frame_sdk/serial_transport.ts similarity index 100% rename from src/struct_frame/boilerplate/ts/sdk/serial_transport.ts rename to src/struct_frame/boilerplate/ts/struct_frame_sdk/serial_transport.ts diff --git a/src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts b/src/struct_frame/boilerplate/ts/struct_frame_sdk/struct_frame_sdk.ts similarity index 100% rename from src/struct_frame/boilerplate/ts/sdk/struct_frame_sdk.ts rename to src/struct_frame/boilerplate/ts/struct_frame_sdk/struct_frame_sdk.ts diff --git a/src/struct_frame/boilerplate/ts/sdk/tcp_transport.ts b/src/struct_frame/boilerplate/ts/struct_frame_sdk/tcp_transport.ts similarity index 100% rename from src/struct_frame/boilerplate/ts/sdk/tcp_transport.ts rename to src/struct_frame/boilerplate/ts/struct_frame_sdk/tcp_transport.ts diff --git a/src/struct_frame/boilerplate/ts/sdk/transport.ts b/src/struct_frame/boilerplate/ts/struct_frame_sdk/transport.ts similarity index 100% rename from src/struct_frame/boilerplate/ts/sdk/transport.ts rename to src/struct_frame/boilerplate/ts/struct_frame_sdk/transport.ts diff --git a/src/struct_frame/boilerplate/ts/sdk/udp_transport.ts b/src/struct_frame/boilerplate/ts/struct_frame_sdk/udp_transport.ts similarity index 100% rename from src/struct_frame/boilerplate/ts/sdk/udp_transport.ts rename to src/struct_frame/boilerplate/ts/struct_frame_sdk/udp_transport.ts diff --git a/src/struct_frame/boilerplate/ts/sdk/websocket_transport.ts b/src/struct_frame/boilerplate/ts/struct_frame_sdk/websocket_transport.ts similarity index 100% rename from src/struct_frame/boilerplate/ts/sdk/websocket_transport.ts rename to src/struct_frame/boilerplate/ts/struct_frame_sdk/websocket_transport.ts From b08c2bc85778f2fc1e178cfd86aadd12941916f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Dec 2025 20:27:22 +0000 Subject: [PATCH 7/9] Implement ASIO network transports and improve C# WebSocket handling Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- .../boilerplate/cpp/struct_frame_sdk/asio.hpp | 199 + .../asio/any_completion_executor.hpp | 336 ++ .../asio/any_completion_handler.hpp | 822 ++++ .../struct_frame_sdk/asio/any_io_executor.hpp | 351 ++ .../cpp/struct_frame_sdk/asio/append.hpp | 65 + .../cpp/struct_frame_sdk/asio/as_tuple.hpp | 126 + .../asio/associated_allocator.hpp | 214 + .../asio/associated_cancellation_slot.hpp | 221 + .../asio/associated_executor.hpp | 235 + .../asio/associated_immediate_executor.hpp | 280 ++ .../cpp/struct_frame_sdk/asio/associator.hpp | 35 + .../struct_frame_sdk/asio/async_result.hpp | 942 ++++ .../cpp/struct_frame_sdk/asio/awaitable.hpp | 142 + .../asio/basic_datagram_socket.hpp | 1362 ++++++ .../asio/basic_deadline_timer.hpp | 710 +++ .../cpp/struct_frame_sdk/asio/basic_file.hpp | 824 ++++ .../struct_frame_sdk/asio/basic_io_object.hpp | 286 ++ .../asio/basic_random_access_file.hpp | 689 +++ .../asio/basic_raw_socket.hpp | 1356 ++++++ .../asio/basic_readable_pipe.hpp | 626 +++ .../asio/basic_seq_packet_socket.hpp | 823 ++++ .../asio/basic_serial_port.hpp | 987 ++++ .../asio/basic_signal_set.hpp | 648 +++ .../struct_frame_sdk/asio/basic_socket.hpp | 1936 ++++++++ .../asio/basic_socket_acceptor.hpp | 2708 +++++++++++ .../asio/basic_socket_iostream.hpp | 331 ++ .../asio/basic_socket_streambuf.hpp | 642 +++ .../asio/basic_stream_file.hpp | 744 +++ .../asio/basic_stream_socket.hpp | 1163 +++++ .../struct_frame_sdk/asio/basic_streambuf.hpp | 450 ++ .../asio/basic_streambuf_fwd.hpp | 36 + .../asio/basic_waitable_timer.hpp | 824 ++++ .../asio/basic_writable_pipe.hpp | 622 +++ .../struct_frame_sdk/asio/bind_allocator.hpp | 530 +++ .../asio/bind_cancellation_slot.hpp | 544 +++ .../struct_frame_sdk/asio/bind_executor.hpp | 582 +++ .../asio/bind_immediate_executor.hpp | 549 +++ .../cpp/struct_frame_sdk/asio/buffer.hpp | 2751 +++++++++++ .../asio/buffer_registration.hpp | 318 ++ .../asio/buffered_read_stream.hpp | 273 ++ .../asio/buffered_read_stream_fwd.hpp | 25 + .../struct_frame_sdk/asio/buffered_stream.hpp | 292 ++ .../asio/buffered_stream_fwd.hpp | 25 + .../asio/buffered_write_stream.hpp | 265 ++ .../asio/buffered_write_stream_fwd.hpp | 25 + .../asio/buffers_iterator.hpp | 521 +++ .../asio/cancellation_signal.hpp | 245 + .../asio/cancellation_state.hpp | 235 + .../asio/cancellation_type.hpp | 157 + .../cpp/struct_frame_sdk/asio/co_spawn.hpp | 523 +++ .../asio/completion_condition.hpp | 218 + .../cpp/struct_frame_sdk/asio/compose.hpp | 319 ++ .../cpp/struct_frame_sdk/asio/connect.hpp | 1180 +++++ .../struct_frame_sdk/asio/connect_pipe.hpp | 83 + .../cpp/struct_frame_sdk/asio/consign.hpp | 75 + .../cpp/struct_frame_sdk/asio/coroutine.hpp | 329 ++ .../struct_frame_sdk/asio/deadline_timer.hpp | 38 + .../cpp/struct_frame_sdk/asio/defer.hpp | 218 + .../cpp/struct_frame_sdk/asio/deferred.hpp | 715 +++ .../cpp/struct_frame_sdk/asio/detached.hpp | 105 + .../struct_frame_sdk/asio/detail/array.hpp | 30 + .../asio/detail/array_fwd.hpp | 32 + .../struct_frame_sdk/asio/detail/assert.hpp | 32 + .../asio/detail/atomic_count.hpp | 59 + .../detail/base_from_cancellation_state.hpp | 164 + .../asio/detail/base_from_completion_cond.hpp | 69 + .../asio/detail/bind_handler.hpp | 711 +++ .../asio/detail/blocking_executor_op.hpp | 107 + .../asio/detail/buffer_resize_guard.hpp | 66 + .../asio/detail/buffer_sequence_adapter.hpp | 837 ++++ .../asio/detail/buffered_stream_storage.hpp | 126 + .../asio/detail/call_stack.hpp | 125 + .../struct_frame_sdk/asio/detail/chrono.hpp | 45 + .../asio/detail/chrono_time_traits.hpp | 190 + .../asio/detail/completion_handler.hpp | 88 + .../asio/detail/composed_work.hpp | 252 + .../asio/detail/concurrency_hint.hpp | 94 + .../detail/conditionally_enabled_event.hpp | 120 + .../detail/conditionally_enabled_mutex.hpp | 149 + .../struct_frame_sdk/asio/detail/config.hpp | 1422 ++++++ .../asio/detail/consuming_buffers.hpp | 443 ++ .../struct_frame_sdk/asio/detail/cstddef.hpp | 27 + .../struct_frame_sdk/asio/detail/cstdint.hpp | 40 + .../asio/detail/date_time_fwd.hpp | 34 + .../asio/detail/deadline_timer_service.hpp | 335 ++ .../asio/detail/dependent_type.hpp | 36 + .../asio/detail/descriptor_ops.hpp | 179 + .../asio/detail/descriptor_read_op.hpp | 188 + .../asio/detail/descriptor_write_op.hpp | 187 + .../asio/detail/dev_poll_reactor.hpp | 247 + .../asio/detail/epoll_reactor.hpp | 295 ++ .../struct_frame_sdk/asio/detail/event.hpp | 46 + .../detail/eventfd_select_interrupter.hpp | 83 + .../asio/detail/exception.hpp | 29 + .../asio/detail/executor_function.hpp | 152 + .../asio/detail/executor_op.hpp | 84 + .../asio/detail/fd_set_adapter.hpp | 39 + .../asio/detail/fenced_block.hpp | 40 + .../asio/detail/functional.hpp | 33 + .../struct_frame_sdk/asio/detail/future.hpp | 32 + .../struct_frame_sdk/asio/detail/global.hpp | 50 + .../asio/detail/handler_alloc_helpers.hpp | 225 + .../asio/detail/handler_cont_helpers.hpp | 45 + .../asio/detail/handler_tracking.hpp | 264 ++ .../asio/detail/handler_type_requirements.hpp | 553 +++ .../asio/detail/handler_work.hpp | 511 +++ .../struct_frame_sdk/asio/detail/hash_map.hpp | 331 ++ .../detail/impl/buffer_sequence_adapter.ipp | 118 + .../asio/detail/impl/descriptor_ops.ipp | 991 ++++ .../asio/detail/impl/dev_poll_reactor.hpp | 111 + .../asio/detail/impl/dev_poll_reactor.ipp | 469 ++ .../asio/detail/impl/epoll_reactor.hpp | 109 + .../asio/detail/impl/epoll_reactor.ipp | 826 ++++ .../impl/eventfd_select_interrupter.ipp | 171 + .../asio/detail/impl/handler_tracking.ipp | 398 ++ .../impl/io_uring_descriptor_service.ipp | 205 + .../detail/impl/io_uring_file_service.ipp | 140 + .../asio/detail/impl/io_uring_service.hpp | 112 + .../asio/detail/impl/io_uring_service.ipp | 914 ++++ .../impl/io_uring_socket_service_base.ipp | 249 + .../asio/detail/impl/kqueue_reactor.hpp | 113 + .../asio/detail/impl/kqueue_reactor.ipp | 608 +++ .../asio/detail/impl/null_event.ipp | 74 + .../detail/impl/pipe_select_interrupter.ipp | 129 + .../asio/detail/impl/posix_event.ipp | 63 + .../asio/detail/impl/posix_mutex.ipp | 46 + .../detail/impl/posix_serial_port_service.ipp | 168 + .../asio/detail/impl/posix_thread.ipp | 84 + .../asio/detail/impl/posix_tss_ptr.ipp | 46 + .../impl/reactive_descriptor_service.ipp | 230 + .../impl/reactive_socket_service_base.ipp | 310 ++ .../detail/impl/resolver_service_base.ipp | 158 + .../asio/detail/impl/scheduler.ipp | 675 +++ .../asio/detail/impl/select_reactor.hpp | 124 + .../asio/detail/impl/select_reactor.ipp | 400 ++ .../asio/detail/impl/service_registry.hpp | 93 + .../asio/detail/impl/service_registry.ipp | 197 + .../asio/detail/impl/signal_set_service.ipp | 826 ++++ .../asio/detail/impl/socket_ops.ipp | 4035 +++++++++++++++++ .../detail/impl/socket_select_interrupter.ipp | 185 + .../detail/impl/strand_executor_service.hpp | 346 ++ .../detail/impl/strand_executor_service.ipp | 158 + .../asio/detail/impl/strand_service.hpp | 86 + .../asio/detail/impl/strand_service.ipp | 202 + .../asio/detail/impl/thread_context.ipp | 35 + .../asio/detail/impl/throw_error.ipp | 49 + .../asio/detail/impl/timer_queue_ptime.ipp | 97 + .../asio/detail/impl/timer_queue_set.ipp | 101 + .../asio/detail/impl/win_event.ipp | 76 + .../detail/impl/win_iocp_file_service.ipp | 280 ++ .../detail/impl/win_iocp_handle_service.ipp | 619 +++ .../asio/detail/impl/win_iocp_io_context.hpp | 119 + .../asio/detail/impl/win_iocp_io_context.ipp | 614 +++ .../impl/win_iocp_serial_port_service.ipp | 200 + .../impl/win_iocp_socket_service_base.ipp | 821 ++++ .../asio/detail/impl/win_mutex.ipp | 84 + .../detail/impl/win_object_handle_service.ipp | 452 ++ .../asio/detail/impl/win_static_mutex.ipp | 136 + .../asio/detail/impl/win_thread.ipp | 150 + .../asio/detail/impl/win_tss_ptr.ipp | 57 + .../impl/winrt_ssocket_service_base.ipp | 626 +++ .../detail/impl/winrt_timer_scheduler.hpp | 92 + .../detail/impl/winrt_timer_scheduler.ipp | 121 + .../asio/detail/impl/winsock_init.ipp | 82 + .../asio/detail/initiate_defer.hpp | 207 + .../asio/detail/initiate_dispatch.hpp | 193 + .../asio/detail/initiate_post.hpp | 207 + .../asio/detail/io_control.hpp | 84 + .../asio/detail/io_object_impl.hpp | 177 + .../detail/io_uring_descriptor_read_at_op.hpp | 195 + .../detail/io_uring_descriptor_read_op.hpp | 190 + .../detail/io_uring_descriptor_service.hpp | 687 +++ .../io_uring_descriptor_write_at_op.hpp | 189 + .../detail/io_uring_descriptor_write_op.hpp | 185 + .../asio/detail/io_uring_file_service.hpp | 261 ++ .../asio/detail/io_uring_null_buffers_op.hpp | 114 + .../asio/detail/io_uring_operation.hpp | 84 + .../asio/detail/io_uring_service.hpp | 319 ++ .../asio/detail/io_uring_socket_accept_op.hpp | 280 ++ .../detail/io_uring_socket_connect_op.hpp | 140 + .../asio/detail/io_uring_socket_recv_op.hpp | 205 + .../detail/io_uring_socket_recvfrom_op.hpp | 206 + .../detail/io_uring_socket_recvmsg_op.hpp | 192 + .../asio/detail/io_uring_socket_send_op.hpp | 191 + .../asio/detail/io_uring_socket_sendto_op.hpp | 194 + .../asio/detail/io_uring_socket_service.hpp | 629 +++ .../detail/io_uring_socket_service_base.hpp | 663 +++ .../asio/detail/io_uring_wait_op.hpp | 112 + .../asio/detail/is_buffer_sequence.hpp | 296 ++ .../asio/detail/is_executor.hpp | 126 + .../asio/detail/keyword_tss_ptr.hpp | 70 + .../asio/detail/kqueue_reactor.hpp | 271 ++ .../struct_frame_sdk/asio/detail/limits.hpp | 21 + .../asio/detail/local_free_on_block_exit.hpp | 59 + .../struct_frame_sdk/asio/detail/memory.hpp | 126 + .../struct_frame_sdk/asio/detail/mutex.hpp | 46 + .../asio/detail/non_const_lvalue.hpp | 43 + .../asio/detail/noncopyable.hpp | 43 + .../asio/detail/null_event.hpp | 106 + .../asio/detail/null_fenced_block.hpp | 47 + .../asio/detail/null_global.hpp | 59 + .../asio/detail/null_mutex.hpp | 60 + .../asio/detail/null_reactor.hpp | 83 + .../asio/detail/null_signal_blocker.hpp | 69 + .../asio/detail/null_socket_service.hpp | 519 +++ .../asio/detail/null_static_mutex.hpp | 60 + .../asio/detail/null_thread.hpp | 67 + .../asio/detail/null_tss_ptr.hpp | 68 + .../asio/detail/object_pool.hpp | 171 + .../asio/detail/old_win_sdk_compat.hpp | 214 + .../struct_frame_sdk/asio/detail/op_queue.hpp | 162 + .../asio/detail/operation.hpp | 38 + .../asio/detail/pipe_select_interrupter.hpp | 89 + .../asio/detail/pop_options.hpp | 157 + .../asio/detail/posix_event.hpp | 175 + .../asio/detail/posix_fd_set_adapter.hpp | 118 + .../asio/detail/posix_global.hpp | 80 + .../asio/detail/posix_mutex.hpp | 76 + .../asio/detail/posix_serial_port_service.hpp | 249 + .../asio/detail/posix_signal_blocker.hpp | 85 + .../asio/detail/posix_static_mutex.hpp | 64 + .../asio/detail/posix_thread.hpp | 109 + .../asio/detail/posix_tss_ptr.hpp | 79 + .../asio/detail/push_options.hpp | 228 + .../detail/reactive_descriptor_service.hpp | 566 +++ .../asio/detail/reactive_null_buffers_op.hpp | 131 + .../asio/detail/reactive_socket_accept_op.hpp | 323 ++ .../detail/reactive_socket_connect_op.hpp | 162 + .../asio/detail/reactive_socket_recv_op.hpp | 197 + .../detail/reactive_socket_recvfrom_op.hpp | 203 + .../detail/reactive_socket_recvmsg_op.hpp | 184 + .../asio/detail/reactive_socket_send_op.hpp | 201 + .../asio/detail/reactive_socket_sendto_op.hpp | 194 + .../asio/detail/reactive_socket_service.hpp | 633 +++ .../detail/reactive_socket_service_base.hpp | 750 +++ .../asio/detail/reactive_wait_op.hpp | 131 + .../struct_frame_sdk/asio/detail/reactor.hpp | 54 + .../asio/detail/reactor_op.hpp | 71 + .../asio/detail/reactor_op_queue.hpp | 212 + .../asio/detail/recycling_allocator.hpp | 105 + .../asio/detail/regex_fwd.hpp | 35 + .../asio/detail/resolve_endpoint_op.hpp | 140 + .../asio/detail/resolve_op.hpp | 45 + .../asio/detail/resolve_query_op.hpp | 150 + .../asio/detail/resolver_service.hpp | 147 + .../asio/detail/resolver_service_base.hpp | 158 + .../asio/detail/scheduler.hpp | 241 + .../asio/detail/scheduler_operation.hpp | 78 + .../asio/detail/scheduler_task.hpp | 49 + .../asio/detail/scheduler_thread_info.hpp | 40 + .../asio/detail/scoped_lock.hpp | 101 + .../asio/detail/scoped_ptr.hpp | 87 + .../asio/detail/select_interrupter.hpp | 46 + .../asio/detail/select_reactor.hpp | 291 ++ .../asio/detail/service_registry.hpp | 163 + .../asio/detail/signal_blocker.hpp | 44 + .../asio/detail/signal_handler.hpp | 90 + .../asio/detail/signal_init.hpp | 47 + .../asio/detail/signal_op.hpp | 53 + .../asio/detail/signal_set_service.hpp | 292 ++ .../asio/detail/socket_holder.hpp | 98 + .../asio/detail/socket_ops.hpp | 375 ++ .../asio/detail/socket_option.hpp | 316 ++ .../asio/detail/socket_select_interrupter.hpp | 91 + .../asio/detail/socket_types.hpp | 427 ++ .../asio/detail/source_location.hpp | 45 + .../asio/detail/static_mutex.hpp | 50 + .../asio/detail/std_event.hpp | 183 + .../asio/detail/std_fenced_block.hpp | 57 + .../asio/detail/std_global.hpp | 65 + .../asio/detail/std_mutex.hpp | 68 + .../asio/detail/std_static_mutex.hpp | 76 + .../asio/detail/std_thread.hpp | 66 + .../asio/detail/strand_executor_service.hpp | 173 + .../asio/detail/strand_service.hpp | 144 + .../asio/detail/string_view.hpp | 47 + .../struct_frame_sdk/asio/detail/thread.hpp | 58 + .../asio/detail/thread_context.hpp | 51 + .../asio/detail/thread_group.hpp | 99 + .../asio/detail/thread_info_base.hpp | 250 + .../asio/detail/throw_error.hpp | 62 + .../asio/detail/throw_exception.hpp | 55 + .../asio/detail/timer_queue.hpp | 389 ++ .../asio/detail/timer_queue_base.hpp | 68 + .../asio/detail/timer_queue_ptime.hpp | 103 + .../asio/detail/timer_queue_set.hpp | 66 + .../asio/detail/timer_scheduler.hpp | 37 + .../asio/detail/timer_scheduler_fwd.hpp | 42 + .../struct_frame_sdk/asio/detail/tss_ptr.hpp | 69 + .../asio/detail/type_traits.hpp | 178 + .../struct_frame_sdk/asio/detail/utility.hpp | 83 + .../asio/detail/wait_handler.hpp | 90 + .../struct_frame_sdk/asio/detail/wait_op.hpp | 49 + .../asio/detail/win_event.hpp | 164 + .../asio/detail/win_fd_set_adapter.hpp | 149 + .../asio/detail/win_global.hpp | 71 + .../asio/detail/win_iocp_file_service.hpp | 287 ++ .../asio/detail/win_iocp_handle_read_op.hpp | 119 + .../asio/detail/win_iocp_handle_service.hpp | 431 ++ .../asio/detail/win_iocp_handle_write_op.hpp | 114 + .../asio/detail/win_iocp_io_context.hpp | 347 ++ .../asio/detail/win_iocp_null_buffers_op.hpp | 129 + .../asio/detail/win_iocp_operation.hpp | 96 + .../asio/detail/win_iocp_overlapped_op.hpp | 100 + .../asio/detail/win_iocp_overlapped_ptr.hpp | 171 + .../detail/win_iocp_serial_port_service.hpp | 233 + .../asio/detail/win_iocp_socket_accept_op.hpp | 339 ++ .../detail/win_iocp_socket_connect_op.hpp | 138 + .../asio/detail/win_iocp_socket_recv_op.hpp | 126 + .../detail/win_iocp_socket_recvfrom_op.hpp | 135 + .../detail/win_iocp_socket_recvmsg_op.hpp | 127 + .../asio/detail/win_iocp_socket_send_op.hpp | 120 + .../asio/detail/win_iocp_socket_service.hpp | 680 +++ .../detail/win_iocp_socket_service_base.hpp | 829 ++++ .../asio/detail/win_iocp_thread_info.hpp | 34 + .../asio/detail/win_iocp_wait_op.hpp | 130 + .../asio/detail/win_mutex.hpp | 78 + .../asio/detail/win_object_handle_service.hpp | 194 + .../asio/detail/win_static_mutex.hpp | 74 + .../asio/detail/win_thread.hpp | 147 + .../asio/detail/win_tss_ptr.hpp | 79 + .../asio/detail/winapp_thread.hpp | 124 + .../asio/detail/wince_thread.hpp | 124 + .../asio/detail/winrt_async_manager.hpp | 305 ++ .../asio/detail/winrt_async_op.hpp | 65 + .../asio/detail/winrt_resolve_op.hpp | 125 + .../asio/detail/winrt_resolver_service.hpp | 212 + .../asio/detail/winrt_socket_connect_op.hpp | 98 + .../asio/detail/winrt_socket_recv_op.hpp | 119 + .../asio/detail/winrt_socket_send_op.hpp | 110 + .../asio/detail/winrt_ssocket_service.hpp | 250 + .../detail/winrt_ssocket_service_base.hpp | 362 ++ .../asio/detail/winrt_timer_scheduler.hpp | 147 + .../asio/detail/winrt_utils.hpp | 106 + .../asio/detail/winsock_init.hpp | 128 + .../asio/detail/work_dispatcher.hpp | 143 + .../asio/detail/wrapped_handler.hpp | 217 + .../cpp/struct_frame_sdk/asio/dispatch.hpp | 197 + .../cpp/struct_frame_sdk/asio/error.hpp | 389 ++ .../cpp/struct_frame_sdk/asio/error_code.hpp | 39 + .../cpp/struct_frame_sdk/asio/execution.hpp | 33 + .../asio/execution/allocator.hpp | 278 ++ .../asio/execution/any_executor.hpp | 1933 ++++++++ .../asio/execution/bad_executor.hpp | 46 + .../asio/execution/blocking.hpp | 1360 ++++++ .../asio/execution/blocking_adaptation.hpp | 1080 +++++ .../asio/execution/context.hpp | 191 + .../asio/execution/context_as.hpp | 190 + .../asio/execution/executor.hpp | 116 + .../asio/execution/impl/bad_executor.ipp | 40 + .../asio/execution/invocable_archetype.hpp | 43 + .../asio/execution/mapping.hpp | 1002 ++++ .../asio/execution/occupancy.hpp | 184 + .../asio/execution/outstanding_work.hpp | 753 +++ .../asio/execution/prefer_only.hpp | 328 ++ .../asio/execution/relationship.hpp | 751 +++ .../asio/execution_context.hpp | 388 ++ .../cpp/struct_frame_sdk/asio/executor.hpp | 363 ++ .../asio/executor_work_guard.hpp | 362 ++ .../asio/experimental/append.hpp | 36 + .../asio/experimental/as_single.hpp | 132 + .../asio/experimental/as_tuple.hpp | 36 + .../asio/experimental/awaitable_operators.hpp | 536 +++ .../asio/experimental/basic_channel.hpp | 513 +++ .../experimental/basic_concurrent_channel.hpp | 513 +++ .../experimental/cancellation_condition.hpp | 152 + .../asio/experimental/channel.hpp | 70 + .../asio/experimental/channel_error.hpp | 82 + .../asio/experimental/channel_traits.hpp | 301 ++ .../asio/experimental/co_composed.hpp | 145 + .../asio/experimental/co_spawn.hpp | 187 + .../asio/experimental/concurrent_channel.hpp | 70 + .../asio/experimental/coro.hpp | 293 ++ .../asio/experimental/coro_traits.hpp | 228 + .../asio/experimental/deferred.hpp | 36 + .../experimental/detail/channel_handler.hpp | 77 + .../experimental/detail/channel_message.hpp | 129 + .../experimental/detail/channel_operation.hpp | 361 ++ .../experimental/detail/channel_payload.hpp | 222 + .../detail/channel_receive_op.hpp | 127 + .../detail/channel_send_functions.hpp | 192 + .../experimental/detail/channel_send_op.hpp | 148 + .../experimental/detail/channel_service.hpp | 677 +++ .../detail/coro_completion_handler.hpp | 169 + .../detail/coro_promise_allocator.hpp | 141 + .../experimental/detail/has_signature.hpp | 54 + .../detail/impl/channel_service.hpp | 621 +++ .../experimental/detail/partial_promise.hpp | 197 + .../asio/experimental/impl/as_single.hpp | 176 + .../asio/experimental/impl/channel_error.ipp | 61 + .../asio/experimental/impl/co_composed.hpp | 1174 +++++ .../asio/experimental/impl/coro.hpp | 1222 +++++ .../asio/experimental/impl/parallel_group.hpp | 788 ++++ .../asio/experimental/impl/promise.hpp | 255 ++ .../asio/experimental/impl/use_coro.hpp | 214 + .../asio/experimental/impl/use_promise.hpp | 66 + .../asio/experimental/parallel_group.hpp | 457 ++ .../asio/experimental/prepend.hpp | 36 + .../asio/experimental/promise.hpp | 224 + .../asio/experimental/use_coro.hpp | 189 + .../asio/experimental/use_promise.hpp | 111 + .../cpp/struct_frame_sdk/asio/file_base.hpp | 166 + .../asio/generic/basic_endpoint.hpp | 189 + .../asio/generic/datagram_protocol.hpp | 123 + .../asio/generic/detail/endpoint.hpp | 133 + .../asio/generic/detail/impl/endpoint.ipp | 110 + .../asio/generic/raw_protocol.hpp | 121 + .../asio/generic/seq_packet_protocol.hpp | 122 + .../asio/generic/stream_protocol.hpp | 127 + .../asio/handler_continuation_hook.hpp | 54 + .../asio/high_resolution_timer.hpp | 39 + .../asio/impl/any_completion_executor.ipp | 126 + .../asio/impl/any_io_executor.ipp | 134 + .../cpp/struct_frame_sdk/asio/impl/append.hpp | 162 + .../struct_frame_sdk/asio/impl/as_tuple.hpp | 245 + .../struct_frame_sdk/asio/impl/awaitable.hpp | 1196 +++++ .../asio/impl/buffered_read_stream.hpp | 404 ++ .../asio/impl/buffered_write_stream.hpp | 384 ++ .../asio/impl/cancellation_signal.ipp | 96 + .../struct_frame_sdk/asio/impl/co_spawn.hpp | 449 ++ .../struct_frame_sdk/asio/impl/connect.hpp | 809 ++++ .../asio/impl/connect_pipe.hpp | 73 + .../asio/impl/connect_pipe.ipp | 149 + .../struct_frame_sdk/asio/impl/consign.hpp | 137 + .../struct_frame_sdk/asio/impl/deferred.hpp | 147 + .../struct_frame_sdk/asio/impl/detached.hpp | 77 + .../cpp/struct_frame_sdk/asio/impl/error.ipp | 128 + .../struct_frame_sdk/asio/impl/error_code.ipp | 206 + .../asio/impl/execution_context.hpp | 77 + .../asio/impl/execution_context.ipp | 82 + .../struct_frame_sdk/asio/impl/executor.hpp | 317 ++ .../struct_frame_sdk/asio/impl/executor.ipp | 43 + .../struct_frame_sdk/asio/impl/io_context.hpp | 433 ++ .../struct_frame_sdk/asio/impl/io_context.ipp | 176 + .../asio/impl/multiple_exceptions.ipp | 45 + .../struct_frame_sdk/asio/impl/prepend.hpp | 163 + .../cpp/struct_frame_sdk/asio/impl/read.hpp | 1053 +++++ .../struct_frame_sdk/asio/impl/read_at.hpp | 628 +++ .../struct_frame_sdk/asio/impl/read_until.hpp | 2941 ++++++++++++ .../asio/impl/redirect_error.hpp | 250 + .../asio/impl/serial_port_base.hpp | 59 + .../asio/impl/serial_port_base.ipp | 554 +++ .../cpp/struct_frame_sdk/asio/impl/spawn.hpp | 1400 ++++++ .../cpp/struct_frame_sdk/asio/impl/src.hpp | 94 + .../asio/impl/system_context.hpp | 34 + .../asio/impl/system_context.ipp | 92 + .../asio/impl/system_executor.hpp | 179 + .../asio/impl/thread_pool.hpp | 277 ++ .../asio/impl/thread_pool.ipp | 142 + .../asio/impl/use_awaitable.hpp | 301 ++ .../struct_frame_sdk/asio/impl/use_future.hpp | 707 +++ .../cpp/struct_frame_sdk/asio/impl/write.hpp | 939 ++++ .../struct_frame_sdk/asio/impl/write_at.hpp | 551 +++ .../cpp/struct_frame_sdk/asio/io_context.hpp | 1505 ++++++ .../asio/io_context_strand.hpp | 396 ++ .../cpp/struct_frame_sdk/asio/io_service.hpp | 33 + .../asio/io_service_strand.hpp | 20 + .../cpp/struct_frame_sdk/asio/ip/address.hpp | 281 ++ .../struct_frame_sdk/asio/ip/address_v4.hpp | 421 ++ .../asio/ip/address_v4_iterator.hpp | 156 + .../asio/ip/address_v4_range.hpp | 128 + .../struct_frame_sdk/asio/ip/address_v6.hpp | 407 ++ .../asio/ip/address_v6_iterator.hpp | 178 + .../asio/ip/address_v6_range.hpp | 124 + .../asio/ip/bad_address_cast.hpp | 63 + .../asio/ip/basic_endpoint.hpp | 282 ++ .../asio/ip/basic_resolver.hpp | 1112 +++++ .../asio/ip/basic_resolver_entry.hpp | 113 + .../asio/ip/basic_resolver_iterator.hpp | 188 + .../asio/ip/basic_resolver_query.hpp | 260 ++ .../asio/ip/basic_resolver_results.hpp | 307 ++ .../asio/ip/detail/endpoint.hpp | 141 + .../asio/ip/detail/impl/endpoint.ipp | 195 + .../asio/ip/detail/socket_option.hpp | 566 +++ .../struct_frame_sdk/asio/ip/host_name.hpp | 42 + .../cpp/struct_frame_sdk/asio/ip/icmp.hpp | 115 + .../struct_frame_sdk/asio/ip/impl/address.hpp | 67 + .../struct_frame_sdk/asio/ip/impl/address.ipp | 235 + .../asio/ip/impl/address_v4.hpp | 67 + .../asio/ip/impl/address_v4.ipp | 206 + .../asio/ip/impl/address_v6.hpp | 67 + .../asio/ip/impl/address_v6.ipp | 342 ++ .../asio/ip/impl/basic_endpoint.hpp | 43 + .../asio/ip/impl/host_name.ipp | 54 + .../asio/ip/impl/network_v4.hpp | 54 + .../asio/ip/impl/network_v4.ipp | 218 + .../asio/ip/impl/network_v6.hpp | 53 + .../asio/ip/impl/network_v6.ipp | 187 + .../struct_frame_sdk/asio/ip/multicast.hpp | 191 + .../struct_frame_sdk/asio/ip/network_v4.hpp | 257 ++ .../struct_frame_sdk/asio/ip/network_v6.hpp | 231 + .../asio/ip/resolver_base.hpp | 129 + .../asio/ip/resolver_query_base.hpp | 43 + .../cpp/struct_frame_sdk/asio/ip/tcp.hpp | 155 + .../cpp/struct_frame_sdk/asio/ip/udp.hpp | 111 + .../cpp/struct_frame_sdk/asio/ip/unicast.hpp | 70 + .../cpp/struct_frame_sdk/asio/ip/v6_only.hpp | 69 + .../asio/is_applicable_property.hpp | 61 + .../asio/is_contiguous_iterator.hpp | 45 + .../cpp/struct_frame_sdk/asio/is_executor.hpp | 46 + .../asio/is_read_buffered.hpp | 59 + .../asio/is_write_buffered.hpp | 59 + .../asio/local/basic_endpoint.hpp | 243 + .../asio/local/connect_pair.hpp | 101 + .../asio/local/datagram_protocol.hpp | 80 + .../asio/local/detail/endpoint.hpp | 139 + .../asio/local/detail/impl/endpoint.ipp | 131 + .../asio/local/seq_packet_protocol.hpp | 84 + .../asio/local/stream_protocol.hpp | 90 + .../asio/multiple_exceptions.hpp | 52 + .../struct_frame_sdk/asio/packaged_task.hpp | 66 + .../struct_frame_sdk/asio/placeholders.hpp | 75 + .../asio/posix/basic_descriptor.hpp | 773 ++++ .../asio/posix/basic_stream_descriptor.hpp | 559 +++ .../asio/posix/descriptor.hpp | 37 + .../asio/posix/descriptor_base.hpp | 90 + .../asio/posix/stream_descriptor.hpp | 37 + .../cpp/struct_frame_sdk/asio/post.hpp | 213 + .../cpp/struct_frame_sdk/asio/prefer.hpp | 577 +++ .../cpp/struct_frame_sdk/asio/prepend.hpp | 66 + .../cpp/struct_frame_sdk/asio/query.hpp | 311 ++ .../asio/random_access_file.hpp | 35 + .../cpp/struct_frame_sdk/asio/read.hpp | 1448 ++++++ .../cpp/struct_frame_sdk/asio/read_at.hpp | 778 ++++ .../cpp/struct_frame_sdk/asio/read_until.hpp | 3124 +++++++++++++ .../struct_frame_sdk/asio/readable_pipe.hpp | 35 + .../asio/recycling_allocator.hpp | 138 + .../struct_frame_sdk/asio/redirect_error.hpp | 64 + .../asio/registered_buffer.hpp | 344 ++ .../cpp/struct_frame_sdk/asio/require.hpp | 433 ++ .../struct_frame_sdk/asio/require_concept.hpp | 343 ++ .../cpp/struct_frame_sdk/asio/serial_port.hpp | 36 + .../asio/serial_port_base.hpp | 167 + .../cpp/struct_frame_sdk/asio/signal_set.hpp | 28 + .../struct_frame_sdk/asio/signal_set_base.hpp | 171 + .../cpp/struct_frame_sdk/asio/socket_base.hpp | 559 +++ .../cpp/struct_frame_sdk/asio/spawn.hpp | 872 ++++ .../cpp/struct_frame_sdk/asio/ssl.hpp | 28 + .../cpp/struct_frame_sdk/asio/ssl/context.hpp | 762 ++++ .../asio/ssl/context_base.hpp | 209 + .../asio/ssl/detail/buffered_handshake_op.hpp | 119 + .../asio/ssl/detail/engine.hpp | 169 + .../asio/ssl/detail/handshake_op.hpp | 67 + .../asio/ssl/detail/impl/engine.ipp | 377 ++ .../asio/ssl/detail/impl/openssl_init.ipp | 169 + .../struct_frame_sdk/asio/ssl/detail/io.hpp | 376 ++ .../asio/ssl/detail/openssl_init.hpp | 101 + .../asio/ssl/detail/openssl_types.hpp | 34 + .../asio/ssl/detail/password_callback.hpp | 66 + .../asio/ssl/detail/read_op.hpp | 72 + .../asio/ssl/detail/shutdown_op.hpp | 69 + .../asio/ssl/detail/stream_core.hpp | 217 + .../asio/ssl/detail/verify_callback.hpp | 62 + .../asio/ssl/detail/write_op.hpp | 76 + .../cpp/struct_frame_sdk/asio/ssl/error.hpp | 123 + .../asio/ssl/host_name_verification.hpp | 90 + .../asio/ssl/impl/context.hpp | 67 + .../asio/ssl/impl/context.ipp | 1319 ++++++ .../struct_frame_sdk/asio/ssl/impl/error.ipp | 124 + .../asio/ssl/impl/host_name_verification.ipp | 73 + .../asio/ssl/impl/rfc2818_verification.ipp | 164 + .../struct_frame_sdk/asio/ssl/impl/src.hpp | 29 + .../asio/ssl/rfc2818_verification.hpp | 98 + .../cpp/struct_frame_sdk/asio/ssl/stream.hpp | 1042 +++++ .../struct_frame_sdk/asio/ssl/stream_base.hpp | 52 + .../asio/ssl/verify_context.hpp | 67 + .../struct_frame_sdk/asio/ssl/verify_mode.hpp | 63 + .../asio/static_thread_pool.hpp | 31 + .../struct_frame_sdk/asio/steady_timer.hpp | 37 + .../cpp/struct_frame_sdk/asio/strand.hpp | 557 +++ .../cpp/struct_frame_sdk/asio/stream_file.hpp | 35 + .../cpp/struct_frame_sdk/asio/streambuf.hpp | 33 + .../struct_frame_sdk/asio/system_context.hpp | 90 + .../struct_frame_sdk/asio/system_error.hpp | 31 + .../struct_frame_sdk/asio/system_executor.hpp | 671 +++ .../struct_frame_sdk/asio/system_timer.hpp | 37 + .../cpp/struct_frame_sdk/asio/this_coro.hpp | 267 ++ .../cpp/struct_frame_sdk/asio/thread.hpp | 92 + .../cpp/struct_frame_sdk/asio/thread_pool.hpp | 963 ++++ .../cpp/struct_frame_sdk/asio/time_traits.hpp | 86 + .../asio/traits/equality_comparable.hpp | 100 + .../asio/traits/execute_member.hpp | 104 + .../asio/traits/prefer_free.hpp | 104 + .../asio/traits/prefer_member.hpp | 104 + .../asio/traits/query_free.hpp | 104 + .../asio/traits/query_member.hpp | 104 + .../traits/query_static_constexpr_member.hpp | 101 + .../asio/traits/require_concept_free.hpp | 104 + .../asio/traits/require_concept_member.hpp | 104 + .../asio/traits/require_free.hpp | 104 + .../asio/traits/require_member.hpp | 104 + .../asio/traits/static_query.hpp | 102 + .../asio/traits/static_require.hpp | 115 + .../asio/traits/static_require_concept.hpp | 116 + .../cpp/struct_frame_sdk/asio/ts/buffer.hpp | 24 + .../cpp/struct_frame_sdk/asio/ts/executor.hpp | 35 + .../cpp/struct_frame_sdk/asio/ts/internet.hpp | 40 + .../struct_frame_sdk/asio/ts/io_context.hpp | 20 + .../cpp/struct_frame_sdk/asio/ts/net.hpp | 26 + .../cpp/struct_frame_sdk/asio/ts/netfwd.hpp | 236 + .../cpp/struct_frame_sdk/asio/ts/socket.hpp | 27 + .../cpp/struct_frame_sdk/asio/ts/timer.hpp | 26 + .../cpp/struct_frame_sdk/asio/unyield.hpp | 21 + .../struct_frame_sdk/asio/use_awaitable.hpp | 161 + .../cpp/struct_frame_sdk/asio/use_future.hpp | 159 + .../struct_frame_sdk/asio/uses_executor.hpp | 67 + .../cpp/struct_frame_sdk/asio/version.hpp | 23 + .../cpp/struct_frame_sdk/asio/wait_traits.hpp | 56 + .../asio/windows/basic_object_handle.hpp | 485 ++ .../asio/windows/basic_overlapped_handle.hpp | 455 ++ .../windows/basic_random_access_handle.hpp | 567 +++ .../asio/windows/basic_stream_handle.hpp | 551 +++ .../asio/windows/object_handle.hpp | 38 + .../asio/windows/overlapped_handle.hpp | 39 + .../asio/windows/overlapped_ptr.hpp | 145 + .../asio/windows/random_access_handle.hpp | 37 + .../asio/windows/stream_handle.hpp | 37 + .../struct_frame_sdk/asio/writable_pipe.hpp | 35 + .../cpp/struct_frame_sdk/asio/write.hpp | 1414 ++++++ .../cpp/struct_frame_sdk/asio/write_at.hpp | 789 ++++ .../cpp/struct_frame_sdk/asio/yield.hpp | 23 + .../struct_frame_sdk/network_transports.hpp | 402 +- .../SerialAndWebSocketTransports.cs | 81 +- 623 files changed, 168215 insertions(+), 124 deletions(-) create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_completion_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_completion_handler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_io_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/append.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/as_tuple.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_allocator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_cancellation_slot.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_immediate_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/async_result.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/awaitable.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_datagram_socket.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_deadline_timer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_file.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_io_object.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_random_access_file.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_raw_socket.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_readable_pipe.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_seq_packet_socket.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_serial_port.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_signal_set.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_socket.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_socket_acceptor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_socket_iostream.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_socket_streambuf.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_stream_file.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_stream_socket.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_streambuf.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_streambuf_fwd.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_waitable_timer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/basic_writable_pipe.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/bind_allocator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/bind_cancellation_slot.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/bind_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/bind_immediate_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/buffer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/buffer_registration.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/buffered_read_stream.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/buffered_read_stream_fwd.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/buffered_stream.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/buffered_stream_fwd.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/buffered_write_stream.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/buffered_write_stream_fwd.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/buffers_iterator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/cancellation_signal.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/cancellation_state.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/cancellation_type.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/co_spawn.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/completion_condition.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/compose.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/connect.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/connect_pipe.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/consign.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/coroutine.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/deadline_timer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/defer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/deferred.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detached.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/array.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/array_fwd.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/assert.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/atomic_count.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/base_from_cancellation_state.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/base_from_completion_cond.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/bind_handler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/blocking_executor_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/buffer_resize_guard.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/buffer_sequence_adapter.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/buffered_stream_storage.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/call_stack.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/chrono.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/chrono_time_traits.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/completion_handler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/composed_work.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/concurrency_hint.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/conditionally_enabled_event.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/conditionally_enabled_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/config.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/consuming_buffers.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/cstddef.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/cstdint.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/date_time_fwd.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/deadline_timer_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/dependent_type.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/descriptor_ops.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/descriptor_read_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/descriptor_write_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/dev_poll_reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/epoll_reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/event.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/eventfd_select_interrupter.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/exception.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/executor_function.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/executor_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/fd_set_adapter.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/fenced_block.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/functional.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/future.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/global.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/handler_alloc_helpers.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/handler_cont_helpers.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/handler_tracking.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/handler_type_requirements.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/handler_work.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/hash_map.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/buffer_sequence_adapter.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/descriptor_ops.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/dev_poll_reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/dev_poll_reactor.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/epoll_reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/epoll_reactor.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/eventfd_select_interrupter.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/handler_tracking.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/io_uring_descriptor_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/io_uring_file_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/io_uring_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/io_uring_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/io_uring_socket_service_base.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/kqueue_reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/kqueue_reactor.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/null_event.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/pipe_select_interrupter.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/posix_event.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/posix_mutex.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/posix_serial_port_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/posix_thread.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/posix_tss_ptr.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/reactive_descriptor_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/reactive_socket_service_base.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/resolver_service_base.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/scheduler.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/select_reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/select_reactor.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/service_registry.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/service_registry.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/signal_set_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/socket_ops.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/socket_select_interrupter.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/strand_executor_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/strand_executor_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/strand_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/strand_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/thread_context.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/throw_error.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/timer_queue_ptime.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/timer_queue_set.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_event.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_iocp_file_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_iocp_handle_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_iocp_io_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_iocp_io_context.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_iocp_serial_port_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_iocp_socket_service_base.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_mutex.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_object_handle_service.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_static_mutex.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_thread.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/win_tss_ptr.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/winrt_ssocket_service_base.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/winrt_timer_scheduler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/winrt_timer_scheduler.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/impl/winsock_init.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/initiate_defer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/initiate_dispatch.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/initiate_post.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_control.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_object_impl.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_descriptor_read_at_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_descriptor_read_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_descriptor_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_descriptor_write_at_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_descriptor_write_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_file_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_null_buffers_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_operation.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_socket_accept_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_socket_connect_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_socket_recv_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_socket_recvfrom_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_socket_recvmsg_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_socket_send_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_socket_sendto_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_socket_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_socket_service_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/io_uring_wait_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/is_buffer_sequence.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/is_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/keyword_tss_ptr.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/kqueue_reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/limits.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/local_free_on_block_exit.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/memory.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/non_const_lvalue.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/noncopyable.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_event.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_fenced_block.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_global.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_signal_blocker.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_socket_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_static_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_thread.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/null_tss_ptr.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/object_pool.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/old_win_sdk_compat.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/op_queue.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/operation.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/pipe_select_interrupter.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/pop_options.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/posix_event.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/posix_fd_set_adapter.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/posix_global.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/posix_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/posix_serial_port_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/posix_signal_blocker.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/posix_static_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/posix_thread.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/posix_tss_ptr.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/push_options.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_descriptor_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_null_buffers_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_socket_accept_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_socket_connect_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_socket_recv_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_socket_recvfrom_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_socket_recvmsg_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_socket_send_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_socket_sendto_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_socket_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_socket_service_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactive_wait_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactor_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/reactor_op_queue.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/recycling_allocator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/regex_fwd.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/resolve_endpoint_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/resolve_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/resolve_query_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/resolver_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/resolver_service_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/scheduler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/scheduler_operation.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/scheduler_task.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/scheduler_thread_info.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/scoped_lock.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/scoped_ptr.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/select_interrupter.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/select_reactor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/service_registry.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/signal_blocker.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/signal_handler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/signal_init.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/signal_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/signal_set_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/socket_holder.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/socket_ops.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/socket_option.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/socket_select_interrupter.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/socket_types.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/source_location.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/static_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/std_event.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/std_fenced_block.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/std_global.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/std_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/std_static_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/std_thread.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/strand_executor_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/strand_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/string_view.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/thread.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/thread_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/thread_group.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/thread_info_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/throw_error.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/throw_exception.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/timer_queue.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/timer_queue_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/timer_queue_ptime.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/timer_queue_set.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/timer_scheduler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/timer_scheduler_fwd.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/tss_ptr.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/type_traits.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/utility.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/wait_handler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/wait_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_event.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_fd_set_adapter.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_global.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_file_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_handle_read_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_handle_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_handle_write_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_io_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_null_buffers_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_operation.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_overlapped_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_overlapped_ptr.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_serial_port_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_socket_accept_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_socket_connect_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_socket_recv_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_socket_recvfrom_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_socket_recvmsg_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_socket_send_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_socket_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_socket_service_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_thread_info.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_iocp_wait_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_object_handle_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_static_mutex.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_thread.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/win_tss_ptr.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winapp_thread.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/wince_thread.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_async_manager.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_async_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_resolve_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_resolver_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_socket_connect_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_socket_recv_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_socket_send_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_ssocket_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_ssocket_service_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_timer_scheduler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winrt_utils.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/winsock_init.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/work_dispatcher.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/detail/wrapped_handler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/dispatch.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/error.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/error_code.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/allocator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/any_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/bad_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/blocking.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/blocking_adaptation.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/context_as.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/impl/bad_executor.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/invocable_archetype.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/mapping.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/occupancy.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/outstanding_work.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/prefer_only.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution/relationship.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/execution_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/executor_work_guard.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/append.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/as_single.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/as_tuple.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/awaitable_operators.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/basic_channel.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/basic_concurrent_channel.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/cancellation_condition.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/channel.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/channel_error.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/channel_traits.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/co_composed.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/co_spawn.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/concurrent_channel.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/coro.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/coro_traits.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/deferred.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/channel_handler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/channel_message.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/channel_operation.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/channel_payload.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/channel_receive_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/channel_send_functions.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/channel_send_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/channel_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/coro_completion_handler.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/coro_promise_allocator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/has_signature.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/impl/channel_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/detail/partial_promise.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/impl/as_single.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/impl/channel_error.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/impl/co_composed.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/impl/coro.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/impl/parallel_group.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/impl/promise.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/impl/use_coro.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/impl/use_promise.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/parallel_group.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/prepend.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/promise.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/use_coro.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/experimental/use_promise.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/file_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/generic/basic_endpoint.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/generic/datagram_protocol.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/generic/detail/endpoint.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/generic/detail/impl/endpoint.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/generic/raw_protocol.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/generic/seq_packet_protocol.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/generic/stream_protocol.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/handler_continuation_hook.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/high_resolution_timer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/any_completion_executor.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/any_io_executor.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/append.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/as_tuple.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/awaitable.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/buffered_read_stream.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/buffered_write_stream.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/cancellation_signal.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/co_spawn.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/connect.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/connect_pipe.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/connect_pipe.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/consign.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/deferred.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/detached.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/error.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/error_code.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/execution_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/execution_context.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/executor.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/io_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/io_context.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/multiple_exceptions.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/prepend.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/read.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/read_at.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/read_until.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/redirect_error.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/serial_port_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/serial_port_base.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/spawn.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/src.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/system_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/system_context.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/system_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/thread_pool.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/thread_pool.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/use_awaitable.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/use_future.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/write.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/impl/write_at.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/io_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/io_context_strand.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/io_service.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/io_service_strand.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/address.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/address_v4.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/address_v4_iterator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/address_v4_range.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/address_v6.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/address_v6_iterator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/address_v6_range.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/bad_address_cast.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/basic_endpoint.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/basic_resolver.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/basic_resolver_entry.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/basic_resolver_iterator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/basic_resolver_query.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/basic_resolver_results.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/detail/endpoint.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/detail/impl/endpoint.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/detail/socket_option.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/host_name.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/icmp.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/address.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/address.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/address_v4.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/address_v4.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/address_v6.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/address_v6.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/basic_endpoint.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/host_name.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/network_v4.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/network_v4.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/network_v6.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/impl/network_v6.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/multicast.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/network_v4.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/network_v6.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/resolver_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/resolver_query_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/tcp.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/udp.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/unicast.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ip/v6_only.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/is_applicable_property.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/is_contiguous_iterator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/is_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/is_read_buffered.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/is_write_buffered.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/local/basic_endpoint.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/local/connect_pair.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/local/datagram_protocol.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/local/detail/endpoint.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/local/detail/impl/endpoint.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/local/seq_packet_protocol.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/local/stream_protocol.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/multiple_exceptions.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/packaged_task.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/placeholders.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/posix/basic_descriptor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/posix/basic_stream_descriptor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/posix/descriptor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/posix/descriptor_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/posix/stream_descriptor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/post.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/prefer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/prepend.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/query.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/random_access_file.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/read.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/read_at.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/read_until.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/readable_pipe.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/recycling_allocator.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/redirect_error.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/registered_buffer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/require.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/require_concept.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/serial_port.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/serial_port_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/signal_set.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/signal_set_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/socket_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/spawn.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/context_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/buffered_handshake_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/engine.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/handshake_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/impl/engine.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/impl/openssl_init.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/io.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/openssl_init.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/openssl_types.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/password_callback.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/read_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/shutdown_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/stream_core.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/verify_callback.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/detail/write_op.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/error.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/host_name_verification.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/impl/context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/impl/context.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/impl/error.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/impl/host_name_verification.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/impl/rfc2818_verification.ipp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/impl/src.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/rfc2818_verification.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/stream.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/stream_base.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/verify_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ssl/verify_mode.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/static_thread_pool.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/steady_timer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/strand.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/stream_file.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/streambuf.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/system_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/system_error.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/system_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/system_timer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/this_coro.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/thread.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/thread_pool.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/time_traits.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/equality_comparable.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/execute_member.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/prefer_free.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/prefer_member.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/query_free.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/query_member.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/query_static_constexpr_member.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/require_concept_free.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/require_concept_member.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/require_free.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/require_member.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/static_query.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/static_require.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/traits/static_require_concept.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ts/buffer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ts/executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ts/internet.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ts/io_context.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ts/net.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ts/netfwd.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ts/socket.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/ts/timer.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/unyield.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/use_awaitable.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/use_future.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/uses_executor.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/version.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/wait_traits.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/windows/basic_object_handle.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/windows/basic_overlapped_handle.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/windows/basic_random_access_handle.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/windows/basic_stream_handle.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/windows/object_handle.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/windows/overlapped_handle.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/windows/overlapped_ptr.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/windows/random_access_handle.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/windows/stream_handle.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/writable_pipe.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/write.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/write_at.hpp create mode 100644 src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/yield.hpp diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio.hpp new file mode 100644 index 00000000..3421b58b --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio.hpp @@ -0,0 +1,199 @@ +// +// asio.hpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_HPP +#define ASIO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/any_completion_executor.hpp" +#include "asio/any_completion_handler.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/append.hpp" +#include "asio/as_tuple.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_cancellation_slot.hpp" +#include "asio/associated_executor.hpp" +#include "asio/associated_immediate_executor.hpp" +#include "asio/associator.hpp" +#include "asio/async_result.hpp" +#include "asio/awaitable.hpp" +#include "asio/basic_datagram_socket.hpp" +#include "asio/basic_deadline_timer.hpp" +#include "asio/basic_file.hpp" +#include "asio/basic_io_object.hpp" +#include "asio/basic_random_access_file.hpp" +#include "asio/basic_raw_socket.hpp" +#include "asio/basic_readable_pipe.hpp" +#include "asio/basic_seq_packet_socket.hpp" +#include "asio/basic_serial_port.hpp" +#include "asio/basic_signal_set.hpp" +#include "asio/basic_socket.hpp" +#include "asio/basic_socket_acceptor.hpp" +#include "asio/basic_socket_iostream.hpp" +#include "asio/basic_socket_streambuf.hpp" +#include "asio/basic_stream_file.hpp" +#include "asio/basic_stream_socket.hpp" +#include "asio/basic_streambuf.hpp" +#include "asio/basic_waitable_timer.hpp" +#include "asio/basic_writable_pipe.hpp" +#include "asio/bind_allocator.hpp" +#include "asio/bind_cancellation_slot.hpp" +#include "asio/bind_executor.hpp" +#include "asio/bind_immediate_executor.hpp" +#include "asio/buffer.hpp" +#include "asio/buffer_registration.hpp" +#include "asio/buffered_read_stream_fwd.hpp" +#include "asio/buffered_read_stream.hpp" +#include "asio/buffered_stream_fwd.hpp" +#include "asio/buffered_stream.hpp" +#include "asio/buffered_write_stream_fwd.hpp" +#include "asio/buffered_write_stream.hpp" +#include "asio/buffers_iterator.hpp" +#include "asio/cancellation_signal.hpp" +#include "asio/cancellation_state.hpp" +#include "asio/cancellation_type.hpp" +#include "asio/co_spawn.hpp" +#include "asio/completion_condition.hpp" +#include "asio/compose.hpp" +#include "asio/connect.hpp" +#include "asio/connect_pipe.hpp" +#include "asio/consign.hpp" +#include "asio/coroutine.hpp" +#include "asio/deadline_timer.hpp" +#include "asio/defer.hpp" +#include "asio/deferred.hpp" +#include "asio/detached.hpp" +#include "asio/dispatch.hpp" +#include "asio/error.hpp" +#include "asio/error_code.hpp" +#include "asio/execution.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/any_executor.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/blocking_adaptation.hpp" +#include "asio/execution/context.hpp" +#include "asio/execution/context_as.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/invocable_archetype.hpp" +#include "asio/execution/mapping.hpp" +#include "asio/execution/occupancy.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/execution/prefer_only.hpp" +#include "asio/execution/relationship.hpp" +#include "asio/executor.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/file_base.hpp" +#include "asio/generic/basic_endpoint.hpp" +#include "asio/generic/datagram_protocol.hpp" +#include "asio/generic/raw_protocol.hpp" +#include "asio/generic/seq_packet_protocol.hpp" +#include "asio/generic/stream_protocol.hpp" +#include "asio/handler_continuation_hook.hpp" +#include "asio/high_resolution_timer.hpp" +#include "asio/io_context.hpp" +#include "asio/io_context_strand.hpp" +#include "asio/io_service.hpp" +#include "asio/io_service_strand.hpp" +#include "asio/ip/address.hpp" +#include "asio/ip/address_v4.hpp" +#include "asio/ip/address_v4_iterator.hpp" +#include "asio/ip/address_v4_range.hpp" +#include "asio/ip/address_v6.hpp" +#include "asio/ip/address_v6_iterator.hpp" +#include "asio/ip/address_v6_range.hpp" +#include "asio/ip/network_v4.hpp" +#include "asio/ip/network_v6.hpp" +#include "asio/ip/bad_address_cast.hpp" +#include "asio/ip/basic_endpoint.hpp" +#include "asio/ip/basic_resolver.hpp" +#include "asio/ip/basic_resolver_entry.hpp" +#include "asio/ip/basic_resolver_iterator.hpp" +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/host_name.hpp" +#include "asio/ip/icmp.hpp" +#include "asio/ip/multicast.hpp" +#include "asio/ip/resolver_base.hpp" +#include "asio/ip/resolver_query_base.hpp" +#include "asio/ip/tcp.hpp" +#include "asio/ip/udp.hpp" +#include "asio/ip/unicast.hpp" +#include "asio/ip/v6_only.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/is_contiguous_iterator.hpp" +#include "asio/is_executor.hpp" +#include "asio/is_read_buffered.hpp" +#include "asio/is_write_buffered.hpp" +#include "asio/local/basic_endpoint.hpp" +#include "asio/local/connect_pair.hpp" +#include "asio/local/datagram_protocol.hpp" +#include "asio/local/seq_packet_protocol.hpp" +#include "asio/local/stream_protocol.hpp" +#include "asio/multiple_exceptions.hpp" +#include "asio/packaged_task.hpp" +#include "asio/placeholders.hpp" +#include "asio/posix/basic_descriptor.hpp" +#include "asio/posix/basic_stream_descriptor.hpp" +#include "asio/posix/descriptor.hpp" +#include "asio/posix/descriptor_base.hpp" +#include "asio/posix/stream_descriptor.hpp" +#include "asio/post.hpp" +#include "asio/prefer.hpp" +#include "asio/prepend.hpp" +#include "asio/query.hpp" +#include "asio/random_access_file.hpp" +#include "asio/read.hpp" +#include "asio/read_at.hpp" +#include "asio/read_until.hpp" +#include "asio/readable_pipe.hpp" +#include "asio/recycling_allocator.hpp" +#include "asio/redirect_error.hpp" +#include "asio/registered_buffer.hpp" +#include "asio/require.hpp" +#include "asio/require_concept.hpp" +#include "asio/serial_port.hpp" +#include "asio/serial_port_base.hpp" +#include "asio/signal_set.hpp" +#include "asio/signal_set_base.hpp" +#include "asio/socket_base.hpp" +#include "asio/static_thread_pool.hpp" +#include "asio/steady_timer.hpp" +#include "asio/strand.hpp" +#include "asio/stream_file.hpp" +#include "asio/streambuf.hpp" +#include "asio/system_context.hpp" +#include "asio/system_error.hpp" +#include "asio/system_executor.hpp" +#include "asio/system_timer.hpp" +#include "asio/this_coro.hpp" +#include "asio/thread.hpp" +#include "asio/thread_pool.hpp" +#include "asio/time_traits.hpp" +#include "asio/use_awaitable.hpp" +#include "asio/use_future.hpp" +#include "asio/uses_executor.hpp" +#include "asio/version.hpp" +#include "asio/wait_traits.hpp" +#include "asio/windows/basic_object_handle.hpp" +#include "asio/windows/basic_overlapped_handle.hpp" +#include "asio/windows/basic_random_access_handle.hpp" +#include "asio/windows/basic_stream_handle.hpp" +#include "asio/windows/object_handle.hpp" +#include "asio/windows/overlapped_handle.hpp" +#include "asio/windows/overlapped_ptr.hpp" +#include "asio/windows/random_access_handle.hpp" +#include "asio/windows/stream_handle.hpp" +#include "asio/writable_pipe.hpp" +#include "asio/write.hpp" +#include "asio/write_at.hpp" + +#endif // ASIO_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_completion_executor.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_completion_executor.hpp new file mode 100644 index 00000000..650ff7ba --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_completion_executor.hpp @@ -0,0 +1,336 @@ +// +// any_completion_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ANY_COMPLETION_EXECUTOR_HPP +#define ASIO_ANY_COMPLETION_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/executor.hpp" +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/execution.hpp" +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +typedef executor any_completion_executor; + +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +/// Polymorphic executor type for use with I/O objects. +/** + * The @c any_completion_executor type is a polymorphic executor that supports + * the set of properties required for the execution of completion handlers. It + * is defined as the execution::any_executor class template parameterised as + * follows: + * @code execution::any_executor< + * execution::prefer_only, + * execution::prefer_only + * execution::prefer_only, + * execution::prefer_only + * > @endcode + */ +class any_completion_executor : +#if defined(GENERATING_DOCUMENTATION) + public execution::any_executor<...> +#else // defined(GENERATING_DOCUMENTATION) + public execution::any_executor< + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + > +#endif // defined(GENERATING_DOCUMENTATION) +{ +public: +#if !defined(GENERATING_DOCUMENTATION) + typedef execution::any_executor< + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + > base_type; + + typedef void supportable_properties_type( + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + ); +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Default constructor. + ASIO_DECL any_completion_executor() noexcept; + + /// Construct in an empty state. Equivalent effects to default constructor. + ASIO_DECL any_completion_executor(nullptr_t) noexcept; + + /// Copy constructor. + ASIO_DECL any_completion_executor( + const any_completion_executor& e) noexcept; + + /// Move constructor. + ASIO_DECL any_completion_executor( + any_completion_executor&& e) noexcept; + + /// Construct to point to the same target as another any_executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_completion_executor( + execution::any_executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_completion_executor(OtherAnyExecutor e, + constraint_t< + conditional< + !is_same::value + && is_base_of::value, + typename execution::detail::supportable_properties< + 0, supportable_properties_type>::template + is_valid_target, + false_type + >::type::value + > = 0) + : base_type(static_cast(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct to point to the same target as another any_executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_completion_executor(std::nothrow_t, + execution::any_executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_completion_executor(std::nothrow_t, OtherAnyExecutor e, + constraint_t< + conditional< + !is_same::value + && is_base_of::value, + typename execution::detail::supportable_properties< + 0, supportable_properties_type>::template + is_valid_target, + false_type + >::type::value + > = 0) noexcept + : base_type(std::nothrow, static_cast(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct to point to the same target as another any_executor. + ASIO_DECL any_completion_executor(std::nothrow_t, + const any_completion_executor& e) noexcept; + + /// Construct to point to the same target as another any_executor. + ASIO_DECL any_completion_executor(std::nothrow_t, + any_completion_executor&& e) noexcept; + + /// Construct a polymorphic wrapper for the specified executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_completion_executor(Executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_completion_executor(Executor e, + constraint_t< + conditional< + !is_same::value + && !is_base_of::value, + execution::detail::is_valid_target_executor< + Executor, supportable_properties_type>, + false_type + >::type::value + > = 0) + : base_type(static_cast(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct a polymorphic wrapper for the specified executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_completion_executor(std::nothrow_t, Executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_completion_executor(std::nothrow_t, Executor e, + constraint_t< + conditional< + !is_same::value + && !is_base_of::value, + execution::detail::is_valid_target_executor< + Executor, supportable_properties_type>, + false_type + >::type::value + > = 0) noexcept + : base_type(std::nothrow, static_cast(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Assignment operator. + ASIO_DECL any_completion_executor& operator=( + const any_completion_executor& e) noexcept; + + /// Move assignment operator. + ASIO_DECL any_completion_executor& operator=( + any_completion_executor&& e) noexcept; + + /// Assignment operator that sets the polymorphic wrapper to the empty state. + ASIO_DECL any_completion_executor& operator=(nullptr_t); + + /// Destructor. + ASIO_DECL ~any_completion_executor(); + + /// Swap targets with another polymorphic wrapper. + ASIO_DECL void swap(any_completion_executor& other) noexcept; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require and asio::prefer customisation points. + * + * For example: + * @code any_completion_executor ex = ...; + * auto ex2 = asio::require(ex, execution::relationship.fork); @endcode + */ + template + any_completion_executor require(const Property& p, + constraint_t< + traits::require_member::is_valid + > = 0) const + { + return static_cast(*this).require(p); + } + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::prefer customisation point. + * + * For example: + * @code any_completion_executor ex = ...; + * auto ex2 = asio::prefer(ex, execution::relationship.fork); @endcode + */ + template + any_completion_executor prefer(const Property& p, + constraint_t< + traits::prefer_member::is_valid + > = 0) const + { + return static_cast(*this).prefer(p); + } +}; + +#if !defined(GENERATING_DOCUMENTATION) + +template <> +ASIO_DECL any_completion_executor any_completion_executor::prefer( + const execution::outstanding_work_t::tracked_t&, int) const; + +template <> +ASIO_DECL any_completion_executor any_completion_executor::prefer( + const execution::outstanding_work_t::untracked_t&, int) const; + +template <> +ASIO_DECL any_completion_executor any_completion_executor::prefer( + const execution::relationship_t::fork_t&, int) const; + +template <> +ASIO_DECL any_completion_executor any_completion_executor::prefer( + const execution::relationship_t::continuation_t&, int) const; + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <> +struct equality_comparable +{ + static const bool is_valid = true; + static const bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member : + query_member +{ +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member : + require_member +{ + typedef any_completion_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template +struct prefer_member : + prefer_member +{ + typedef any_completion_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) \ + && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/impl/any_completion_executor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + // && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#endif // ASIO_ANY_COMPLETION_EXECUTOR_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_completion_handler.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_completion_handler.hpp new file mode 100644 index 00000000..45b3e75f --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_completion_handler.hpp @@ -0,0 +1,822 @@ +// +// any_completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ANY_COMPLETION_HANDLER_HPP +#define ASIO_ANY_COMPLETION_HANDLER_HPP + +#include "asio/detail/config.hpp" +#include +#include +#include +#include +#include "asio/any_completion_executor.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_cancellation_slot.hpp" +#include "asio/associated_executor.hpp" +#include "asio/associated_immediate_executor.hpp" +#include "asio/cancellation_state.hpp" +#include "asio/recycling_allocator.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class any_completion_handler_impl_base +{ +public: + template + explicit any_completion_handler_impl_base(S&& slot) + : cancel_state_(static_cast(slot), enable_total_cancellation()) + { + } + + cancellation_slot get_cancellation_slot() const noexcept + { + return cancel_state_.slot(); + } + +private: + cancellation_state cancel_state_; +}; + +template +class any_completion_handler_impl : + public any_completion_handler_impl_base +{ +public: + template + any_completion_handler_impl(S&& slot, H&& h) + : any_completion_handler_impl_base(static_cast(slot)), + handler_(static_cast(h)) + { + } + + struct uninit_deleter + { + typename std::allocator_traits< + associated_allocator_t>>::template + rebind_alloc alloc; + + void operator()(any_completion_handler_impl* ptr) + { + std::allocator_traits::deallocate(alloc, ptr, 1); + } + }; + + struct deleter + { + typename std::allocator_traits< + associated_allocator_t>>::template + rebind_alloc alloc; + + void operator()(any_completion_handler_impl* ptr) + { + std::allocator_traits::destroy(alloc, ptr); + std::allocator_traits::deallocate(alloc, ptr, 1); + } + }; + + template + static any_completion_handler_impl* create(S&& slot, H&& h) + { + uninit_deleter d{ + (get_associated_allocator)(h, + asio::recycling_allocator())}; + + std::unique_ptr uninit_ptr( + std::allocator_traits::allocate(d.alloc, 1), d); + + any_completion_handler_impl* ptr = + new (uninit_ptr.get()) any_completion_handler_impl( + static_cast(slot), static_cast(h)); + + uninit_ptr.release(); + return ptr; + } + + void destroy() + { + deleter d{ + (get_associated_allocator)(handler_, + asio::recycling_allocator())}; + + d(this); + } + + any_completion_executor executor( + const any_completion_executor& candidate) const noexcept + { + return any_completion_executor(std::nothrow, + (get_associated_executor)(handler_, candidate)); + } + + any_completion_executor immediate_executor( + const any_io_executor& candidate) const noexcept + { + return any_completion_executor(std::nothrow, + (get_associated_immediate_executor)(handler_, candidate)); + } + + void* allocate(std::size_t size, std::size_t align) const + { + typename std::allocator_traits< + associated_allocator_t>>::template + rebind_alloc alloc( + (get_associated_allocator)(handler_, + asio::recycling_allocator())); + + std::size_t space = size + align - 1; + unsigned char* base = + std::allocator_traits::allocate( + alloc, space + sizeof(std::ptrdiff_t)); + + void* p = base; + if (detail::align(align, size, p, space)) + { + std::ptrdiff_t off = static_cast(p) - base; + std::memcpy(static_cast(p) + size, &off, sizeof(off)); + return p; + } + + std::bad_alloc ex; + asio::detail::throw_exception(ex); + return nullptr; + } + + void deallocate(void* p, std::size_t size, std::size_t align) const + { + if (p) + { + typename std::allocator_traits< + associated_allocator_t>>::template + rebind_alloc alloc( + (get_associated_allocator)(handler_, + asio::recycling_allocator())); + + std::ptrdiff_t off; + std::memcpy(&off, static_cast(p) + size, sizeof(off)); + unsigned char* base = static_cast(p) - off; + + std::allocator_traits::deallocate( + alloc, base, size + align -1 + sizeof(std::ptrdiff_t)); + } + } + + template + void call(Args&&... args) + { + deleter d{ + (get_associated_allocator)(handler_, + asio::recycling_allocator())}; + + std::unique_ptr ptr(this, d); + Handler handler(static_cast(handler_)); + ptr.reset(); + + static_cast(handler)( + static_cast(args)...); + } + +private: + Handler handler_; +}; + +template +class any_completion_handler_call_fn; + +template +class any_completion_handler_call_fn +{ +public: + using type = void(*)(any_completion_handler_impl_base*, Args...); + + constexpr any_completion_handler_call_fn(type fn) + : call_fn_(fn) + { + } + + void call(any_completion_handler_impl_base* impl, Args... args) const + { + call_fn_(impl, static_cast(args)...); + } + + template + static void impl(any_completion_handler_impl_base* impl, Args... args) + { + static_cast*>(impl)->call( + static_cast(args)...); + } + +private: + type call_fn_; +}; + +template +class any_completion_handler_call_fns; + +template +class any_completion_handler_call_fns : + public any_completion_handler_call_fn +{ +public: + using any_completion_handler_call_fn< + Signature>::any_completion_handler_call_fn; + using any_completion_handler_call_fn::call; +}; + +template +class any_completion_handler_call_fns : + public any_completion_handler_call_fn, + public any_completion_handler_call_fns +{ +public: + template + constexpr any_completion_handler_call_fns(CallFn fn, CallFns... fns) + : any_completion_handler_call_fn(fn), + any_completion_handler_call_fns(fns...) + { + } + + using any_completion_handler_call_fn::call; + using any_completion_handler_call_fns::call; +}; + +class any_completion_handler_destroy_fn +{ +public: + using type = void(*)(any_completion_handler_impl_base*); + + constexpr any_completion_handler_destroy_fn(type fn) + : destroy_fn_(fn) + { + } + + void destroy(any_completion_handler_impl_base* impl) const + { + destroy_fn_(impl); + } + + template + static void impl(any_completion_handler_impl_base* impl) + { + static_cast*>(impl)->destroy(); + } + +private: + type destroy_fn_; +}; + +class any_completion_handler_executor_fn +{ +public: + using type = any_completion_executor(*)( + any_completion_handler_impl_base*, const any_completion_executor&); + + constexpr any_completion_handler_executor_fn(type fn) + : executor_fn_(fn) + { + } + + any_completion_executor executor(any_completion_handler_impl_base* impl, + const any_completion_executor& candidate) const + { + return executor_fn_(impl, candidate); + } + + template + static any_completion_executor impl(any_completion_handler_impl_base* impl, + const any_completion_executor& candidate) + { + return static_cast*>(impl)->executor( + candidate); + } + +private: + type executor_fn_; +}; + +class any_completion_handler_immediate_executor_fn +{ +public: + using type = any_completion_executor(*)( + any_completion_handler_impl_base*, const any_io_executor&); + + constexpr any_completion_handler_immediate_executor_fn(type fn) + : immediate_executor_fn_(fn) + { + } + + any_completion_executor immediate_executor( + any_completion_handler_impl_base* impl, + const any_io_executor& candidate) const + { + return immediate_executor_fn_(impl, candidate); + } + + template + static any_completion_executor impl(any_completion_handler_impl_base* impl, + const any_io_executor& candidate) + { + return static_cast*>( + impl)->immediate_executor(candidate); + } + +private: + type immediate_executor_fn_; +}; + +class any_completion_handler_allocate_fn +{ +public: + using type = void*(*)(any_completion_handler_impl_base*, + std::size_t, std::size_t); + + constexpr any_completion_handler_allocate_fn(type fn) + : allocate_fn_(fn) + { + } + + void* allocate(any_completion_handler_impl_base* impl, + std::size_t size, std::size_t align) const + { + return allocate_fn_(impl, size, align); + } + + template + static void* impl(any_completion_handler_impl_base* impl, + std::size_t size, std::size_t align) + { + return static_cast*>(impl)->allocate( + size, align); + } + +private: + type allocate_fn_; +}; + +class any_completion_handler_deallocate_fn +{ +public: + using type = void(*)(any_completion_handler_impl_base*, + void*, std::size_t, std::size_t); + + constexpr any_completion_handler_deallocate_fn(type fn) + : deallocate_fn_(fn) + { + } + + void deallocate(any_completion_handler_impl_base* impl, + void* p, std::size_t size, std::size_t align) const + { + deallocate_fn_(impl, p, size, align); + } + + template + static void impl(any_completion_handler_impl_base* impl, + void* p, std::size_t size, std::size_t align) + { + static_cast*>(impl)->deallocate( + p, size, align); + } + +private: + type deallocate_fn_; +}; + +template +class any_completion_handler_fn_table + : private any_completion_handler_destroy_fn, + private any_completion_handler_executor_fn, + private any_completion_handler_immediate_executor_fn, + private any_completion_handler_allocate_fn, + private any_completion_handler_deallocate_fn, + private any_completion_handler_call_fns +{ +public: + template + constexpr any_completion_handler_fn_table( + any_completion_handler_destroy_fn::type destroy_fn, + any_completion_handler_executor_fn::type executor_fn, + any_completion_handler_immediate_executor_fn::type immediate_executor_fn, + any_completion_handler_allocate_fn::type allocate_fn, + any_completion_handler_deallocate_fn::type deallocate_fn, + CallFns... call_fns) + : any_completion_handler_destroy_fn(destroy_fn), + any_completion_handler_executor_fn(executor_fn), + any_completion_handler_immediate_executor_fn(immediate_executor_fn), + any_completion_handler_allocate_fn(allocate_fn), + any_completion_handler_deallocate_fn(deallocate_fn), + any_completion_handler_call_fns(call_fns...) + { + } + + using any_completion_handler_destroy_fn::destroy; + using any_completion_handler_executor_fn::executor; + using any_completion_handler_immediate_executor_fn::immediate_executor; + using any_completion_handler_allocate_fn::allocate; + using any_completion_handler_deallocate_fn::deallocate; + using any_completion_handler_call_fns::call; +}; + +template +struct any_completion_handler_fn_table_instance +{ + static constexpr any_completion_handler_fn_table + value = any_completion_handler_fn_table( + &any_completion_handler_destroy_fn::impl, + &any_completion_handler_executor_fn::impl, + &any_completion_handler_immediate_executor_fn::impl, + &any_completion_handler_allocate_fn::impl, + &any_completion_handler_deallocate_fn::impl, + &any_completion_handler_call_fn::template impl...); +}; + +template +constexpr any_completion_handler_fn_table +any_completion_handler_fn_table_instance::value; + +} // namespace detail + +template +class any_completion_handler; + +/// An allocator type that forwards memory allocation operations through an +/// instance of @c any_completion_handler. +template +class any_completion_handler_allocator +{ +private: + template + friend class any_completion_handler; + + template + friend class any_completion_handler_allocator; + + const detail::any_completion_handler_fn_table* fn_table_; + detail::any_completion_handler_impl_base* impl_; + + constexpr any_completion_handler_allocator(int, + const any_completion_handler& h) noexcept + : fn_table_(h.fn_table_), + impl_(h.impl_) + { + } + +public: + /// The type of objects that may be allocated by the allocator. + typedef T value_type; + + /// Rebinds an allocator to another value type. + template + struct rebind + { + /// Specifies the type of the rebound allocator. + typedef any_completion_handler_allocator other; + }; + + /// Construct from another @c any_completion_handler_allocator. + template + constexpr any_completion_handler_allocator( + const any_completion_handler_allocator& a) + noexcept + : fn_table_(a.fn_table_), + impl_(a.impl_) + { + } + + /// Equality operator. + constexpr bool operator==( + const any_completion_handler_allocator& other) const noexcept + { + return fn_table_ == other.fn_table_ && impl_ == other.impl_; + } + + /// Inequality operator. + constexpr bool operator!=( + const any_completion_handler_allocator& other) const noexcept + { + return fn_table_ != other.fn_table_ || impl_ != other.impl_; + } + + /// Allocate space for @c n objects of the allocator's value type. + T* allocate(std::size_t n) const + { + if (fn_table_) + { + return static_cast( + fn_table_->allocate( + impl_, sizeof(T) * n, alignof(T))); + } + std::bad_alloc ex; + asio::detail::throw_exception(ex); + return nullptr; + } + + /// Deallocate space for @c n objects of the allocator's value type. + void deallocate(T* p, std::size_t n) const + { + fn_table_->deallocate(impl_, p, sizeof(T) * n, alignof(T)); + } +}; + +/// A protoco-allocator type that may be rebound to obtain an allocator that +/// forwards memory allocation operations through an instance of +/// @c any_completion_handler. +template +class any_completion_handler_allocator +{ +private: + template + friend class any_completion_handler; + + template + friend class any_completion_handler_allocator; + + const detail::any_completion_handler_fn_table* fn_table_; + detail::any_completion_handler_impl_base* impl_; + + constexpr any_completion_handler_allocator(int, + const any_completion_handler& h) noexcept + : fn_table_(h.fn_table_), + impl_(h.impl_) + { + } + +public: + /// @c void as no objects can be allocated through a proto-allocator. + typedef void value_type; + + /// Rebinds an allocator to another value type. + template + struct rebind + { + /// Specifies the type of the rebound allocator. + typedef any_completion_handler_allocator other; + }; + + /// Construct from another @c any_completion_handler_allocator. + template + constexpr any_completion_handler_allocator( + const any_completion_handler_allocator& a) + noexcept + : fn_table_(a.fn_table_), + impl_(a.impl_) + { + } + + /// Equality operator. + constexpr bool operator==( + const any_completion_handler_allocator& other) const noexcept + { + return fn_table_ == other.fn_table_ && impl_ == other.impl_; + } + + /// Inequality operator. + constexpr bool operator!=( + const any_completion_handler_allocator& other) const noexcept + { + return fn_table_ != other.fn_table_ || impl_ != other.impl_; + } +}; + +/// Polymorphic wrapper for completion handlers. +/** + * The @c any_completion_handler class template is a polymorphic wrapper for + * completion handlers that propagates the associated executor, associated + * allocator, and associated cancellation slot through a type-erasing interface. + * + * When using @c any_completion_handler, specify one or more completion + * signatures as template parameters. These will dictate the arguments that may + * be passed to the handler through the polymorphic interface. + * + * Typical uses for @c any_completion_handler include: + * + * @li Separate compilation of asynchronous operation implementations. + * + * @li Enabling interoperability between asynchronous operations and virtual + * functions. + */ +template +class any_completion_handler +{ +#if !defined(GENERATING_DOCUMENTATION) +private: + template + friend class any_completion_handler_allocator; + + template + friend struct associated_executor; + + template + friend struct associated_immediate_executor; + + const detail::any_completion_handler_fn_table* fn_table_; + detail::any_completion_handler_impl_base* impl_; +#endif // !defined(GENERATING_DOCUMENTATION) + +public: + /// The associated allocator type. + using allocator_type = any_completion_handler_allocator; + + /// The associated cancellation slot type. + using cancellation_slot_type = cancellation_slot; + + /// Construct an @c any_completion_handler in an empty state, without a target + /// object. + constexpr any_completion_handler() + : fn_table_(nullptr), + impl_(nullptr) + { + } + + /// Construct an @c any_completion_handler in an empty state, without a target + /// object. + constexpr any_completion_handler(nullptr_t) + : fn_table_(nullptr), + impl_(nullptr) + { + } + + /// Construct an @c any_completion_handler to contain the specified target. + template > + any_completion_handler(H&& h, + constraint_t< + !is_same, any_completion_handler>::value + > = 0) + : fn_table_( + &detail::any_completion_handler_fn_table_instance< + Handler, Signatures...>::value), + impl_(detail::any_completion_handler_impl::create( + (get_associated_cancellation_slot)(h), static_cast(h))) + { + } + + /// Move-construct an @c any_completion_handler from another. + /** + * After the operation, the moved-from object @c other has no target. + */ + any_completion_handler(any_completion_handler&& other) noexcept + : fn_table_(other.fn_table_), + impl_(other.impl_) + { + other.fn_table_ = nullptr; + other.impl_ = nullptr; + } + + /// Move-assign an @c any_completion_handler from another. + /** + * After the operation, the moved-from object @c other has no target. + */ + any_completion_handler& operator=( + any_completion_handler&& other) noexcept + { + any_completion_handler( + static_cast(other)).swap(*this); + return *this; + } + + /// Assignment operator that sets the polymorphic wrapper to the empty state. + any_completion_handler& operator=(nullptr_t) noexcept + { + any_completion_handler().swap(*this); + return *this; + } + + /// Destructor. + ~any_completion_handler() + { + if (impl_) + fn_table_->destroy(impl_); + } + + /// Test if the polymorphic wrapper is empty. + constexpr explicit operator bool() const noexcept + { + return impl_ != nullptr; + } + + /// Test if the polymorphic wrapper is non-empty. + constexpr bool operator!() const noexcept + { + return impl_ == nullptr; + } + + /// Swap the content of an @c any_completion_handler with another. + void swap(any_completion_handler& other) noexcept + { + std::swap(fn_table_, other.fn_table_); + std::swap(impl_, other.impl_); + } + + /// Get the associated allocator. + allocator_type get_allocator() const noexcept + { + return allocator_type(0, *this); + } + + /// Get the associated cancellation slot. + cancellation_slot_type get_cancellation_slot() const noexcept + { + return impl_ ? impl_->get_cancellation_slot() : cancellation_slot_type(); + } + + /// Function call operator. + /** + * Invokes target completion handler with the supplied arguments. + * + * This function may only be called once, as the target handler is moved from. + * The polymorphic wrapper is left in an empty state. + * + * Throws @c std::bad_function_call if the polymorphic wrapper is empty. + */ + template + auto operator()(Args&&... args) + -> decltype(fn_table_->call(impl_, static_cast(args)...)) + { + if (detail::any_completion_handler_impl_base* impl = impl_) + { + impl_ = nullptr; + return fn_table_->call(impl, static_cast(args)...); + } + std::bad_function_call ex; + asio::detail::throw_exception(ex); + } + + /// Equality operator. + friend constexpr bool operator==( + const any_completion_handler& a, nullptr_t) noexcept + { + return a.impl_ == nullptr; + } + + /// Equality operator. + friend constexpr bool operator==( + nullptr_t, const any_completion_handler& b) noexcept + { + return nullptr == b.impl_; + } + + /// Inequality operator. + friend constexpr bool operator!=( + const any_completion_handler& a, nullptr_t) noexcept + { + return a.impl_ != nullptr; + } + + /// Inequality operator. + friend constexpr bool operator!=( + nullptr_t, const any_completion_handler& b) noexcept + { + return nullptr != b.impl_; + } +}; + +template +struct associated_executor, Candidate> +{ + using type = any_completion_executor; + + static type get(const any_completion_handler& handler, + const Candidate& candidate = Candidate()) noexcept + { + any_completion_executor any_candidate(std::nothrow, candidate); + return handler.fn_table_ + ? handler.fn_table_->executor(handler.impl_, any_candidate) + : any_candidate; + } +}; + +template +struct associated_immediate_executor< + any_completion_handler, Candidate> +{ + using type = any_completion_executor; + + static type get(const any_completion_handler& handler, + const Candidate& candidate = Candidate()) noexcept + { + any_io_executor any_candidate(std::nothrow, candidate); + return handler.fn_table_ + ? handler.fn_table_->immediate_executor(handler.impl_, any_candidate) + : any_candidate; + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ANY_COMPLETION_HANDLER_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_io_executor.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_io_executor.hpp new file mode 100644 index 00000000..d35acf44 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/any_io_executor.hpp @@ -0,0 +1,351 @@ +// +// any_io_executor.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ANY_IO_EXECUTOR_HPP +#define ASIO_ANY_IO_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/executor.hpp" +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/execution.hpp" +# include "asio/execution_context.hpp" +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +typedef executor any_io_executor; + +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +/// Polymorphic executor type for use with I/O objects. +/** + * The @c any_io_executor type is a polymorphic executor that supports the set + * of properties required by I/O objects. It is defined as the + * execution::any_executor class template parameterised as follows: + * @code execution::any_executor< + * execution::context_as_t, + * execution::blocking_t::never_t, + * execution::prefer_only, + * execution::prefer_only, + * execution::prefer_only, + * execution::prefer_only, + * execution::prefer_only + * > @endcode + */ +class any_io_executor : +#if defined(GENERATING_DOCUMENTATION) + public execution::any_executor<...> +#else // defined(GENERATING_DOCUMENTATION) + public execution::any_executor< + execution::context_as_t, + execution::blocking_t::never_t, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + > +#endif // defined(GENERATING_DOCUMENTATION) +{ +public: +#if !defined(GENERATING_DOCUMENTATION) + typedef execution::any_executor< + execution::context_as_t, + execution::blocking_t::never_t, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + > base_type; + + typedef void supportable_properties_type( + execution::context_as_t, + execution::blocking_t::never_t, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + ); +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Default constructor. + ASIO_DECL any_io_executor() noexcept; + + /// Construct in an empty state. Equivalent effects to default constructor. + ASIO_DECL any_io_executor(nullptr_t) noexcept; + + /// Copy constructor. + ASIO_DECL any_io_executor(const any_io_executor& e) noexcept; + + /// Move constructor. + ASIO_DECL any_io_executor(any_io_executor&& e) noexcept; + + /// Construct to point to the same target as another any_executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_io_executor(execution::any_executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_io_executor(OtherAnyExecutor e, + constraint_t< + conditional_t< + !is_same::value + && is_base_of::value, + typename execution::detail::supportable_properties< + 0, supportable_properties_type>::template + is_valid_target, + false_type + >::value + > = 0) + : base_type(static_cast(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct to point to the same target as another any_executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_io_executor(std::nothrow_t, + execution::any_executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_io_executor(std::nothrow_t, OtherAnyExecutor e, + constraint_t< + conditional_t< + !is_same::value + && is_base_of::value, + typename execution::detail::supportable_properties< + 0, supportable_properties_type>::template + is_valid_target, + false_type + >::value + > = 0) noexcept + : base_type(std::nothrow, static_cast(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct to point to the same target as another any_executor. + ASIO_DECL any_io_executor(std::nothrow_t, + const any_io_executor& e) noexcept; + + /// Construct to point to the same target as another any_executor. + ASIO_DECL any_io_executor(std::nothrow_t, any_io_executor&& e) noexcept; + + /// Construct a polymorphic wrapper for the specified executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_io_executor(Executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_io_executor(Executor e, + constraint_t< + conditional_t< + !is_same::value + && !is_base_of::value, + execution::detail::is_valid_target_executor< + Executor, supportable_properties_type>, + false_type + >::value + > = 0) + : base_type(static_cast(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct a polymorphic wrapper for the specified executor. +#if defined(GENERATING_DOCUMENTATION) + template + any_io_executor(std::nothrow_t, Executor e); +#else // defined(GENERATING_DOCUMENTATION) + template + any_io_executor(std::nothrow_t, Executor e, + constraint_t< + conditional_t< + !is_same::value + && !is_base_of::value, + execution::detail::is_valid_target_executor< + Executor, supportable_properties_type>, + false_type + >::value + > = 0) noexcept + : base_type(std::nothrow, static_cast(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Assignment operator. + ASIO_DECL any_io_executor& operator=( + const any_io_executor& e) noexcept; + + /// Move assignment operator. + ASIO_DECL any_io_executor& operator=(any_io_executor&& e) noexcept; + + /// Assignment operator that sets the polymorphic wrapper to the empty state. + ASIO_DECL any_io_executor& operator=(nullptr_t); + + /// Destructor. + ASIO_DECL ~any_io_executor(); + + /// Swap targets with another polymorphic wrapper. + ASIO_DECL void swap(any_io_executor& other) noexcept; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require and asio::prefer customisation points. + * + * For example: + * @code any_io_executor ex = ...; + * auto ex2 = asio::require(ex, execution::blocking.possibly); @endcode + */ + template + any_io_executor require(const Property& p, + constraint_t< + traits::require_member::is_valid + > = 0) const + { + return static_cast(*this).require(p); + } + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::prefer customisation point. + * + * For example: + * @code any_io_executor ex = ...; + * auto ex2 = asio::prefer(ex, execution::blocking.possibly); @endcode + */ + template + any_io_executor prefer(const Property& p, + constraint_t< + traits::prefer_member::is_valid + > = 0) const + { + return static_cast(*this).prefer(p); + } +}; + +#if !defined(GENERATING_DOCUMENTATION) + +template <> +ASIO_DECL any_io_executor any_io_executor::require( + const execution::blocking_t::never_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::blocking_t::possibly_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::outstanding_work_t::tracked_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::outstanding_work_t::untracked_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::relationship_t::fork_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::relationship_t::continuation_t&, int) const; + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <> +struct equality_comparable +{ + static const bool is_valid = true; + static const bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member : + query_member +{ +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member : + require_member +{ + typedef any_io_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template +struct prefer_member : + prefer_member +{ + typedef any_io_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) \ + && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/impl/any_io_executor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + // && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#endif // ASIO_ANY_IO_EXECUTOR_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/append.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/append.hpp new file mode 100644 index 00000000..04608924 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/append.hpp @@ -0,0 +1,65 @@ +// +// append.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_APPEND_HPP +#define ASIO_APPEND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Completion token type used to specify that the completion handler +/// arguments should be passed additional values after the results of the +/// operation. +template +class append_t +{ +public: + /// Constructor. + template + constexpr explicit append_t(T&& completion_token, V&&... values) + : token_(static_cast(completion_token)), + values_(static_cast(values)...) + { + } + +//private: + CompletionToken token_; + std::tuple values_; +}; + +/// Completion token type used to specify that the completion handler +/// arguments should be passed additional values after the results of the +/// operation. +template +ASIO_NODISCARD inline constexpr +append_t, decay_t...> +append(CompletionToken&& completion_token, Values&&... values) +{ + return append_t, decay_t...>( + static_cast(completion_token), + static_cast(values)...); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/append.hpp" + +#endif // ASIO_APPEND_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/as_tuple.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/as_tuple.hpp new file mode 100644 index 00000000..60008bda --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/as_tuple.hpp @@ -0,0 +1,126 @@ +// +// as_tuple.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_AS_TUPLE_HPP +#define ASIO_AS_TUPLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// A @ref completion_token adapter used to specify that the completion handler +/// arguments should be combined into a single tuple argument. +/** + * The as_tuple_t class is used to indicate that any arguments to the + * completion handler should be combined and passed as a single tuple argument. + * The arguments are first moved into a @c std::tuple and that tuple is then + * passed to the completion handler. + */ +template +class as_tuple_t +{ +public: + /// Tag type used to prevent the "default" constructor from being used for + /// conversions. + struct default_constructor_tag {}; + + /// Default constructor. + /** + * This constructor is only valid if the underlying completion token is + * default constructible and move constructible. The underlying completion + * token is itself defaulted as an argument to allow it to capture a source + * location. + */ + constexpr as_tuple_t( + default_constructor_tag = default_constructor_tag(), + CompletionToken token = CompletionToken()) + : token_(static_cast(token)) + { + } + + /// Constructor. + template + constexpr explicit as_tuple_t( + T&& completion_token) + : token_(static_cast(completion_token)) + { + } + + /// Adapts an executor to add the @c as_tuple_t completion token as the + /// default. + template + struct executor_with_default : InnerExecutor + { + /// Specify @c as_tuple_t as the default completion token type. + typedef as_tuple_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + template + executor_with_default(const InnerExecutor1& ex, + constraint_t< + conditional_t< + !is_same::value, + is_convertible, + false_type + >::value + > = 0) noexcept + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c as_tuple_t as its + /// default completion token type. + template + using as_default_on_t = typename T::template rebind_executor< + executor_with_default>::other; + + /// Function helper to adapt an I/O object to use @c as_tuple_t as its + /// default completion token type. + template + static typename decay_t::template rebind_executor< + executor_with_default::executor_type> + >::other + as_default_on(T&& object) + { + return typename decay_t::template rebind_executor< + executor_with_default::executor_type> + >::other(static_cast(object)); + } + +//private: + CompletionToken token_; +}; + +/// Adapt a @ref completion_token to specify that the completion handler +/// arguments should be combined into a single tuple argument. +template +ASIO_NODISCARD inline +constexpr as_tuple_t> +as_tuple(CompletionToken&& completion_token) +{ + return as_tuple_t>( + static_cast(completion_token)); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/as_tuple.hpp" + +#endif // ASIO_AS_TUPLE_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_allocator.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_allocator.hpp new file mode 100644 index 00000000..f21ea250 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_allocator.hpp @@ -0,0 +1,214 @@ +// +// associated_allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ASSOCIATED_ALLOCATOR_HPP +#define ASIO_ASSOCIATED_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/associator.hpp" +#include "asio/detail/functional.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template +struct associated_allocator; + +namespace detail { + +template +struct has_allocator_type : false_type +{ +}; + +template +struct has_allocator_type> : true_type +{ +}; + +template +struct associated_allocator_impl +{ + typedef void asio_associated_allocator_is_unspecialised; + + typedef A type; + + static type get(const T&) noexcept + { + return type(); + } + + static const type& get(const T&, const A& a) noexcept + { + return a; + } +}; + +template +struct associated_allocator_impl> +{ + typedef typename T::allocator_type type; + + static auto get(const T& t) noexcept + -> decltype(t.get_allocator()) + { + return t.get_allocator(); + } + + static auto get(const T& t, const A&) noexcept + -> decltype(t.get_allocator()) + { + return t.get_allocator(); + } +}; + +template +struct associated_allocator_impl::value + >, + void_t< + typename associator::type + >> : associator +{ +}; + +} // namespace detail + +/// Traits type used to obtain the allocator associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Allocator shall be a type meeting the Allocator requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c a is an object of type @c + * Allocator. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Allocator requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type or a (possibly const) reference to @c + * type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,a) and with return type @c type or a (possibly const) reference to @c + * type. + */ +template > +struct associated_allocator +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_allocator_impl +#endif // !defined(GENERATING_DOCUMENTATION) +{ +#if defined(GENERATING_DOCUMENTATION) + /// If @c T has a nested type @c allocator_type, T::allocator_type. + /// Otherwise @c Allocator. + typedef see_below type; + + /// If @c T has a nested type @c allocator_type, returns + /// t.get_allocator(). Otherwise returns @c type(). + static decltype(auto) get(const T& t) noexcept; + + /// If @c T has a nested type @c allocator_type, returns + /// t.get_allocator(). Otherwise returns @c a. + static decltype(auto) get(const T& t, const Allocator& a) noexcept; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +/// Helper function to obtain an object's associated allocator. +/** + * @returns associated_allocator::get(t) + */ +template +ASIO_NODISCARD inline typename associated_allocator::type +get_associated_allocator(const T& t) noexcept +{ + return associated_allocator::get(t); +} + +/// Helper function to obtain an object's associated allocator. +/** + * @returns associated_allocator::get(t, a) + */ +template +ASIO_NODISCARD inline auto get_associated_allocator( + const T& t, const Allocator& a) noexcept + -> decltype(associated_allocator::get(t, a)) +{ + return associated_allocator::get(t, a); +} + +template > +using associated_allocator_t + = typename associated_allocator::type; + +namespace detail { + +template +struct associated_allocator_forwarding_base +{ +}; + +template +struct associated_allocator_forwarding_base::asio_associated_allocator_is_unspecialised, + void + >::value + >> +{ + typedef void asio_associated_allocator_is_unspecialised; +}; + +} // namespace detail + +/// Specialisation of associated_allocator for @c std::reference_wrapper. +template +struct associated_allocator, Allocator> +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_allocator_forwarding_base +#endif // !defined(GENERATING_DOCUMENTATION) +{ + /// Forwards @c type to the associator specialisation for the unwrapped type + /// @c T. + typedef typename associated_allocator::type type; + + /// Forwards the request to get the allocator to the associator specialisation + /// for the unwrapped type @c T. + static type get(reference_wrapper t) noexcept + { + return associated_allocator::get(t.get()); + } + + /// Forwards the request to get the allocator to the associator specialisation + /// for the unwrapped type @c T. + static auto get(reference_wrapper t, const Allocator& a) noexcept + -> decltype(associated_allocator::get(t.get(), a)) + { + return associated_allocator::get(t.get(), a); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASSOCIATED_ALLOCATOR_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_cancellation_slot.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_cancellation_slot.hpp new file mode 100644 index 00000000..518bd881 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_cancellation_slot.hpp @@ -0,0 +1,221 @@ +// +// associated_cancellation_slot.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP +#define ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/cancellation_signal.hpp" +#include "asio/detail/functional.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template +struct associated_cancellation_slot; + +namespace detail { + +template +struct has_cancellation_slot_type : false_type +{ +}; + +template +struct has_cancellation_slot_type> + : true_type +{ +}; + +template +struct associated_cancellation_slot_impl +{ + typedef void asio_associated_cancellation_slot_is_unspecialised; + + typedef S type; + + static type get(const T&) noexcept + { + return type(); + } + + static const type& get(const T&, const S& s) noexcept + { + return s; + } +}; + +template +struct associated_cancellation_slot_impl> +{ + typedef typename T::cancellation_slot_type type; + + static auto get(const T& t) noexcept + -> decltype(t.get_cancellation_slot()) + { + return t.get_cancellation_slot(); + } + + static auto get(const T& t, const S&) noexcept + -> decltype(t.get_cancellation_slot()) + { + return t.get_cancellation_slot(); + } +}; + +template +struct associated_cancellation_slot_impl::value + >, + void_t< + typename associator::type + >> : associator +{ +}; + +} // namespace detail + +/// Traits type used to obtain the cancellation_slot associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * CancellationSlot shall be a type meeting the CancellationSlot requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c s is an object of type @c + * CancellationSlot. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * CancellationSlot requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type or a (possibly const) reference to @c + * type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,s) and with return type @c type or a (possibly const) reference to @c + * type. + */ +template +struct associated_cancellation_slot +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_cancellation_slot_impl +#endif // !defined(GENERATING_DOCUMENTATION) +{ +#if defined(GENERATING_DOCUMENTATION) + /// If @c T has a nested type @c cancellation_slot_type, + /// T::cancellation_slot_type. Otherwise + /// @c CancellationSlot. + typedef see_below type; + + /// If @c T has a nested type @c cancellation_slot_type, returns + /// t.get_cancellation_slot(). Otherwise returns @c type(). + static decltype(auto) get(const T& t) noexcept; + + /// If @c T has a nested type @c cancellation_slot_type, returns + /// t.get_cancellation_slot(). Otherwise returns @c s. + static decltype(auto) get(const T& t, + const CancellationSlot& s) noexcept; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +/// Helper function to obtain an object's associated cancellation_slot. +/** + * @returns associated_cancellation_slot::get(t) + */ +template +ASIO_NODISCARD inline typename associated_cancellation_slot::type +get_associated_cancellation_slot(const T& t) noexcept +{ + return associated_cancellation_slot::get(t); +} + +/// Helper function to obtain an object's associated cancellation_slot. +/** + * @returns associated_cancellation_slot::get(t, st) + */ +template +ASIO_NODISCARD inline auto get_associated_cancellation_slot( + const T& t, const CancellationSlot& st) noexcept + -> decltype(associated_cancellation_slot::get(t, st)) +{ + return associated_cancellation_slot::get(t, st); +} + +template +using associated_cancellation_slot_t = + typename associated_cancellation_slot::type; + +namespace detail { + +template +struct associated_cancellation_slot_forwarding_base +{ +}; + +template +struct associated_cancellation_slot_forwarding_base::asio_associated_cancellation_slot_is_unspecialised, + void + >::value + >> +{ + typedef void asio_associated_cancellation_slot_is_unspecialised; +}; + +} // namespace detail + +/// Specialisation of associated_cancellation_slot for @c +/// std::reference_wrapper. +template +struct associated_cancellation_slot, CancellationSlot> +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_cancellation_slot_forwarding_base +#endif // !defined(GENERATING_DOCUMENTATION) +{ + /// Forwards @c type to the associator specialisation for the unwrapped type + /// @c T. + typedef typename associated_cancellation_slot::type type; + + /// Forwards the request to get the cancellation slot to the associator + /// specialisation for the unwrapped type @c T. + static type get(reference_wrapper t) noexcept + { + return associated_cancellation_slot::get(t.get()); + } + + /// Forwards the request to get the cancellation slot to the associator + /// specialisation for the unwrapped type @c T. + static auto get(reference_wrapper t, const CancellationSlot& s) noexcept + -> decltype( + associated_cancellation_slot::get(t.get(), s)) + { + return associated_cancellation_slot::get(t.get(), s); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_executor.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_executor.hpp new file mode 100644 index 00000000..4ca7ba14 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_executor.hpp @@ -0,0 +1,235 @@ +// +// associated_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ASSOCIATED_EXECUTOR_HPP +#define ASIO_ASSOCIATED_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/detail/functional.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_executor.hpp" +#include "asio/system_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template +struct associated_executor; + +namespace detail { + +template +struct has_executor_type : false_type +{ +}; + +template +struct has_executor_type> + : true_type +{ +}; + +template +struct associated_executor_impl +{ + typedef void asio_associated_executor_is_unspecialised; + + typedef E type; + + static type get(const T&) noexcept + { + return type(); + } + + static const type& get(const T&, const E& e) noexcept + { + return e; + } +}; + +template +struct associated_executor_impl> +{ + typedef typename T::executor_type type; + + static auto get(const T& t) noexcept + -> decltype(t.get_executor()) + { + return t.get_executor(); + } + + static auto get(const T& t, const E&) noexcept + -> decltype(t.get_executor()) + { + return t.get_executor(); + } +}; + +template +struct associated_executor_impl::value + >, + void_t< + typename associator::type + >> : associator +{ +}; + +} // namespace detail + +/// Traits type used to obtain the executor associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Executor shall be a type meeting the Executor requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c e is an object of type @c + * Executor. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Executor requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type or a (possibly const) reference to @c + * type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,e) and with return type @c type or a (possibly const) reference to @c + * type. + */ +template +struct associated_executor +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_executor_impl +#endif // !defined(GENERATING_DOCUMENTATION) +{ +#if defined(GENERATING_DOCUMENTATION) + /// If @c T has a nested type @c executor_type, T::executor_type. + /// Otherwise @c Executor. + typedef see_below type; + + /// If @c T has a nested type @c executor_type, returns + /// t.get_executor(). Otherwise returns @c type(). + static decltype(auto) get(const T& t) noexcept; + + /// If @c T has a nested type @c executor_type, returns + /// t.get_executor(). Otherwise returns @c ex. + static decltype(auto) get(const T& t, const Executor& ex) noexcept; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_executor::get(t) + */ +template +ASIO_NODISCARD inline typename associated_executor::type +get_associated_executor(const T& t) noexcept +{ + return associated_executor::get(t); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_executor::get(t, ex) + */ +template +ASIO_NODISCARD inline auto get_associated_executor( + const T& t, const Executor& ex, + constraint_t< + is_executor::value || execution::is_executor::value + > = 0) noexcept + -> decltype(associated_executor::get(t, ex)) +{ + return associated_executor::get(t, ex); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_executor::get(t, ctx.get_executor()) + */ +template +ASIO_NODISCARD inline typename associated_executor::type +get_associated_executor(const T& t, ExecutionContext& ctx, + constraint_t::value> = 0) noexcept +{ + return associated_executor::get(t, ctx.get_executor()); +} + +template +using associated_executor_t = typename associated_executor::type; + +namespace detail { + +template +struct associated_executor_forwarding_base +{ +}; + +template +struct associated_executor_forwarding_base::asio_associated_executor_is_unspecialised, + void + >::value + >> +{ + typedef void asio_associated_executor_is_unspecialised; +}; + +} // namespace detail + +/// Specialisation of associated_executor for @c std::reference_wrapper. +template +struct associated_executor, Executor> +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_executor_forwarding_base +#endif // !defined(GENERATING_DOCUMENTATION) +{ + /// Forwards @c type to the associator specialisation for the unwrapped type + /// @c T. + typedef typename associated_executor::type type; + + /// Forwards the request to get the executor to the associator specialisation + /// for the unwrapped type @c T. + static type get(reference_wrapper t) noexcept + { + return associated_executor::get(t.get()); + } + + /// Forwards the request to get the executor to the associator specialisation + /// for the unwrapped type @c T. + static auto get(reference_wrapper t, const Executor& ex) noexcept + -> decltype(associated_executor::get(t.get(), ex)) + { + return associated_executor::get(t.get(), ex); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASSOCIATED_EXECUTOR_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_immediate_executor.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_immediate_executor.hpp new file mode 100644 index 00000000..aa6e0fcf --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associated_immediate_executor.hpp @@ -0,0 +1,280 @@ +// +// associated_immediate_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP +#define ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/detail/functional.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution_context.hpp" +#include "asio/is_executor.hpp" +#include "asio/require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template +struct associated_immediate_executor; + +namespace detail { + +template +struct has_immediate_executor_type : false_type +{ +}; + +template +struct has_immediate_executor_type> + : true_type +{ +}; + +template +struct default_immediate_executor +{ + typedef require_result_t type; + + static type get(const E& e) noexcept + { + return asio::require(e, execution::blocking.never); + } +}; + +template +struct default_immediate_executor::value + >, + enable_if_t< + is_executor::value + >> +{ + class type : public E + { + public: + template + explicit type(const Executor1& e, + constraint_t< + conditional_t< + !is_same::value, + is_convertible, + false_type + >::value + > = 0) noexcept + : E(e) + { + } + + type(const type& other) noexcept + : E(static_cast(other)) + { + } + + type(type&& other) noexcept + : E(static_cast(other)) + { + } + + template + void dispatch(Function&& f, const Allocator& a) const + { + this->post(static_cast(f), a); + } + + friend bool operator==(const type& a, const type& b) noexcept + { + return static_cast(a) == static_cast(b); + } + + friend bool operator!=(const type& a, const type& b) noexcept + { + return static_cast(a) != static_cast(b); + } + }; + + static type get(const E& e) noexcept + { + return type(e); + } +}; + +template +struct associated_immediate_executor_impl +{ + typedef void asio_associated_immediate_executor_is_unspecialised; + + typedef typename default_immediate_executor::type type; + + static auto get(const T&, const E& e) noexcept + -> decltype(default_immediate_executor::get(e)) + { + return default_immediate_executor::get(e); + } +}; + +template +struct associated_immediate_executor_impl> +{ + typedef typename T::immediate_executor_type type; + + static auto get(const T& t, const E&) noexcept + -> decltype(t.get_immediate_executor()) + { + return t.get_immediate_executor(); + } +}; + +template +struct associated_immediate_executor_impl::value + >, + void_t< + typename associator::type + >> : associator +{ +}; + +} // namespace detail + +/// Traits type used to obtain the immediate executor associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Executor shall be a type meeting the Executor requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c e is an object of type @c + * Executor. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Executor requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type or a (possibly const) reference to @c + * type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,e) and with return type @c type or a (possibly const) reference to @c + * type. + */ +template +struct associated_immediate_executor +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_immediate_executor_impl +#endif // !defined(GENERATING_DOCUMENTATION) +{ +#if defined(GENERATING_DOCUMENTATION) + /// If @c T has a nested type @c immediate_executor_type, + // T::immediate_executor_type. Otherwise @c Executor. + typedef see_below type; + + /// If @c T has a nested type @c immediate_executor_type, returns + /// t.get_immediate_executor(). Otherwise returns + /// asio::require(ex, asio::execution::blocking.never). + static decltype(auto) get(const T& t, const Executor& ex) noexcept; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_immediate_executor::get(t, ex) + */ +template +ASIO_NODISCARD inline auto get_associated_immediate_executor( + const T& t, const Executor& ex, + constraint_t< + is_executor::value || execution::is_executor::value + > = 0) noexcept + -> decltype(associated_immediate_executor::get(t, ex)) +{ + return associated_immediate_executor::get(t, ex); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_immediate_executor::get(t, ctx.get_executor()) + */ +template +ASIO_NODISCARD inline typename associated_immediate_executor::type +get_associated_immediate_executor(const T& t, ExecutionContext& ctx, + constraint_t< + is_convertible::value + > = 0) noexcept +{ + return associated_immediate_executor::get(t, ctx.get_executor()); +} + +template +using associated_immediate_executor_t = + typename associated_immediate_executor::type; + +namespace detail { + +template +struct associated_immediate_executor_forwarding_base +{ +}; + +template +struct associated_immediate_executor_forwarding_base::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >> +{ + typedef void asio_associated_immediate_executor_is_unspecialised; +}; + +} // namespace detail + +/// Specialisation of associated_immediate_executor for +/// @c std::reference_wrapper. +template +struct associated_immediate_executor, Executor> +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_immediate_executor_forwarding_base +#endif // !defined(GENERATING_DOCUMENTATION) +{ + /// Forwards @c type to the associator specialisation for the unwrapped type + /// @c T. + typedef typename associated_immediate_executor::type type; + + /// Forwards the request to get the executor to the associator specialisation + /// for the unwrapped type @c T. + static auto get(reference_wrapper t, const Executor& ex) noexcept + -> decltype(associated_immediate_executor::get(t.get(), ex)) + { + return associated_immediate_executor::get(t.get(), ex); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associator.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associator.hpp new file mode 100644 index 00000000..7952fcc5 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/struct_frame_sdk/asio/associator.hpp @@ -0,0 +1,35 @@ +// +// associator.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ASSOCIATOR_HPP +#define ASIO_ASSOCIATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Used to generically specialise associators for a type. +template