mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-03 03:01:44 +00:00
1172 lines
38 KiB
C++
1172 lines
38 KiB
C++
/*----------------------------------------------------------------------------*/
|
|
/* 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 <cassert>
|
|
#include <cstdlib>
|
|
|
|
#include "support/timestamp.h"
|
|
|
|
#include "Value_internal.h"
|
|
|
|
using namespace nt;
|
|
|
|
// Conversion helpers
|
|
|
|
static void ConvertToC(llvm::StringRef in, char** out) {
|
|
*out = static_cast<char*>(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<NT_RpcParamDef*>(
|
|
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<NT_RpcResultDef*>(
|
|
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 <typename I, typename O>
|
|
static void ConvertToC(const std::vector<I>& 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<O*>(std::malloc(sizeof(O*) * in.size()));
|
|
for (size_t i = 0; i < in.size(); ++i) {
|
|
out[i] = static_cast<O*>(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<NT_Entry*>(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<NT_EntryInfo*>(
|
|
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<std::shared_ptr<Value>> 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<NT_Type>(types, types_len));
|
|
if (values_v.size() == 0) return nullptr;
|
|
|
|
// create array and copy into it
|
|
NT_Value** values =
|
|
static_cast<NT_Value**>(std::malloc(values_v.size() * sizeof(NT_Value*)));
|
|
for (size_t i = 0; i < values_v.size(); ++i) {
|
|
values[i] = static_cast<NT_Value*>(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<std::pair<StringRef, unsigned int>> 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<std::pair<StringRef, unsigned int>> 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<NT_ConnectionInfo*>(
|
|
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<char*>(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<int*>(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<double*>(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<NT_String*>(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<std::string> 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<NT_String*>(
|
|
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<std::string> 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<int*>(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<double*>(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<NT_String*>(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"
|