Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ set (

src/OpenTrackIOProperties.cpp
src/OpenTrackIOSample.cpp
src/OpenTrackIOTypes.cpp
)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
Expand Down Expand Up @@ -78,7 +79,6 @@ target_include_directories(
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>

)

target_link_libraries(${PROJECT_NAME} PUBLIC nlohmann_json::nlohmann_json)
Expand Down
126 changes: 107 additions & 19 deletions include/opentrackio-cpp/OpenTrackIOHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,16 @@
#pragma once
#include <format>
#include <regex>
#include <string>
#include <type_traits>
#include <nlohmann/json.hpp>

#define TYPE_COVERSION_ASSERT(JsonConcept, CppType) \
static_assert(JsonConcept<CppType>, "Type is not compatible!");

#define TYPE_NON_COVERSION_ASSERT(JsonConcept, CppType) \
static_assert(!JsonConcept<CppType>, "Type is unexpectedly compatible!");

namespace opentrackio
{
template<typename T>
Expand All @@ -32,6 +40,36 @@ namespace opentrackio
{ t.iris } -> std::convertible_to<std::optional<uint16_t>>;
{ t.zoom } -> std::convertible_to<std::optional<uint16_t>>;
};

template<typename T>
concept JsonBool = std::is_same_v<T, bool>;
template<typename T>
concept JsonString = std::is_same_v<T, std::string>;
template<typename T>
concept JsonNumber = std::is_integral_v<T> && !JsonBool<T>;
template<typename T>
concept JsonFloatDouble = std::is_floating_point_v<T> && !JsonNumber<T>;

// Basic type conversion checks to ensure compatability with json library.
TYPE_COVERSION_ASSERT(JsonBool, bool);
TYPE_NON_COVERSION_ASSERT(JsonBool, int);
TYPE_NON_COVERSION_ASSERT(JsonBool, short);
TYPE_NON_COVERSION_ASSERT(JsonBool, long);

TYPE_COVERSION_ASSERT(JsonString, std::string);
TYPE_NON_COVERSION_ASSERT(JsonString, const char*);

TYPE_COVERSION_ASSERT(JsonNumber, int);
TYPE_COVERSION_ASSERT(JsonNumber, long);
TYPE_COVERSION_ASSERT(JsonNumber, short);
TYPE_NON_COVERSION_ASSERT(JsonNumber, float);
TYPE_NON_COVERSION_ASSERT(JsonNumber, double);

TYPE_COVERSION_ASSERT(JsonFloatDouble, float);
TYPE_COVERSION_ASSERT(JsonFloatDouble, double);
TYPE_NON_COVERSION_ASSERT(JsonFloatDouble, int);
TYPE_NON_COVERSION_ASSERT(JsonFloatDouble, long);
TYPE_NON_COVERSION_ASSERT(JsonFloatDouble, short);

class OpenTrackIOHelpers
{
Expand Down Expand Up @@ -83,18 +121,44 @@ namespace opentrackio

template<typename T>
static void assignField(nlohmann::json &json, std::string_view fieldStr, std::optional<T> &field,
std::string_view typeStr, std::vector<std::string> &errors)
std::vector<std::string> &errors)
{
if (json.contains(fieldStr))
{
if (!checkJsonTypeMatch<T>(json[fieldStr], fieldStr, errors))
return;

getFieldFromJson(json[fieldStr], field);
json.erase(fieldStr);
}
}

template<typename T>
static void assignFieldArray(nlohmann::json& json, std::string_view fieldStr, std::optional<std::vector<T>>& field,
std::vector<std::string>& errors)
{
if (json.contains(fieldStr))
{
if (!json[fieldStr].is_array())
{
errors.emplace_back(std::format("field: {0} isn't an array:", fieldStr));
return;
}

for (const auto& jsonValue : json[fieldStr])
{
if (!checkJsonTypeMatch<T>(jsonValue, fieldStr, errors))
return;
}

getFieldFromJson(json[fieldStr], field);
json.erase(fieldStr);
}
}

