diff --git a/src/sfizz/Messaging.h b/src/sfizz/Messaging.h index ab76237f..0f48587b 100644 --- a/src/sfizz/Messaging.h +++ b/src/sfizz/Messaging.h @@ -6,13 +6,12 @@ #pragma once #include "sfizz_message.h" -#include namespace sfz { template struct OscDataTraits; template using OscType = typename OscDataTraits::type; -template using OscDecayedType = typename std::decay>::type; +template using OscDecayedType = typename OscDataTraits::decayed_type; class Client { public: diff --git a/src/sfizz/Messaging.hpp b/src/sfizz/Messaging.hpp index e5df7537..587e671d 100644 --- a/src/sfizz/Messaging.hpp +++ b/src/sfizz/Messaging.hpp @@ -6,6 +6,7 @@ #pragma once #include "Messaging.h" +#include #include #include @@ -30,30 +31,33 @@ inline void Client::receive(int delay, const char* path, OscDecayedType... } /// -#define OSC_SCALAR_TRAITS(tag, member) \ - template <> struct OscDataTraits { \ - typedef decltype(sfizz_arg_t::member) type; \ - static_assert(std::is_scalar::value, ""); \ - static inline sfizz_arg_t make_arg(type v) { \ - sfizz_arg_t a; a.member = v; return a; \ - } \ +#define OSC_SCALAR_TRAITS(tag, member) \ + template <> struct OscDataTraits { \ + typedef decltype(sfizz_arg_t::member) type; \ + typedef type decayed_type; \ + static_assert(std::is_scalar::value, ""); \ + static inline sfizz_arg_t make_arg(decayed_type v) { \ + sfizz_arg_t a; a.member = v; return a; \ + } \ } -#define OSC_BYTEARRAY_TRAITS(tag, member) \ - template <> struct OscDataTraits { \ - typedef decltype(sfizz_arg_t::member) type; \ - static_assert(std::is_array::value, ""); \ - static inline sfizz_arg_t make_arg(type v) { \ - sfizz_arg_t a; \ - std::memcpy(a.member, v, sizeof(a.member)); \ - return a; \ - } \ +#define OSC_BYTEARRAY_TRAITS(tag, member) \ + template <> struct OscDataTraits { \ + typedef decltype(sfizz_arg_t::member) type; \ + static_assert(std::is_array::value, ""); \ + typedef const typename std::remove_all_extents::type* decayed_type; \ + static inline sfizz_arg_t make_arg(decayed_type v) { \ + sfizz_arg_t a; \ + std::memcpy(a.member, v, sizeof(a.member)); \ + return a; \ + } \ } -#define OSC_VOID_TRAITS(tag) \ - template <> struct OscDataTraits { \ - typedef struct Nothing {} type; \ - static inline sfizz_arg_t make_arg(type v) { \ - sfizz_arg_t a; (void)v; return a; \ - } \ +#define OSC_VOID_TRAITS(tag) \ + template <> struct OscDataTraits { \ + typedef struct Nothing {} type; \ + typedef type decayed_type; \ + static inline sfizz_arg_t make_arg(decayed_type v) { \ + sfizz_arg_t a; (void)v; return a; \ + } \ } OSC_SCALAR_TRAITS('i', i); diff --git a/tests/MessagingT.cpp b/tests/MessagingT.cpp index 2b52df56..5496ca82 100644 --- a/tests/MessagingT.cpp +++ b/tests/MessagingT.cpp @@ -93,3 +93,33 @@ TEST_CASE("[Messaging] OSC message creation") REQUIRE(args2[4].f == 5.678f); } } + +TEST_CASE("[Messaging] Type-safe client API") +{ + sfz::Client client(nullptr); + + static const int32_t i = 777; + static const int64_t h = 0x100000000LL; + static const float f = 3.14f; + static const double d = 6.28; + static const uint8_t m[4] = {0x90, 0x40, 0xFF}; + static const sfizz_blob_t b { reinterpret_cast("MyBinaryString"), 14 }; + static const char s[] = "Hello, World!"; + + client.setReceiveCallback(+[](void*, int, const char* path, const char* sig, const sfizz_arg_t* args) { + REQUIRE(!strcmp(path, "/test")); + REQUIRE(!strcmp(sig, "imhfdsbTFNI")); + unsigned index = 0; + REQUIRE(args[index++].i == i); + REQUIRE(!memcmp(args[index++].m, m, 4)); + REQUIRE(args[index++].h == h); + REQUIRE(args[index++].f == f); + REQUIRE(args[index++].d == d); + REQUIRE(!strcmp(args[index++].s, s)); + REQUIRE(args[index ].b->data == b.data); + REQUIRE(args[index++].b->size == b.size); + }); + + client.receive<'i', 'm', 'h', 'f', 'd', 's', 'b', 'T', 'F', 'N', 'I'>( + 0, "/test", i, m, h, f, d, s, &b, {}, {}, {}, {}); +}