// WASM-PROPOSAL Phase 2 — native UCE core subset compiled to WASM. // // This scaffold validates the Phase 2 membrane without the Phase 3 dynamic // loader: the core owns memory/libc++/DValue/UCEB1, imports a tiny hostcall // surface, decodes a host-provided UCEB1 request context, and invokes one // statically linked real .uce page. #include #include #include "../../src/lib/types.h" #include "../../src/lib/dvalue.cpp" extern "C" { size_t uce_host_ctx_read(char* buf, size_t cap); void uce_host_log(int level, const char* buf, size_t len); } #define RENDER(X) extern "C" void __uce_render(X) #include "page.uce" static Request g_request; static ByteStream g_ob; static String g_output; SharedUnit::~SharedUnit() {} String nibble(String div, String& haystack) { auto pos = haystack.find(div); if(pos == String::npos) { auto result = haystack; haystack.clear(); return(result); } auto result = haystack.substr(0, pos); haystack.erase(0, pos + div.length()); return(result); } void Request::ob_start() { ob_stack.push_back(new ByteStream()); ob = ob_stack.back(); } void Request::set_status(s32 code, String reason) { if(reason == "") reason = code == 200 ? "OK" : "Status"; response_code = "HTTP/1.1 " + std::to_string(code) + " " + reason; } Request::~Request() { for(auto* stream : ob_stack) delete stream; ob_stack.clear(); } static void phase2_clear_ob_stack() { for(auto* stream : g_request.ob_stack) delete stream; g_request.ob_stack.clear(); } static void phase2_apply_context(DValue& root) { g_request.call = root; g_request.params.clear(); DValue* params = root.key("params"); if(params) { params->each([&](const DValue& item, String key) { g_request.params[key] = item.to_string(); }); } } extern "C" { void* uce_alloc(size_t len) { return(malloc(len)); } void uce_free(void* ptr) { free(ptr); } int uce_phase2_render() { context = &g_request; phase2_clear_ob_stack(); g_ob.str(""); g_ob.clear(); g_request.ob = &g_ob; g_request.out = ""; g_output = ""; size_t ctx_required = uce_host_ctx_read(0, 0); if(ctx_required == 0) return(10); char* ctx_buf = (char*)malloc(ctx_required); if(ctx_buf == 0) return(11); size_t ctx_len = uce_host_ctx_read(ctx_buf, ctx_required); if(ctx_len != ctx_required) { free(ctx_buf); return(12); } DValue decoded; String error; bool ok = ucb_decode(String(ctx_buf, ctx_len), decoded, &error); free(ctx_buf); if(!ok) { uce_host_log(3, error.data(), error.size()); return(20); } phase2_apply_context(decoded); __uce_render(g_request); g_output = g_ob.str(); return(0); } const char* uce_phase2_output_data() { return(g_output.data()); } size_t uce_phase2_output_size() { return(g_output.size()); } }