#ifndef SOKR_HPP
#define SOKR_HPP
#include <sokr.h>
#include <cstdint>
#include <stdexcept>
#include <memory>
#include <string>
namespace sokr {
class SokrError : public std::runtime_error {
public:
explicit SokrError(SokrResult result)
: std::runtime_error(result_string(result)), result_(result) {}
[[nodiscard]] SokrResult result() const noexcept { return result_; }
private:
SokrResult result_;
static std::string result_string(SokrResult result) {
switch (result) {
case SOKR_RESULT_OK:
return "Ok";
case SOKR_RESULT_CAPABILITY_DENIED:
return "CapabilityDenied";
case SOKR_RESULT_DISPATCH_FAILED:
return "DispatchFailed";
case SOKR_RESULT_TIMEOUT:
return "Timeout";
case SOKR_RESULT_VERSION_MISMATCH:
return "VersionMismatch";
case SOKR_RESULT_NO_CAPABLE_SUBSTRATE:
return "NoCapableSubstrate";
case SOKR_RESULT_INVALID_INPUT:
return "InvalidInput";
case SOKR_RESULT_INVALID_IR:
return "InvalidIR";
case SOKR_RESULT_NOT_FOUND:
return "NotFound";
case SOKR_RESULT_REGISTRY_FULL:
return "RegistryFull";
}
return "Unknown";
}
};
class RegisteredSubstrate {
public:
RegisteredSubstrate(uint64_t id) noexcept : id_(id) {}
~RegisteredSubstrate() {
if (id_ != 0) {
sokr_deregister_substrate(id_);
}
}
RegisteredSubstrate(const RegisteredSubstrate&) = delete;
RegisteredSubstrate& operator=(const RegisteredSubstrate&) = delete;
RegisteredSubstrate(RegisteredSubstrate&& other) noexcept : id_(other.release()) {}
RegisteredSubstrate& operator=(RegisteredSubstrate&& other) noexcept {
reset(other.release());
return *this;
}
[[nodiscard]] uint64_t get() const noexcept { return id_; }
[[nodiscard]] uint64_t release() noexcept {
auto id = id_;
id_ = 0;
return id;
}
void reset(uint64_t id = 0) noexcept {
if (id_ != 0) {
sokr_deregister_substrate(id_);
}
id_ = id;
}
[[nodiscard]] explicit operator bool() const noexcept { return id_ != 0; }
private:
uint64_t id_;
};
class CompletionToken {
public:
explicit CompletionToken(uint64_t handle = 0) noexcept : handle_(handle) {}
[[nodiscard]] uint64_t handle() const noexcept { return handle_; }
[[nodiscard]] bool is_valid() const noexcept { return handle_ != 0; }
[[nodiscard]] explicit operator bool() const noexcept { return is_valid(); }
private:
uint64_t handle_;
};
class CompletionSignal {
public:
enum class Status {
Pending = SOKR_COMPLETION_SIGNAL_PENDING,
Complete = SOKR_COMPLETION_SIGNAL_COMPLETE,
Failed = SOKR_COMPLETION_SIGNAL_FAILED,
TimedOut = SOKR_COMPLETION_SIGNAL_TIMED_OUT,
};
explicit CompletionSignal(Status status = Status::Pending) noexcept
: status_(status) {}
[[nodiscard]] Status get() const noexcept { return status_; }
[[nodiscard]] bool is_complete() const noexcept {
return status_ == Status::Complete;
}
[[nodiscard]] bool is_pending() const noexcept {
return status_ == Status::Pending;
}
[[nodiscard]] bool is_failed() const noexcept { return status_ == Status::Failed; }
[[nodiscard]] bool is_timed_out() const noexcept {
return status_ == Status::TimedOut;
}
private:
Status status_;
};
class CapabilityQuery {
public:
CapabilityQuery(SokrComputationId id, const char* ir_format, const void* ir_data,
std::size_t ir_data_len)
: id_(id), ir_format_(ir_format), ir_data_(ir_data), ir_data_len_(ir_data_len) {}
[[nodiscard]] SokrCapabilityQuery to_ffi() const noexcept {
return SokrCapabilityQuery{
.computation_id = id_,
.ir_format = ir_format_,
.ir_data_ptr = ir_data_,
.ir_data_len = ir_data_len_,
.padding = {0},
};
}
private:
SokrComputationId id_;
const char* ir_format_;
const void* ir_data_;
std::size_t ir_data_len_;
};
class CapabilityResponse {
public:
explicit CapabilityResponse(const SokrCapabilityResponse& resp)
: result_(resp.result), substrate_id_(resp.substrate_id),
estimated_latency_ns_(resp.estimated_latency_ns) {}
[[nodiscard]] bool is_accepted() const noexcept {
return result_ == SOKR_RESULT_OK;
}
[[nodiscard]] uint64_t substrate_id() const noexcept { return substrate_id_; }
[[nodiscard]] uint64_t estimated_latency_ns() const noexcept {
return estimated_latency_ns_;
}
private:
SokrResult result_;
uint64_t substrate_id_;
uint64_t estimated_latency_ns_;
};
class DispatchRequest {
public:
DispatchRequest(SokrComputationId id, uint64_t substrate_id, const void* ir_data,
std::size_t ir_data_len, const void* params = nullptr,
std::size_t params_len = 0)
: id_(id), substrate_id_(substrate_id), ir_data_(ir_data),
ir_data_len_(ir_data_len), params_(params), params_len_(params_len) {}
[[nodiscard]] SokrDispatchRequest to_ffi() const noexcept {
return SokrDispatchRequest{
.computation_id = id_,
.substrate_id = substrate_id_,
.ir_data_ptr = ir_data_,
.ir_data_len = ir_data_len_,
.params_ptr = params_,
.params_len = params_len_,
.padding = {0},
};
}
private:
SokrComputationId id_;
uint64_t substrate_id_;
const void* ir_data_;
std::size_t ir_data_len_;
const void* params_;
std::size_t params_len_;
};
class CompletionQuery {
public:
explicit CompletionQuery(CompletionToken token, uint64_t timeout_ns = 0)
: token_(token.handle()), timeout_ns_(timeout_ns) {}
[[nodiscard]] SokrCompletionQuery to_ffi() const noexcept {
return SokrCompletionQuery{
.completion_token = token_,
.timeout_ns = timeout_ns_,
.padding = {0},
};
}
private:
uint64_t token_;
uint64_t timeout_ns_;
};
class Registry {
public:
Registry() = default;
RegisteredSubstrate register_substrate(const SokrSubstratePlugin& plugin) {
uint64_t id = 0;
auto result = sokr_register_substrate(&plugin, &id);
if (result != SOKR_RESULT_OK) {
throw SokrError(result);
}
return RegisteredSubstrate(id);
}
CapabilityResponse query_capability(const CapabilityQuery& query) {
auto ffi_query = query.to_ffi();
SokrCapabilityResponse ffi_response = {};
auto result = sokr_capability(&ffi_query, &ffi_response);
if (result != SOKR_RESULT_OK) {
throw SokrError(result);
}
if (ffi_response.result != SOKR_RESULT_OK) {
throw SokrError(ffi_response.result);
}
return CapabilityResponse(ffi_response);
}
CompletionToken dispatch(const DispatchRequest& request) {
auto ffi_request = request.to_ffi();
SokrDispatchResponse ffi_response = {};
auto result = sokr_dispatch(&ffi_request, &ffi_response);
if (result != SOKR_RESULT_OK) {
throw SokrError(result);
}
if (ffi_response.result != SOKR_RESULT_OK) {
throw SokrError(ffi_response.result);
}
return CompletionToken(ffi_response.completion_token);
}
CompletionSignal query_completion(const CompletionQuery& query) {
auto ffi_query = query.to_ffi();
SokrCompletionSignal ffi_signal = SOKR_COMPLETION_SIGNAL_PENDING;
auto result = sokr_completion(&ffi_query, &ffi_signal);
if (result != SOKR_RESULT_OK) {
throw SokrError(result);
}
return CompletionSignal(static_cast<CompletionSignal::Status>(ffi_signal));
}
[[nodiscard]] static const SokrVersion& version() noexcept {
return *sokr_version();
}
};
}
#endif