#include "whisker_bridge.h"
#include <cstdlib>
#include <cstring>
#include <mutex>
#include <string>
#include <unordered_map>
namespace {
std::mutex& ModuleRegistryMutex() {
static std::mutex m;
return m;
}
std::unordered_map<std::string, WhiskerModuleDispatchFn>& ModuleRegistry() {
static std::unordered_map<std::string, WhiskerModuleDispatchFn> m;
return m;
}
WhiskerValueRaw MakeHostStubError(const char* message) {
WhiskerValueRaw v;
std::memset(&v, 0, sizeof(v));
v.type = WHISKER_VALUE_ERROR;
if (message != nullptr) {
size_t len = std::strlen(message);
char* buf = static_cast<char*>(std::malloc(len + 1));
std::memcpy(buf, message, len + 1);
v.v.s.ptr = buf;
v.v.s.len = len;
}
return v;
}
}
extern "C" void whisker_bridge_register_module_dispatch(
const char* module_name,
WhiskerModuleDispatchFn dispatch) {
if (module_name == nullptr) return;
std::lock_guard<std::mutex> g(ModuleRegistryMutex());
if (dispatch == nullptr) {
ModuleRegistry().erase(module_name);
} else {
ModuleRegistry()[module_name] = dispatch;
}
}
extern "C" WhiskerValueRaw whisker_bridge_invoke_module(
const char* module_name,
const char* method_name,
const WhiskerValueRaw* args,
size_t arg_count) {
if (module_name == nullptr || method_name == nullptr) {
return MakeHostStubError("module/method name is NULL");
}
WhiskerModuleDispatchFn fn = nullptr;
{
std::lock_guard<std::mutex> g(ModuleRegistryMutex());
auto it = ModuleRegistry().find(module_name);
if (it != ModuleRegistry().end()) {
fn = it->second;
}
}
if (fn == nullptr) {
return MakeHostStubError(
"whisker_bridge_invoke_module: host build has no platform "
"module registered for this name — link against the iOS / "
"Android bridge for real module invocation");
}
return fn(method_name, args, arg_count);
}
extern "C" WhiskerValueRaw whisker_bridge_invoke_element_method(
WhiskerElement* ,
const char* ,
const WhiskerValueRaw* ,
size_t ) {
return MakeHostStubError(
"whisker_bridge_invoke_element_method: host build has no Lynx — "
"link against the iOS / Android bridge for real element-method "
"dispatch (which itself is currently a stub pending Phase 7-Φ.H.2.7)");
}
extern "C" WhiskerValueRaw whisker_bridge_invoke_element_method_with_params(
WhiskerElement* ,
const char* ,
const WhiskerValueRaw* ) {
return MakeHostStubError(
"whisker_bridge_invoke_element_method_with_params: host build has no "
"Lynx — link against the iOS / Android bridge for real built-in "
"UI-method dispatch");
}
extern "C" WhiskerValueRaw whisker_bridge_element_animate(
WhiskerElement* ,
int32_t ,
const char* ,
const WhiskerValueRaw* ,
const WhiskerValueRaw* ) {
return MakeHostStubError(
"whisker_bridge_element_animate: host build has no Lynx — link "
"against the iOS / Android bridge for real animation dispatch");
}
extern "C" bool whisker_bridge_invoke_module_async(
const char* module_name,
const char* method_name,
const WhiskerValueRaw* args,
size_t arg_count,
WhiskerModuleCallback callback,
void* user_data) {
if (callback == nullptr) return false;
WhiskerValueRaw result = whisker_bridge_invoke_module(
module_name, method_name, args, arg_count);
callback(user_data, &result);
whisker_bridge_value_release(&result);
return true;
}
extern "C" bool whisker_bridge_invoke_element_method_async_with_params(
WhiskerElement* ,
const char* ,
const WhiskerValueRaw* ,
WhiskerModuleCallback callback,
void* user_data) {
if (callback == nullptr) return false;
WhiskerValueRaw err = MakeHostStubError(
"whisker_bridge_invoke_element_method_async_with_params: host build "
"has no Lynx");
callback(user_data, &err);
whisker_bridge_value_release(&err);
return true;
}
extern "C" bool whisker_bridge_invoke_element_method_async(
WhiskerElement* ,
const char* ,
const WhiskerValueRaw* ,
size_t ,
WhiskerModuleCallback callback,
void* user_data) {
if (callback == nullptr) return false;
WhiskerValueRaw result = MakeHostStubError(
"whisker_bridge_invoke_element_method_async: host build has no Lynx");
callback(user_data, &result);
whisker_bridge_value_release(&result);
return false;
}
extern "C" void whisker_bridge_value_release(WhiskerValueRaw* value) {
if (value == nullptr) return;
switch (value->type) {
case WHISKER_VALUE_STRING:
case WHISKER_VALUE_ERROR:
std::free(const_cast<char*>(value->v.s.ptr));
value->v.s.ptr = nullptr;
value->v.s.len = 0;
break;
case WHISKER_VALUE_BYTES:
std::free(const_cast<uint8_t*>(value->v.bytes.ptr));
value->v.bytes.ptr = nullptr;
value->v.bytes.len = 0;
break;
case WHISKER_VALUE_ARRAY:
for (size_t i = 0; i < value->v.array.count; i++) {
whisker_bridge_value_release(&value->v.array.items[i]);
}
std::free(value->v.array.items);
value->v.array.items = nullptr;
value->v.array.count = 0;
break;
case WHISKER_VALUE_MAP:
for (size_t i = 0; i < value->v.map.count; i++) {
std::free(const_cast<char*>(value->v.map.entries[i].key.ptr));
whisker_bridge_value_release(&value->v.map.entries[i].value);
}
std::free(value->v.map.entries);
value->v.map.entries = nullptr;
value->v.map.count = 0;
break;
default:
break;
}
value->type = WHISKER_VALUE_NULL;
}
extern "C" void whisker_bridge_log_hello(void) {
}
extern "C" int32_t whisker_bridge_module_add_event_listener(
const char* ,
const char* ,
WhiskerModuleEventCallback ,
void* ) {
return 1;
}
extern "C" void whisker_bridge_module_remove_event_listener(
int32_t ) {
}
extern "C" void whisker_bridge_module_send_event(
const char* ,
const char* ,
const WhiskerValueRaw* ) {
}
extern "C" void whisker_bridge_module_register_observer_hooks(
const char* ,
WhiskerModuleObserverHook ,
WhiskerModuleObserverHook ) {
}
extern "C" void whisker_bridge_log_info(
const char* , const char* ) {
}