Decode request maps directly into Wasm workspaces

This commit is contained in:
udo
2026-07-18 04:21:28 +00:00
parent 516ed94032
commit 5e140d6a5a
7 changed files with 218 additions and 111 deletions
+43 -14
View File
@@ -921,11 +921,11 @@ bool ucb_append_varint(String& out, u64 value)
return(true);
}
bool ucb_read_varint(const String& src, size_t& offset, u64& value_out)
bool ucb_read_varint(const char* src, size_t src_size, size_t& offset, u64& value_out)
{
value_out = 0;
u32 shift = 0;
while(offset < src.size() && shift <= 63)
while(offset < src_size && shift <= 63)
{
u8 byte = (u8)src[offset++];
value_out |= ((u64)(byte & 0x7f) << shift);
@@ -936,6 +936,11 @@ bool ucb_read_varint(const String& src, size_t& offset, u64& value_out)
return(false);
}
bool ucb_read_varint(const String& src, size_t& offset, u64& value_out)
{
return(ucb_read_varint(src.data(), src.size(), offset, value_out));
}
char ucb_node_type(const DValue& value)
{
const DValue& target = value.deref();
@@ -1149,6 +1154,30 @@ String ucb_encode(const DValue& value)
return(out);
}
// Internal request/config transport uses the same UCEB2 map representation
// without first building a duplicate DValue tree.
String ucb_encode_flat_string_map(const StringMap& value)
{
String out;
out.append(UCEB_MAGIC, 4);
out.push_back((char)UCEB_VERSION);
out.push_back(0);
out.push_back('M');
ucb_append_varint(out, 0);
ucb_append_varint(out, value.size());
for(auto& child : value)
{
ucb_append_varint(out, child.first.size());
out.append(child.first.data(), child.first.size());
out.push_back(0);
out.push_back('S');
ucb_append_varint(out, child.second.size());
out.append(child.second.data(), child.second.size());
ucb_append_varint(out, 0);
}
return(out);
}
bool ucb_decode(const String& encoded, DValue& out, String* error_out)
{
String error;
@@ -1176,7 +1205,7 @@ bool ucb_decode(const String& encoded, DValue& out, String* error_out)
}
#ifdef __UCE_WASM_CORE__
static bool ucb_decode_flat_string_map(const String& encoded, StringMap& out, String* error_out)
static bool ucb_decode_flat_string_map(const char* encoded, size_t encoded_size, StringMap& out, String* error_out)
{
String error;
StringMap decoded;
@@ -1185,14 +1214,14 @@ static bool ucb_decode_flat_string_map(const String& encoded, StringMap& out, St
error = message;
return(false);
};
if(encoded.size() < 5 || encoded.compare(0, 4, UCEB_MAGIC) != 0)
if(encoded_size < 5 || memcmp(encoded, UCEB_MAGIC, 4) != 0)
fail("missing UCEB magic header");
else if((u8)encoded[4] != UCEB_VERSION)
fail("unsupported UCEB version");
else
{
offset = 5;
if(encoded.size() - offset < 2)
if(encoded_size - offset < 2)
fail("unexpected end of UCEB2 string map");
else
{
@@ -1201,44 +1230,44 @@ static bool ucb_decode_flat_string_map(const String& encoded, StringMap& out, St
u64 scalar_len = 0, child_count = 0;
if(flags != 0 || type != 'M')
fail("UCEB2 string map root must be a map");
else if(!ucb_read_varint(encoded, offset, scalar_len) || scalar_len != 0)
else if(!ucb_read_varint(encoded, encoded_size, offset, scalar_len) || scalar_len != 0)
fail("UCEB2 string map root must have no scalar");
else if(!ucb_read_varint(encoded, offset, child_count))
else if(!ucb_read_varint(encoded, encoded_size, offset, child_count))
fail("invalid UCEB2 string map child count");
else
{
for(u64 i = 0; error == "" && i < child_count; i++)
{
u64 key_len = 0, value_len = 0, value_children = 0;
if(!ucb_read_varint(encoded, offset, key_len) || key_len > encoded.size() - offset)
if(!ucb_read_varint(encoded, encoded_size, offset, key_len) || key_len > encoded_size - offset)
{
fail("invalid UCEB2 string map key");
break;
}
String key(encoded.data() + offset, (size_t)key_len);
String key(encoded + offset, (size_t)key_len);
offset += (size_t)key_len;
if(encoded.size() - offset < 2)
if(encoded_size - offset < 2)
{
fail("unexpected end of UCEB2 string map value");
break;
}
u8 value_flags = (u8)encoded[offset++];
char value_type = encoded[offset++];
if(value_flags != 0 || value_type != 'S' || !ucb_read_varint(encoded, offset, value_len) || value_len > encoded.size() - offset)
if(value_flags != 0 || value_type != 'S' || !ucb_read_varint(encoded, encoded_size, offset, value_len) || value_len > encoded_size - offset)
{
fail("UCEB2 string map value must be a string scalar");
break;
}
String value(encoded.data() + offset, (size_t)value_len);
String value(encoded + offset, (size_t)value_len);
offset += (size_t)value_len;
if(!ucb_read_varint(encoded, offset, value_children) || value_children != 0)
if(!ucb_read_varint(encoded, encoded_size, offset, value_children) || value_children != 0)
{
fail("UCEB2 string map value cannot have children");
break;
}
decoded[std::move(key)] = std::move(value);
}
if(error == "" && offset != encoded.size())
if(error == "" && offset != encoded_size)
fail("trailing bytes after UCEB2 string map");
}
}
+1
View File
@@ -78,6 +78,7 @@ String to_String(DValue t);
String var_dump(const DValue& map, String prefix = "", String postfix = "\n");
String ucb_encode(const DValue& value);
String ucb_encode_flat_string_map(const StringMap& value);
DValue ucb_decode(const String& encoded);
bool ucb_decode(const String& encoded, DValue& out, String* error_out = 0);