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..75746a78 --- /dev/null +++ b/docs/user-guide/cpp-sdk.md @@ -0,0 +1,483 @@ +# 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 in embedded mode**: Core SDK has no external dependencies when using `--sdk_embedded` +- **Observer pattern**: Type-safe message subscription using function pointers (no `std::function`, no `std::vector`) +- **Embedded-friendly**: Generic serial interface for bare-metal systems +- **Cross-platform**: Works on Windows, macOS, and Linux +- **Network support**: UDP, TCP, WebSocket via ASIO (included with `--sdk` flag) + +## Installation + +### Full SDK (with network transports) + +Generate C++ code with full SDK including ASIO: + +```bash +python -m struct_frame your_messages.proto --build_cpp --cpp_path generated/cpp --sdk +``` + +This includes: +- ASIO standalone headers (v1.30.2) +- UDP, TCP, Serial transports using ASIO +- Network transports implementation +- All SDK features + +### Embedded SDK (serial only, no dependencies) + +For embedded/bare-metal systems, use the minimal SDK: + +```bash +python -m struct_frame your_messages.proto --build_cpp --cpp_path generated/cpp --sdk_embedded +``` + +This includes: +- Observer pattern with function pointers (no STL dependencies) +- Generic serial transport interface +- No ASIO headers +- Minimal footprint + +### Without SDK (default) + +Generate only message serialization code: + +```bash +python -m struct_frame your_messages.proto --build_cpp --cpp_path generated/cpp +``` + +## Including the SDK + +For full SDK: +```cpp +#include "struct_frame_sdk/sdk.hpp" +``` + +For embedded SDK: +```cpp +#include "struct_frame_sdk/sdk_embedded.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 "struct_frame_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); +``` + +### Function Pointer Observer (Embedded) + +For embedded systems without STL dependencies, use function pointer observers: + +```cpp +#include "struct_frame_sdk/observer.hpp" +#include "my_messages.hpp" + +using namespace StructFrame; + +// Define handler function +void onStatusMessage(const StatusMessage& message, uint8_t msgId) { + // Handle message +} + +// Usage with function pointer +auto* observer = new FunctionObserver(onStatusMessage); +auto* observable = sdk.getObservable(StatusMessage::msg_id); +observable->subscribe(observer); +``` + +### 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 "struct_frame_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 "struct_frame_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 "struct_frame_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 "struct_frame_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 "struct_frame_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..47834c39 --- /dev/null +++ b/docs/user-guide/csharp-sdk.md @@ -0,0 +1,489 @@ +# 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 + +Generate C# code with SDK: + +```bash +python -m struct_frame your_messages.proto --build_csharp --csharp_path generated/csharp --sdk +``` + +**Note**: The SDK is not included by default. Use the `--sdk` flag to generate SDK files. + +## 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..0ea9e651 --- /dev/null +++ b/docs/user-guide/python-sdk.md @@ -0,0 +1,398 @@ +# Python SDK + +The Python SDK provides both synchronous and asynchronous interfaces for structured message communication. + +## Installation + +Generate Python code with SDK: + +```bash +python -m struct_frame your_messages.proto --build_py --py_path generated/py --sdk +``` + +**Note**: The SDK is not included by default. Use the `--sdk` flag to generate SDK files. + +## Available Transports + +### Synchronous Transports + +#### UDP Transport + +```python +from struct_frame_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 struct_frame_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 struct_frame_sdk import WebSocketTransport, WebSocketTransportConfig + +transport = WebSocketTransport(WebSocketTransportConfig( + url='ws://localhost:8080', + timeout=5.0, +)) +``` + +#### Serial Transport + +Requires `pyserial` package: + +```python +from struct_frame_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 struct_frame_sdk import ( + AsyncUdpTransport, AsyncUdpTransportConfig, + AsyncTcpTransport, AsyncTcpTransportConfig, + AsyncWebSocketTransport, AsyncWebSocketTransportConfig, + AsyncSerialTransport, AsyncSerialTransportConfig, +) +``` + +## Synchronous SDK Usage + +### Creating the SDK + +```python +from struct_frame_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 struct_frame_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 struct_frame_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 struct_frame_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..f1997fe6 --- /dev/null +++ b/docs/user-guide/sdk-overview.md @@ -0,0 +1,209 @@ +# 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. + +## Enabling SDK Generation + +**The SDK is opt-in and not generated by default.** To include SDK files during code generation, use one of these flags: + +- **`--sdk`**: Generate full SDK with all transports (includes ASIO for C++) +- **`--sdk_embedded`**: Generate minimal embedded SDK (serial transport only, no ASIO, no STL dependencies for C++) + +```bash +# Generate code without SDK (default) +python -m struct_frame your_messages.proto --build_cpp --cpp_path gen/cpp + +# Generate code with full SDK +python -m struct_frame your_messages.proto --build_cpp --cpp_path gen/cpp --sdk + +# Generate code with embedded SDK (minimal footprint) +python -m struct_frame your_messages.proto --build_cpp --cpp_path gen/cpp --sdk_embedded +``` + +## 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 | SDK Flags | +|----------|------------|------------|------------------|-----------| +| **TypeScript/JavaScript** | Async (Promise-based) | UDP, TCP, WebSocket, Serial | Callback-based | `--sdk` | +| **Python** | Both Sync & Async | UDP, TCP, WebSocket, Serial | Callback-based | `--sdk` | +| **C++** | Sync (poll-based) | UDP*, TCP*, WebSocket*, Serial | Observer/Subscriber | `--sdk` (full) or `--sdk_embedded` (minimal) | +| **C#** | Async (Task-based) | UDP, TCP, WebSocket*, Serial | Event-based | `--sdk` | + +*UDP, TCP, WebSocket transports in C++ require ASIO and Simple-WebSocket-Server libraries (included with `--sdk`). Use `--sdk_embedded` for serial-only with no external dependencies. + +## Quick Start + +### TypeScript/JavaScript + +```typescript +import { + StructFrameSdk, + UdpTransport, +} from './struct_frame_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 struct_frame_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..41d35928 --- /dev/null +++ b/docs/user-guide/typescript-sdk.md @@ -0,0 +1,286 @@ +# TypeScript/JavaScript SDK + +The TypeScript/JavaScript SDK provides a high-level, Promise-based interface for structured message communication. + +## Installation + +Generate TypeScript code with SDK: + +```bash +python -m struct_frame your_messages.proto --build_ts --ts_path generated/ts --sdk +``` + +**Note**: The SDK is not included by default. Use the `--sdk` flag to generate SDK files. + +## Available Transports + +### UDP Transport + +Uses Node.js `dgram` module for UDP communication. + +```typescript +import { UdpTransport, UdpTransportConfig } from './struct_frame_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 './struct_frame_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 './struct_frame_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 './struct_frame_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 './struct_frame_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 './struct_frame_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 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