/*----------------------------------------------------------------------------*/ /* Copyright (c) FIRST 2015. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ /*----------------------------------------------------------------------------*/ #include "ntcore.h" #include #include #include "support/timestamp.h" #include "Value_internal.h" using namespace nt; // Conversion helpers static void ConvertToC(llvm::StringRef in, char** out) { *out = static_cast(std::malloc(in.size() + 1)); std::memmove(*out, in.data(), in.size()); (*out)[in.size()] = '\0'; } static void ConvertToC(const EntryInfo& in, NT_EntryInfo* out) { out->entry = in.entry; ConvertToC(in.name, &out->name); out->type = in.type; out->flags = in.flags; out->last_change = in.last_change; } static void ConvertToC(const ConnectionInfo& in, NT_ConnectionInfo* out) { ConvertToC(in.remote_id, &out->remote_id); ConvertToC(in.remote_ip, &out->remote_ip); out->remote_port = in.remote_port; out->last_update = in.last_update; out->protocol_version = in.protocol_version; } static void ConvertToC(const RpcParamDef& in, NT_RpcParamDef* out) { ConvertToC(in.name, &out->name); ConvertToC(*in.def_value, &out->def_value); } static void ConvertToC(const RpcResultDef& in, NT_RpcResultDef* out) { ConvertToC(in.name, &out->name); out->type = in.type; } static void ConvertToC(const RpcDefinition& in, NT_RpcDefinition* out) { out->version = in.version; ConvertToC(in.name, &out->name); out->num_params = in.params.size(); out->params = static_cast( std::malloc(in.params.size() * sizeof(NT_RpcParamDef))); for (size_t i = 0; i < in.params.size(); ++i) ConvertToC(in.params[i], &out->params[i]); out->num_results = in.results.size(); out->results = static_cast( std::malloc(in.results.size() * sizeof(NT_RpcResultDef))); for (size_t i = 0; i < in.results.size(); ++i) ConvertToC(in.results[i], &out->results[i]); } static void ConvertToC(const RpcAnswer& in, NT_RpcAnswer* out) { out->entry = in.entry; out->call = in.call; ConvertToC(in.name, &out->name); ConvertToC(in.params, &out->params); ConvertToC(in.conn, &out->conn); } static void ConvertToC(const EntryNotification& in, NT_EntryNotification* out) { out->listener = in.listener; out->entry = in.entry; ConvertToC(in.name, &out->name); ConvertToC(*in.value, &out->value); out->flags = in.flags; } static void ConvertToC(const ConnectionNotification& in, NT_ConnectionNotification* out) { out->listener = in.listener; out->connected = in.connected; ConvertToC(in.conn, &out->conn); } static void ConvertToC(const LogMessage& in, NT_LogMessage* out) { out->logger = in.logger; out->level = in.level; out->filename = in.filename; out->line = in.line; ConvertToC(in.message, &out->message); } template static void ConvertToC(const std::vector& in, O** out, size_t* out_len) { if (!out || !out_len) return; *out_len = in.size(); if (in.empty()) { *out = nullptr; return; } *out = static_cast(std::malloc(sizeof(O*) * in.size())); for (size_t i = 0; i < in.size(); ++i) { out[i] = static_cast(std::malloc(sizeof(O))); ConvertToC(in[i], out[i]); } } static void DisposeConnectionInfo(NT_ConnectionInfo* info) { std::free(info->remote_id.str); std::free(info->remote_ip.str); } static void DisposeEntryInfo(NT_EntryInfo* info) { std::free(info->name.str); } static void DisposeEntryNotification(NT_EntryNotification* info) { std::free(info->name.str); NT_DisposeValue(&info->value); } static void DisposeConnectionNotification(NT_ConnectionNotification* info) { DisposeConnectionInfo(&info->conn); } static RpcParamDef ConvertFromC(const NT_RpcParamDef& in) { RpcParamDef out; out.name = ConvertFromC(in.name); out.def_value = ConvertFromC(in.def_value); return out; } static RpcResultDef ConvertFromC(const NT_RpcResultDef& in) { RpcResultDef out; out.name = ConvertFromC(in.name); out.type = in.type; return out; } static RpcDefinition ConvertFromC(const NT_RpcDefinition& in) { RpcDefinition out; out.version = in.version; out.name = ConvertFromC(in.name); out.params.reserve(in.num_params); for (size_t i = 0; i < in.num_params; ++i) out.params.push_back(ConvertFromC(in.params[i])); out.results.reserve(in.num_results); for (size_t i = 0; i < in.num_results; ++i) out.results.push_back(ConvertFromC(in.results[i])); return out; } extern "C" { /* * Instance Functions */ NT_Inst NT_GetDefaultInstance(void) { return nt::GetDefaultInstance(); } NT_Inst NT_CreateInstance(void) { return nt::CreateInstance(); } void NT_DestroyInstance(NT_Inst inst) { return nt::DestroyInstance(inst); } NT_Inst NT_GetInstanceFromHandle(NT_Handle handle) { return nt::GetInstanceFromHandle(handle); } /* * Table Functions */ NT_Entry NT_GetEntry(NT_Inst inst, const char* name, size_t name_len) { return nt::GetEntry(inst, StringRef(name, name_len)); } NT_Entry* NT_GetEntries(NT_Inst inst, const char* prefix, size_t prefix_len, unsigned int types, size_t* count) { auto info_v = nt::GetEntries(inst, StringRef(prefix, prefix_len), types); *count = info_v.size(); if (info_v.size() == 0) return nullptr; // create array and copy into it NT_Entry* info = static_cast(std::malloc(info_v.size() * sizeof(NT_Entry))); std::memcpy(info, info_v.data(), info_v.size() * sizeof(NT_Entry)); return info; } char* NT_GetEntryName(NT_Entry entry, size_t* name_len) { struct NT_String v_name; nt::ConvertToC(nt::GetEntryName(entry), &v_name); *name_len = v_name.len; return v_name.str; } enum NT_Type NT_GetEntryType(NT_Entry entry) { return nt::GetEntryType(entry); } unsigned long long NT_GetEntryLastChange(NT_Entry entry) { return nt::GetEntryLastChange(entry); } void NT_GetEntryValue(NT_Entry entry, struct NT_Value* value) { NT_InitValue(value); auto v = nt::GetEntryValue(entry); if (!v) return; ConvertToC(*v, value); } int NT_SetDefaultEntryValue(NT_Entry entry, const struct NT_Value* default_value) { return nt::SetDefaultEntryValue(entry, ConvertFromC(*default_value)); } int NT_SetEntryValue(NT_Entry entry, const struct NT_Value* value) { return nt::SetEntryValue(entry, ConvertFromC(*value)); } void NT_SetEntryTypeValue(NT_Entry entry, const struct NT_Value* value) { nt::SetEntryTypeValue(entry, ConvertFromC(*value)); } void NT_SetEntryFlags(NT_Entry entry, unsigned int flags) { nt::SetEntryFlags(entry, flags); } unsigned int NT_GetEntryFlags(NT_Entry entry) { return nt::GetEntryFlags(entry); } void NT_DeleteEntry(NT_Entry entry) { nt::DeleteEntry(entry); } void NT_DeleteAllEntries(NT_Inst inst) { nt::DeleteAllEntries(inst); } struct NT_EntryInfo* NT_GetEntryInfo(NT_Inst inst, const char* prefix, size_t prefix_len, unsigned int types, size_t* count) { auto info_v = nt::GetEntryInfo(inst, StringRef(prefix, prefix_len), types); *count = info_v.size(); if (info_v.size() == 0) return nullptr; // create array and copy into it NT_EntryInfo* info = static_cast( std::malloc(info_v.size() * sizeof(NT_EntryInfo))); for (size_t i = 0; i < info_v.size(); ++i) ConvertToC(info_v[i], &info[i]); return info; } NT_Bool NT_GetEntryInfoHandle(NT_Entry entry, struct NT_EntryInfo* info) { auto info_v = nt::GetEntryInfo(entry); if (info_v.name.empty()) return false; ConvertToC(info_v, info); return true; } /* * Callback Creation Functions */ NT_EntryListener NT_AddEntryListener(NT_Inst inst, const char* prefix, size_t prefix_len, void* data, NT_EntryListenerCallback callback, unsigned int flags) { return nt::AddEntryListener(inst, StringRef(prefix, prefix_len), [=](const EntryNotification& event) { NT_EntryNotification c_event; ConvertToC(event, &c_event); callback(data, &c_event); DisposeEntryNotification(&c_event); }, flags); } NT_EntryListener NT_AddEntryListenerSingle(NT_Entry entry, void* data, NT_EntryListenerCallback callback, unsigned int flags) { return nt::AddEntryListener(entry, [=](const EntryNotification& event) { NT_EntryNotification c_event; ConvertToC(event, &c_event); callback(data, &c_event); DisposeEntryNotification(&c_event); }, flags); } NT_EntryListenerPoller NT_CreateEntryListenerPoller(NT_Inst inst) { return nt::CreateEntryListenerPoller(inst); } void NT_DestroyEntryListenerPoller(NT_EntryListenerPoller poller) { nt::DestroyEntryListenerPoller(poller); } NT_EntryListener NT_AddPolledEntryListener(NT_EntryListenerPoller poller, const char* prefix, size_t prefix_len, unsigned int flags) { return nt::AddPolledEntryListener(poller, StringRef(prefix, prefix_len), flags); } NT_EntryListener NT_AddPolledEntryListenerSingle(NT_EntryListenerPoller poller, NT_Entry entry, unsigned int flags) { return nt::AddPolledEntryListener(poller, entry, flags); } struct NT_EntryNotification* NT_PollEntryListener(NT_EntryListenerPoller poller, size_t* len) { auto arr_cpp = nt::PollEntryListener(poller); NT_EntryNotification* arr; ConvertToC(arr_cpp, &arr, len); return arr; } struct NT_EntryNotification* NT_PollEntryListenerTimeout( NT_EntryListenerPoller poller, size_t* len, double timeout, NT_Bool* timed_out) { bool cpp_timed_out = false; auto arr_cpp = nt::PollEntryListener(poller, timeout, &cpp_timed_out); *timed_out = cpp_timed_out; NT_EntryNotification* arr; ConvertToC(arr_cpp, &arr, len); return arr; } void NT_CancelPollEntryListener(NT_EntryListenerPoller poller) { nt::CancelPollEntryListener(poller); } void NT_RemoveEntryListener(NT_EntryListener entry_listener) { nt::RemoveEntryListener(entry_listener); } NT_Bool NT_WaitForEntryListenerQueue(NT_Inst inst, double timeout) { return nt::WaitForEntryListenerQueue(inst, timeout); } NT_ConnectionListener NT_AddConnectionListener( NT_Inst inst, void* data, NT_ConnectionListenerCallback callback, NT_Bool immediate_notify) { return nt::AddConnectionListener(inst, [=](const ConnectionNotification& event) { NT_ConnectionNotification event_c; ConvertToC(event, &event_c); callback(data, &event_c); DisposeConnectionNotification(&event_c); }, immediate_notify != 0); } NT_ConnectionListenerPoller NT_CreateConnectionListenerPoller(NT_Inst inst) { return nt::CreateConnectionListenerPoller(inst); } void NT_DestroyConnectionListenerPoller(NT_ConnectionListenerPoller poller) { nt::DestroyConnectionListenerPoller(poller); } NT_ConnectionListener NT_AddPolledConnectionListener( NT_ConnectionListenerPoller poller, NT_Bool immediate_notify) { return nt::AddPolledConnectionListener(poller, immediate_notify); } struct NT_ConnectionNotification* NT_PollConnectionListener( NT_ConnectionListenerPoller poller, size_t* len) { auto arr_cpp = nt::PollConnectionListener(poller); NT_ConnectionNotification* arr; ConvertToC(arr_cpp, &arr, len); return arr; } struct NT_ConnectionNotification* NT_PollConnectionListenerTimeout( NT_ConnectionListenerPoller poller, size_t* len, double timeout, NT_Bool* timed_out) { bool cpp_timed_out = false; auto arr_cpp = nt::PollConnectionListener(poller, timeout, &cpp_timed_out); *timed_out = cpp_timed_out; NT_ConnectionNotification* arr; ConvertToC(arr_cpp, &arr, len); return arr; } void NT_CancelPollConnectionListener(NT_ConnectionListenerPoller poller) { nt::CancelPollConnectionListener(poller); } void NT_RemoveConnectionListener(NT_ConnectionListener conn_listener) { nt::RemoveConnectionListener(conn_listener); } NT_Bool NT_WaitForConnectionListenerQueue(NT_Inst inst, double timeout) { return nt::WaitForConnectionListenerQueue(inst, timeout); } /* * Remote Procedure Call Functions */ void NT_CreateRpc(NT_Entry entry, const char* def, size_t def_len, void* data, NT_RpcCallback callback) { nt::CreateRpc(entry, StringRef(def, def_len), [=](const RpcAnswer& answer) { NT_RpcAnswer answer_c; ConvertToC(answer, &answer_c); callback(data, &answer_c); NT_DisposeRpcAnswer(&answer_c); }); } NT_RpcCallPoller NT_CreateRpcCallPoller(NT_Inst inst) { return nt::CreateRpcCallPoller(inst); } void NT_DestroyRpcCallPoller(NT_RpcCallPoller poller) { nt::DestroyRpcCallPoller(poller); } void NT_CreatePolledRpc(NT_Entry entry, const char* def, size_t def_len, NT_RpcCallPoller poller) { nt::CreatePolledRpc(entry, StringRef(def, def_len), poller); } NT_RpcAnswer* NT_PollRpc(NT_RpcCallPoller poller, size_t* len) { auto arr_cpp = nt::PollRpc(poller); NT_RpcAnswer* arr; ConvertToC(arr_cpp, &arr, len); return arr; } NT_RpcAnswer* NT_PollRpcTimeout(NT_RpcCallPoller poller, size_t* len, double timeout, NT_Bool* timed_out) { bool cpp_timed_out = false; auto arr_cpp = nt::PollRpc(poller, timeout, &cpp_timed_out); *timed_out = cpp_timed_out; NT_RpcAnswer* arr; ConvertToC(arr_cpp, &arr, len); return arr; } void NT_CancelPollRpc(NT_RpcCallPoller poller) { nt::CancelPollRpc(poller); } NT_Bool NT_WaitForRpcCallQueue(NT_Inst inst, double timeout) { return nt::WaitForRpcCallQueue(inst, timeout); } void NT_PostRpcResponse(NT_Entry entry, NT_RpcCall call, const char* result, size_t result_len) { nt::PostRpcResponse(entry, call, StringRef(result, result_len)); } NT_RpcCall NT_CallRpc(NT_Entry entry, const char* params, size_t params_len) { return nt::CallRpc(entry, StringRef(params, params_len)); } char* NT_GetRpcResult(NT_Entry entry, NT_RpcCall call, size_t* result_len) { std::string result; if (!nt::GetRpcResult(entry, call, &result)) return nullptr; // convert result *result_len = result.size(); char* result_cstr; ConvertToC(result, &result_cstr); return result_cstr; } char* NT_GetRpcResultTimeout(NT_Entry entry, NT_RpcCall call, size_t* result_len, double timeout, NT_Bool* timed_out) { std::string result; bool cpp_timed_out = false; if (!nt::GetRpcResult(entry, call, &result, timeout, &cpp_timed_out)) { *timed_out = cpp_timed_out; return nullptr; } *timed_out = cpp_timed_out; // convert result *result_len = result.size(); char* result_cstr; ConvertToC(result, &result_cstr); return result_cstr; } void NT_CancelRpcResult(NT_Entry entry, NT_RpcCall call) { nt::CancelRpcResult(entry, call); } char* NT_PackRpcDefinition(const NT_RpcDefinition* def, size_t* packed_len) { auto packed = nt::PackRpcDefinition(ConvertFromC(*def)); // convert result *packed_len = packed.size(); char* packed_cstr; ConvertToC(packed, &packed_cstr); return packed_cstr; } NT_Bool NT_UnpackRpcDefinition(const char* packed, size_t packed_len, NT_RpcDefinition* def) { nt::RpcDefinition def_v; if (!nt::UnpackRpcDefinition(StringRef(packed, packed_len), &def_v)) return 0; // convert result ConvertToC(def_v, def); return 1; } char* NT_PackRpcValues(const NT_Value** values, size_t values_len, size_t* packed_len) { // create input vector std::vector> values_v; values_v.reserve(values_len); for (size_t i = 0; i < values_len; ++i) values_v.push_back(ConvertFromC(*values[i])); // make the call auto packed = nt::PackRpcValues(values_v); // convert result *packed_len = packed.size(); char* packed_cstr; ConvertToC(packed, &packed_cstr); return packed_cstr; } NT_Value** NT_UnpackRpcValues(const char* packed, size_t packed_len, const NT_Type* types, size_t types_len) { auto values_v = nt::UnpackRpcValues(StringRef(packed, packed_len), ArrayRef(types, types_len)); if (values_v.size() == 0) return nullptr; // create array and copy into it NT_Value** values = static_cast(std::malloc(values_v.size() * sizeof(NT_Value*))); for (size_t i = 0; i < values_v.size(); ++i) { values[i] = static_cast(std::malloc(sizeof(NT_Value))); ConvertToC(*values_v[i], values[i]); } return values; } /* * Client/Server Functions */ void NT_SetNetworkIdentity(NT_Inst inst, const char* name, size_t name_len) { nt::SetNetworkIdentity(inst, StringRef(name, name_len)); } unsigned int NT_GetNetworkMode(NT_Inst inst) { return nt::GetNetworkMode(inst); } void NT_StartServer(NT_Inst inst, const char* persist_filename, const char* listen_address, unsigned int port) { nt::StartServer(inst, persist_filename, listen_address, port); } void NT_StopServer(NT_Inst inst) { nt::StopServer(inst); } void NT_StartClientNone(NT_Inst inst) { nt::StartClient(inst); } void NT_StartClient(NT_Inst inst, const char* server_name, unsigned int port) { nt::StartClient(inst, server_name, port); } void NT_StartClientMulti(NT_Inst inst, size_t count, const char** server_names, const unsigned int* ports) { std::vector> servers; servers.reserve(count); for (size_t i = 0; i < count; ++i) servers.emplace_back(std::make_pair(server_names[i], ports[i])); nt::StartClient(inst, servers); } void NT_StartClientTeam(NT_Inst inst, unsigned int team, unsigned int port) { nt::StartClientTeam(inst, team, port); } void NT_StopClient(NT_Inst inst) { nt::StopClient(inst); } void NT_SetServer(NT_Inst inst, const char* server_name, unsigned int port) { nt::SetServer(inst, server_name, port); } void NT_SetServerMulti(NT_Inst inst, size_t count, const char** server_names, const unsigned int* ports) { std::vector> servers; servers.reserve(count); for (size_t i = 0; i < count; ++i) servers.emplace_back(std::make_pair(server_names[i], ports[i])); nt::SetServer(inst, servers); } void NT_SetServerTeam(NT_Inst inst, unsigned int team, unsigned int port) { nt::SetServerTeam(inst, team, port); } void NT_StartDSClient(NT_Inst inst, unsigned int port) { nt::StartDSClient(inst, port); } void NT_StopDSClient(NT_Inst inst) { nt::StopDSClient(inst); } void NT_SetUpdateRate(NT_Inst inst, double interval) { nt::SetUpdateRate(inst, interval); } void NT_Flush(NT_Inst inst) { nt::Flush(inst); } NT_Bool NT_IsConnected(NT_Inst inst) { return nt::IsConnected(inst); } struct NT_ConnectionInfo* NT_GetConnections(NT_Inst inst, size_t* count) { auto conn_v = nt::GetConnections(inst); *count = conn_v.size(); if (conn_v.size() == 0) return nullptr; // create array and copy into it NT_ConnectionInfo* conn = static_cast( std::malloc(conn_v.size() * sizeof(NT_ConnectionInfo))); for (size_t i = 0; i < conn_v.size(); ++i) ConvertToC(conn_v[i], &conn[i]); return conn; } /* * File Save/Load Functions */ const char* NT_SavePersistent(NT_Inst inst, const char* filename) { return nt::SavePersistent(inst, filename); } const char* NT_LoadPersistent(NT_Inst inst, const char* filename, void (*warn)(size_t line, const char* msg)) { return nt::LoadPersistent(inst, filename, warn); } const char* NT_SaveEntries(NT_Inst inst, const char* filename, const char* prefix, size_t prefix_len) { return nt::SaveEntries(inst, filename, StringRef(prefix, prefix_len)); } const char* NT_LoadEntries(NT_Inst inst, const char* filename, const char* prefix, size_t prefix_len, void (*warn)(size_t line, const char* msg)) { return nt::LoadEntries(inst, filename, StringRef(prefix, prefix_len), warn); } /* * Utility Functions */ unsigned long long NT_Now() { return wpi::Now(); } NT_Logger NT_AddLogger(NT_Inst inst, void* data, NT_LogFunc func, unsigned int min_level, unsigned int max_level) { return nt::AddLogger(inst, [=](const LogMessage& msg) { NT_LogMessage msg_c; ConvertToC(msg, &msg_c); func(data, &msg_c); NT_DisposeLogMessage(&msg_c); }, min_level, max_level); } NT_LoggerPoller NT_CreateLoggerPoller(NT_Inst inst) { return nt::CreateLoggerPoller(inst); } void NT_DestroyLoggerPoller(NT_LoggerPoller poller) { nt::DestroyLoggerPoller(poller); } NT_Logger NT_AddPolledLogger(NT_LoggerPoller poller, unsigned int min_level, unsigned int max_level) { return nt::AddPolledLogger(poller, min_level, max_level); } struct NT_LogMessage* NT_PollLogger(NT_LoggerPoller poller, size_t* len) { auto arr_cpp = nt::PollLogger(poller); NT_LogMessage* arr; ConvertToC(arr_cpp, &arr, len); return arr; } struct NT_LogMessage* NT_PollLoggerTimeout(NT_LoggerPoller poller, size_t* len, double timeout, NT_Bool* timed_out) { bool cpp_timed_out = false; auto arr_cpp = nt::PollLogger(poller, timeout, &cpp_timed_out); *timed_out = cpp_timed_out; NT_LogMessage* arr; ConvertToC(arr_cpp, &arr, len); return arr; } void NT_CancelPollLogger(NT_LoggerPoller poller) { nt::CancelPollLogger(poller); } void NT_RemoveLogger(NT_Logger logger) { nt::RemoveLogger(logger); } NT_Bool NT_WaitForLoggerQueue(NT_Inst inst, double timeout) { return nt::WaitForLoggerQueue(inst, timeout); } void NT_DisposeValue(NT_Value* value) { switch (value->type) { case NT_UNASSIGNED: case NT_BOOLEAN: case NT_DOUBLE: break; case NT_STRING: case NT_RAW: case NT_RPC: std::free(value->data.v_string.str); break; case NT_BOOLEAN_ARRAY: std::free(value->data.arr_boolean.arr); break; case NT_DOUBLE_ARRAY: std::free(value->data.arr_double.arr); break; case NT_STRING_ARRAY: { for (size_t i = 0; i < value->data.arr_string.size; i++) std::free(value->data.arr_string.arr[i].str); std::free(value->data.arr_string.arr); break; } default: assert(false && "unknown value type"); } value->type = NT_UNASSIGNED; value->last_change = 0; } void NT_InitValue(NT_Value* value) { value->type = NT_UNASSIGNED; value->last_change = 0; } void NT_DisposeString(NT_String* str) { std::free(str->str); str->str = nullptr; str->len = 0; } void NT_InitString(NT_String* str) { str->str = nullptr; str->len = 0; } void NT_DisposeEntryArray(NT_Entry* arr, size_t count) { std::free(arr); } void NT_DisposeConnectionInfoArray(NT_ConnectionInfo* arr, size_t count) { for (size_t i = 0; i < count; i++) DisposeConnectionInfo(&arr[i]); std::free(arr); } void NT_DisposeEntryInfoArray(NT_EntryInfo* arr, size_t count) { for (size_t i = 0; i < count; i++) DisposeEntryInfo(&arr[i]); std::free(arr); } void NT_DisposeEntryInfo(NT_EntryInfo* info) { DisposeEntryInfo(info); } void NT_DisposeEntryNotificationArray(NT_EntryNotification* arr, size_t count) { for (size_t i = 0; i < count; i++) DisposeEntryNotification(&arr[i]); std::free(arr); } void NT_DisposeEntryNotification(NT_EntryNotification* info) { DisposeEntryNotification(info); } void NT_DisposeConnectionNotificationArray(NT_ConnectionNotification* arr, size_t count) { for (size_t i = 0; i < count; i++) DisposeConnectionNotification(&arr[i]); std::free(arr); } void NT_DisposeConnectionNotification(NT_ConnectionNotification* info) { DisposeConnectionNotification(info); } void NT_DisposeLogMessageArray(NT_LogMessage* arr, size_t count) { for (size_t i = 0; i < count; i++) NT_DisposeLogMessage(&arr[i]); std::free(arr); } void NT_DisposeLogMessage(NT_LogMessage* info) { std::free(info->message); } void NT_DisposeRpcDefinition(NT_RpcDefinition* def) { NT_DisposeString(&def->name); for (size_t i = 0; i < def->num_params; ++i) { NT_DisposeString(&def->params[i].name); NT_DisposeValue(&def->params[i].def_value); } std::free(def->params); def->params = nullptr; def->num_params = 0; for (size_t i = 0; i < def->num_results; ++i) NT_DisposeString(&def->results[i].name); std::free(def->results); def->results = nullptr; def->num_results = 0; } void NT_DisposeRpcAnswerArray(NT_RpcAnswer* arr, size_t count) { for (size_t i = 0; i < count; i++) NT_DisposeRpcAnswer(&arr[i]); std::free(arr); } void NT_DisposeRpcAnswer(NT_RpcAnswer* call_info) { NT_DisposeString(&call_info->name); NT_DisposeString(&call_info->params); DisposeConnectionInfo(&call_info->conn); } /* Interop Utility Functions */ /* Array and Struct Allocations */ /* Allocates a char array of the specified size.*/ char* NT_AllocateCharArray(size_t size) { char* retVal = static_cast(std::malloc(size * sizeof(char))); return retVal; } /* Allocates an integer or boolean array of the specified size. */ int* NT_AllocateBooleanArray(size_t size) { int* retVal = static_cast(std::malloc(size * sizeof(int))); return retVal; } /* Allocates a double array of the specified size. */ double* NT_AllocateDoubleArray(size_t size) { double* retVal = static_cast(std::malloc(size * sizeof(double))); return retVal; } /* Allocates an NT_String array of the specified size. */ struct NT_String* NT_AllocateStringArray(size_t size) { NT_String* retVal = static_cast(std::malloc(size * sizeof(NT_String))); return retVal; } void NT_FreeCharArray(char* v_char) { std::free(v_char); } void NT_FreeDoubleArray(double* v_double) { std::free(v_double); } void NT_FreeBooleanArray(int* v_boolean) { std::free(v_boolean); } void NT_FreeStringArray(struct NT_String* v_string, size_t arr_size) { for (size_t i = 0; i < arr_size; i++) std::free(v_string[i].str); std::free(v_string); } NT_Bool NT_SetEntryDouble(NT_Entry entry, unsigned long long time, double v_double, NT_Bool force) { if (force != 0) { nt::SetEntryTypeValue(entry, Value::MakeDouble(v_double, time)); return 1; } else { return nt::SetEntryValue(entry, Value::MakeDouble(v_double, time)); } } NT_Bool NT_SetEntryBoolean(NT_Entry entry, unsigned long long time, NT_Bool v_boolean, NT_Bool force) { if (force != 0) { nt::SetEntryTypeValue(entry, Value::MakeBoolean(v_boolean != 0, time)); return 1; } else { return nt::SetEntryValue(entry, Value::MakeBoolean(v_boolean != 0, time)); } } NT_Bool NT_SetEntryString(NT_Entry entry, unsigned long long time, const char* str, size_t str_len, NT_Bool force) { if (force != 0) { nt::SetEntryTypeValue(entry, Value::MakeString(StringRef(str, str_len), time)); return 1; } else { return nt::SetEntryValue(entry, Value::MakeString(StringRef(str, str_len), time)); } } NT_Bool NT_SetEntryRaw(NT_Entry entry, unsigned long long time, const char* raw, size_t raw_len, NT_Bool force) { if (force != 0) { nt::SetEntryTypeValue(entry, Value::MakeRaw(StringRef(raw, raw_len), time)); return 1; } else { return nt::SetEntryValue(entry, Value::MakeRaw(StringRef(raw, raw_len), time)); } } NT_Bool NT_SetEntryBooleanArray(NT_Entry entry, unsigned long long time, const NT_Bool* arr, size_t size, NT_Bool force) { if (force != 0) { nt::SetEntryTypeValue( entry, Value::MakeBooleanArray(llvm::makeArrayRef(arr, size), time)); return 1; } else { return nt::SetEntryValue( entry, Value::MakeBooleanArray(llvm::makeArrayRef(arr, size), time)); } } NT_Bool NT_SetEntryDoubleArray(NT_Entry entry, unsigned long long time, const double* arr, size_t size, NT_Bool force) { if (force != 0) { nt::SetEntryTypeValue( entry, Value::MakeDoubleArray(llvm::makeArrayRef(arr, size), time)); return 1; } else { return nt::SetEntryValue( entry, Value::MakeDoubleArray(llvm::makeArrayRef(arr, size), time)); } } NT_Bool NT_SetEntryStringArray(NT_Entry entry, unsigned long long time, const struct NT_String* arr, size_t size, NT_Bool force) { std::vector v; v.reserve(size); for (size_t i = 0; i < size; ++i) v.push_back(ConvertFromC(arr[i])); if (force != 0) { nt::SetEntryTypeValue(entry, Value::MakeStringArray(std::move(v), time)); return 1; } else { return nt::SetEntryValue(entry, Value::MakeStringArray(std::move(v), time)); } } enum NT_Type NT_GetValueType(const struct NT_Value* value) { if (!value) return NT_Type::NT_UNASSIGNED; return value->type; } NT_Bool NT_GetValueBoolean(const struct NT_Value* value, unsigned long long* last_change, NT_Bool* v_boolean) { if (!value || value->type != NT_Type::NT_BOOLEAN) return 0; *v_boolean = value->data.v_boolean; *last_change = value->last_change; return 1; } NT_Bool NT_GetValueDouble(const struct NT_Value* value, unsigned long long* last_change, double* v_double) { if (!value || value->type != NT_Type::NT_DOUBLE) return 0; *last_change = value->last_change; *v_double = value->data.v_double; return 1; } char* NT_GetValueString(const struct NT_Value* value, unsigned long long* last_change, size_t* str_len) { if (!value || value->type != NT_Type::NT_STRING) return nullptr; *last_change = value->last_change; *str_len = value->data.v_string.len; char* str = (char*)std::malloc(value->data.v_string.len + 1); std::memcpy(str, value->data.v_string.str, value->data.v_string.len + 1); return str; } char* NT_GetValueRaw(const struct NT_Value* value, unsigned long long* last_change, size_t* raw_len) { if (!value || value->type != NT_Type::NT_RAW) return nullptr; *last_change = value->last_change; *raw_len = value->data.v_string.len; char* raw = (char*)std::malloc(value->data.v_string.len + 1); std::memcpy(raw, value->data.v_string.str, value->data.v_string.len + 1); return raw; } NT_Bool* NT_GetValueBooleanArray(const struct NT_Value* value, unsigned long long* last_change, size_t* arr_size) { if (!value || value->type != NT_Type::NT_BOOLEAN_ARRAY) return nullptr; *last_change = value->last_change; *arr_size = value->data.arr_boolean.size; NT_Bool* arr = (int*)std::malloc(value->data.arr_boolean.size * sizeof(NT_Bool)); std::memcpy(arr, value->data.arr_boolean.arr, value->data.arr_boolean.size * sizeof(NT_Bool)); return arr; } double* NT_GetValueDoubleArray(const struct NT_Value* value, unsigned long long* last_change, size_t* arr_size) { if (!value || value->type != NT_Type::NT_DOUBLE_ARRAY) return nullptr; *last_change = value->last_change; *arr_size = value->data.arr_double.size; double* arr = (double*)std::malloc(value->data.arr_double.size * sizeof(double)); std::memcpy(arr, value->data.arr_double.arr, value->data.arr_double.size * sizeof(double)); return arr; } NT_String* NT_GetValueStringArray(const struct NT_Value* value, unsigned long long* last_change, size_t* arr_size) { if (!value || value->type != NT_Type::NT_STRING_ARRAY) return nullptr; *last_change = value->last_change; *arr_size = value->data.arr_string.size; NT_String* arr = static_cast( std::malloc(value->data.arr_string.size * sizeof(NT_String))); for (size_t i = 0; i < value->data.arr_string.size; ++i) { size_t len = value->data.arr_string.arr[i].len; arr[i].len = len; arr[i].str = (char*)std::malloc(len + 1); std::memcpy(arr[i].str, value->data.arr_string.arr[i].str, len + 1); } return arr; } NT_Bool NT_SetDefaultEntryBoolean(NT_Entry entry, unsigned long long time, NT_Bool default_boolean) { return nt::SetDefaultEntryValue( entry, Value::MakeBoolean(default_boolean != 0, time)); } NT_Bool NT_SetDefaultEntryDouble(NT_Entry entry, unsigned long long time, double default_double) { return nt::SetDefaultEntryValue(entry, Value::MakeDouble(default_double, time)); } NT_Bool NT_SetDefaultEntryString(NT_Entry entry, unsigned long long time, const char* default_value, size_t default_len) { return nt::SetDefaultEntryValue( entry, Value::MakeString(StringRef(default_value, default_len), time)); } NT_Bool NT_SetDefaultEntryRaw(NT_Entry entry, unsigned long long time, const char* default_value, size_t default_len) { return nt::SetDefaultEntryValue( entry, Value::MakeRaw(StringRef(default_value, default_len), time)); } NT_Bool NT_SetDefaultEntryBooleanArray(NT_Entry entry, unsigned long long time, const NT_Bool* default_value, size_t default_size) { return nt::SetDefaultEntryValue( entry, Value::MakeBooleanArray( llvm::makeArrayRef(default_value, default_size), time)); } NT_Bool NT_SetDefaultEntryDoubleArray(NT_Entry entry, unsigned long long time, const double* default_value, size_t default_size) { return nt::SetDefaultEntryValue( entry, Value::MakeDoubleArray( llvm::makeArrayRef(default_value, default_size), time)); } NT_Bool NT_SetDefaultEntryStringArray(NT_Entry entry, unsigned long long time, const struct NT_String* default_value, size_t default_size) { std::vector vec; vec.reserve(default_size); for (size_t i = 0; i < default_size; ++i) vec.push_back(ConvertFromC(default_value[i])); return nt::SetDefaultEntryValue(entry, Value::MakeStringArray(std::move(vec), time)); } NT_Bool NT_GetEntryBoolean(NT_Entry entry, unsigned long long* last_change, NT_Bool* v_boolean) { auto v = nt::GetEntryValue(entry); if (!v || !v->IsBoolean()) return 0; *v_boolean = v->GetBoolean(); *last_change = v->last_change(); return 1; } NT_Bool NT_GetEntryDouble(NT_Entry entry, unsigned long long* last_change, double* v_double) { auto v = nt::GetEntryValue(entry); if (!v || !v->IsDouble()) return 0; *last_change = v->last_change(); *v_double = v->GetDouble(); return 1; } char* NT_GetEntryString(NT_Entry entry, unsigned long long* last_change, size_t* str_len) { auto v = nt::GetEntryValue(entry); if (!v || !v->IsString()) return nullptr; *last_change = v->last_change(); struct NT_String v_string; nt::ConvertToC(v->GetString(), &v_string); *str_len = v_string.len; return v_string.str; } char* NT_GetEntryRaw(NT_Entry entry, unsigned long long* last_change, size_t* raw_len) { auto v = nt::GetEntryValue(entry); if (!v || !v->IsRaw()) return nullptr; *last_change = v->last_change(); struct NT_String v_raw; nt::ConvertToC(v->GetRaw(), &v_raw); *raw_len = v_raw.len; return v_raw.str; } NT_Bool* NT_GetEntryBooleanArray(NT_Entry entry, unsigned long long* last_change, size_t* arr_size) { auto v = nt::GetEntryValue(entry); if (!v || !v->IsBooleanArray()) return nullptr; *last_change = v->last_change(); auto vArr = v->GetBooleanArray(); NT_Bool* arr = static_cast(std::malloc(vArr.size() * sizeof(NT_Bool))); *arr_size = vArr.size(); std::copy(vArr.begin(), vArr.end(), arr); return arr; } double* NT_GetEntryDoubleArray(NT_Entry entry, unsigned long long* last_change, size_t* arr_size) { auto v = nt::GetEntryValue(entry); if (!v || !v->IsDoubleArray()) return nullptr; *last_change = v->last_change(); auto vArr = v->GetDoubleArray(); double* arr = static_cast(std::malloc(vArr.size() * sizeof(double))); *arr_size = vArr.size(); std::copy(vArr.begin(), vArr.end(), arr); return arr; } NT_String* NT_GetEntryStringArray(NT_Entry entry, unsigned long long* last_change, size_t* arr_size) { auto v = nt::GetEntryValue(entry); if (!v || !v->IsStringArray()) return nullptr; *last_change = v->last_change(); auto vArr = v->GetStringArray(); NT_String* arr = static_cast(std::malloc(vArr.size() * sizeof(NT_String))); for (size_t i = 0; i < vArr.size(); ++i) { ConvertToC(vArr[i], &arr[i]); } *arr_size = vArr.size(); return arr; } } // extern "C"