template<Encoder T>
static void assignField(nlohmann::json &json, std::string_view fieldStr, std::optional<T> &field,
std::string_view typeStr, std::vector<std::string> &errors)
std::vector<std::string> &errors)
{
if (!json.contains(fieldStr))
{
Expand All @@ -104,9 +168,9 @@ namespace opentrackio

field = T{};
auto &encoderJson = json[fieldStr];
assignField(encoderJson, "focus", field->focus, typeStr, errors);
assignField(encoderJson, "iris", field->iris, typeStr, errors);
assignField(encoderJson, "zoom", field->zoom, typeStr, errors);
assignField(encoderJson, "focus", field->focus, errors);
assignField(encoderJson, "iris", field->iris, errors);
assignField(encoderJson, "zoom", field->zoom, errors);

if (!(field->focus.has_value() && field->iris.has_value() && field->zoom.has_value()))
{
Expand Down Expand Up @@ -140,23 +204,47 @@ namespace opentrackio
json.erase(fieldStr);
}
}
};

template<>
inline void OpenTrackIOHelpers::assignField<std::vector<std::string>>(nlohmann::json &json, std::string_view fieldStr,
std::optional<std::vector<std::string>> &field,
std::string_view typeStr, std::vector<std::string> &errors)
{
if (!json.contains(fieldStr) || !json[fieldStr].is_array())
static inline void assignStringArray(nlohmann::json& json, std::string_view fieldStr,
std::optional<std::vector<std::string>>& field,
std::vector<std::string>& errors)
{
field = std::nullopt;
return;
if (!json.contains(fieldStr) || !json[fieldStr].is_array())
{
field = std::nullopt;
return;
}

std::vector<std::string> vec{};
iterateJsonArrayAndPopulateVector<std::string>(json[fieldStr], vec);

field = std::move(vec);
json.erase(fieldStr);
}

std::vector<std::string> vec{};
iterateJsonArrayAndPopulateVector(json[fieldStr], vec);
private:
template<typename FieldT>
static inline constexpr nlohmann::json::value_t getJsonTypeValue()
requires JsonBool<FieldT> || JsonFloatDouble<FieldT> || JsonNumber<FieldT> || JsonString<FieldT>
{
if constexpr (JsonString<FieldT>) { return nlohmann::json::value_t::string; }
else if constexpr (JsonBool<FieldT>) { return nlohmann::json::value_t::boolean; }
else if constexpr (JsonFloatDouble<FieldT>) { return nlohmann::json::value_t::number_float; }
else if constexpr (JsonNumber<FieldT>) { return nlohmann::json::value_t::number_unsigned; }
}

template<typename FieldT>
static inline bool constexpr checkJsonTypeMatch(const nlohmann::json& json, const std::string_view& fieldStr, std::vector<std::string>& errors)
{
nlohmann::json::value_t cppToJsonType = getJsonTypeValue<FieldT>();
if (json.type() != cppToJsonType)
{
errors.emplace_back(std::format("field: {0} of type {1} isn't compatible with {2}.", fieldStr, json.type_name(), typeid(FieldT).name()));
return false;
}

return true;
}

field = std::move(vec);
json.erase(fieldStr);
}
};
} // namespace opentrackio
4 changes: 2 additions & 2 deletions include/opentrackio-cpp/OpenTrackIOProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ namespace opentrackio::opentrackioproperties
struct SourceNumber
{
/**
* Number that identifies the index of the stream from a source from which data is being transported.
* This is most important in the case where a source is producing multiple streams of samples. */
* Number that identifies the index of the stream from a source from which data is being transported.
* This is most important in the case where a source is producing multiple streams of samples. */
Comment on lines +318 to +319

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Number that identifies the index of the stream from a source from which data is being transported.
* This is most important in the case where a source is producing multiple streams of samples. */
* Number that identifies the index of the stream from a source from which data is being transported.
* This is most important in the case where a source is producing multiple streams of samples. */

uint32_t value;

static std::optional<SourceNumber> parse(nlohmann::json& json, std::vector<std::string>& errors);
Expand Down
7 changes: 4 additions & 3 deletions include/opentrackio-cpp/OpenTrackIOSample.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ namespace opentrackio
bool initialise(const nlohmann::json& json);
bool initialise(const std::string_view jsonString);
bool initialise(std::span<const uint8_t> cbor);
const std::vector<std::string>& getErrors() { return m_errorMessages; };
const std::vector<std::string>& getWarnings() { return m_warningMessages; };

const std::vector<std::string>& getErrors() const { return m_errorMessages; };
const std::vector<std::string>& getWarnings() const { return m_warningMessages; };
const nlohmann::json& getJson();

private:
void generateJson();
void parseCameraToJson(nlohmann::json& baseJson);
Expand Down
Loading