diff --git a/layout/src/ffi.rs b/layout/src/ffi.rs index 14c06dc9..4ff7bb39 100644 --- a/layout/src/ffi.rs +++ b/layout/src/ffi.rs @@ -89,14 +89,7 @@ extern "C" { out: *mut *mut u8, out_len: *mut u32, ) -> c_int; - fn kvspaceNewChar( - kind: *const c_char, - s: *const c_char, - out: *mut *mut u8, - out_len: *mut u32, - ) -> c_int; - fn kvspaceNewCharByte(bytes: *const u8, len: u32, out: *mut *mut u8, out_len: *mut u32) - -> c_int; + fn kvspaceNewChar(bytes: *const u8, len: u32, out: *mut *mut u8, out_len: *mut u32) -> c_int; fn kvspaceNewBool(v: u8, out: *mut *mut u8, out_len: *mut u32) -> c_int; fn kvspaceNewInt64(v: i64, out: *mut *mut u8, out_len: *mut u32) -> c_int; fn kvspaceNewFloat64(v: f64, out: *mut *mut u8, out_len: *mut u32) -> c_int; @@ -307,16 +300,35 @@ pub fn new_ptr(kind: &str, target: &str, array_len: i32) -> Vec { } pub fn new_char(kind: &str, s: &str) -> Vec { + let bytes = s.as_bytes(); + if kind == "char/utf8" { + return new_char_byte(bytes); + } + let (raw, n) = if kind == "char/utf32" { + let v: Vec = s.chars().flat_map(|c| (c as u32).to_le_bytes()).collect(); + let n = (v.len() / 4) as i32; + (v, n) + } else { + (bytes.to_vec(), bytes.len() as i32) + }; let ck = CString::new(kind).expect("no NUL"); - let cs = CString::new(s).expect("no NUL"); + let dims = [n]; call_alloc(|out, out_len| unsafe { - kvspaceNewChar(ck.as_ptr(), cs.as_ptr(), out, out_len) + kvspaceTlvEncode( + ck.as_ptr(), + raw.as_ptr(), + raw.len() as u32, + dims.as_ptr(), + 1, + out, + out_len, + ) }) } pub fn new_char_byte(bytes: &[u8]) -> Vec { call_alloc(|out, out_len| unsafe { - kvspaceNewCharByte(bytes.as_ptr(), bytes.len() as u32, out, out_len) + kvspaceNewChar(bytes.as_ptr(), bytes.len() as u32, out, out_len) }) } diff --git a/runtime-rwirext_example/go/json/edge_test.go b/runtime-rwirext_example/go/json/edge_test.go index 6dac9423..dcc3d87e 100644 --- a/runtime-rwirext_example/go/json/edge_test.go +++ b/runtime-rwirext_example/go/json/edge_test.go @@ -10,7 +10,7 @@ func TestEdgeKeys(t *testing.T) { c := rtConn(t) defer disconnect(c) cases := []string{ - `{"a.b":1}`, // 点号 key(应拒绝) + `{"a.b":1}`, // 点号 key(合法,· 才是成员分隔符) `{"a/b":1}`, // 斜杠 key(应拒绝) `{"a[b]":1}`, // 方括号 key(应拒绝) `{"a\nb":1}`, // 换行 key(应拒绝) diff --git a/runtime-rwirext_example/go/json/json.go b/runtime-rwirext_example/go/json/json.go index a647c2de..ff0f3763 100644 --- a/runtime-rwirext_example/go/json/json.go +++ b/runtime-rwirext_example/go/json/json.go @@ -21,8 +21,9 @@ extern int kvspaceSet(void *h, const char *const *keys, const uint8_t *vals, extern int kvspaceList(void *h, const char *prefix, int expand_ext, int resolve, uint8_t **out, uint32_t *out_len); extern int kvspaceDel(void *h, const char *const *keys, uint32_t nkeys, char *err, uint32_t err_cap); +extern int kvspaceDelTree(void *h, const char *prefix, char *err, uint32_t err_cap); extern int kvspaceMkindex(void *h, const char *path, char *err, uint32_t err_cap); -extern int kvspaceNewChar(const char *kind, const char *s, uint8_t **out, uint32_t *out_len); +extern int kvspaceNewChar(const uint8_t *bytes, uint32_t len, uint8_t **out, uint32_t *out_len); // XValue 头(repr(C),对齐 kvspace ABI):kindexpr 为唯一类型真相,body 段靠 offset/len 定位。 typedef struct { @@ -124,13 +125,11 @@ func setTLV(c unsafe.Pointer, key string, tlv []byte) { } func setChar(c unsafe.Pointer, key, val string) { - ck := cstr("char/utf8") - cv := cstr(val) - defer C.free(unsafe.Pointer(ck)) - defer C.free(unsafe.Pointer(cv)) + cv := C.CBytes([]byte(val)) + defer C.free(cv) var out *C.uint8_t var outLen C.uint32_t - if C.kvspaceNewChar(ck, cv, &out, &outLen) != 0 || out == nil { + if C.kvspaceNewChar((*C.uint8_t)(cv), C.uint32_t(len(val)), &out, &outLen) != 0 || out == nil { return } defer C.kvspaceBytesFree(out, outLen) @@ -150,6 +149,13 @@ func del(c unsafe.Pointer, key string) { C.kvspaceDel(c, &keys[0], 1, &err[0], 256) } +func delTree(c unsafe.Pointer, prefix string) { + cp := cstr(prefix) + defer C.free(unsafe.Pointer(cp)) + var err [256]C.char + C.kvspaceDelTree(c, cp, &err[0], 256) +} + func mkindex(c unsafe.Pointer, path string) { cp := cstr(path) defer C.free(unsafe.Pointer(cp)) @@ -216,16 +222,15 @@ func parseTLV(data []byte) (kind string, raw []byte, arrLen int) { return kind, raw, arrLen } -// constructTLV:char/* 走 kvspaceNewChar,数值/布尔走 kvspaceTlvEncode(arrLen>1 → 一维 [arrLen])。 +// constructTLV:char/utf8 走 kvspaceNewChar(显式长度,NUL 安全), +// 其余(数值/布尔/objindex 等)走 kvspaceTlvEncode(arrLen>1 → 一维 [arrLen])。 func constructTLV(kind string, raw []byte, arrLen int) []byte { - if strings.HasPrefix(kind, "char/") { - ck := cstr(kind) - cv := C.CBytes(append(append([]byte{}, raw...), 0)) // NUL 结尾 - defer C.free(unsafe.Pointer(ck)) - defer C.free(cv) + if kind == "char/utf8" { + buf := C.CBytes(raw) + defer C.free(buf) var out *C.uint8_t var ol C.uint32_t - if C.kvspaceNewChar(ck, (*C.char)(cv), &out, &ol) != 0 || out == nil { + if C.kvspaceNewChar((*C.uint8_t)(buf), C.uint32_t(len(raw)), &out, &ol) != 0 || out == nil { return nil } defer C.kvspaceBytesFree(out, ol) @@ -519,6 +524,10 @@ func readArr(c unsafe.Pointer, path string) []interface{} { } func writeMap(c unsafe.Pointer, root string, m map[string]any) error { + // 覆盖语义:root 子树等于 src,写前清空旧子树(杜绝孤儿键与 obj→scalar 脏读)。 + if root != "" && root != "/" { + delTree(c, root) + } return writeObj(c, root, m) } diff --git a/runtime-rwirext_example/py/numpy/numpy.py b/runtime-rwirext_example/py/numpy/numpy.py index 324aad5f..36e9dafe 100644 --- a/runtime-rwirext_example/py/numpy/numpy.py +++ b/runtime-rwirext_example/py/numpy/numpy.py @@ -79,7 +79,7 @@ def _bind(): _ks.kvspaceList.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.POINTER(ctypes.c_uint8)), ctypes.POINTER(ctypes.c_uint32)] _ks.kvspaceList.restype = ctypes.c_int - _ks.kvspaceNewChar.argtypes = [ctypes.c_char_p, ctypes.c_char_p, + _ks.kvspaceNewChar.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_uint32, ctypes.POINTER(ctypes.POINTER(ctypes.c_uint8)), ctypes.POINTER(ctypes.c_uint32)] _ks.kvspaceNewChar.restype = ctypes.c_int _ks.kvspaceDel.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_char_p), ctypes.c_uint32, @@ -211,7 +211,8 @@ def kv_get(self, key): def kv_set(self, key, val): out = ctypes.POINTER(ctypes.c_uint8)(); ol = ctypes.c_uint32() - if _ks.kvspaceNewChar(b"char/utf8", val.encode(), ctypes.byref(out), ctypes.byref(ol)) != 0: + b = val.encode() + if _ks.kvspaceNewChar(b, len(b), ctypes.byref(out), ctypes.byref(ol)) != 0: return _ks.kvspaceShmSet(self.kv, key.encode(), out, ol.value) _ks.kvspaceBytesFree(out, ol.value) diff --git a/runtime-rwirext_example/rust/term/src/main.rs b/runtime-rwirext_example/rust/term/src/main.rs index 39d2f924..4cf7ea8b 100644 --- a/runtime-rwirext_example/rust/term/src/main.rs +++ b/runtime-rwirext_example/rust/term/src/main.rs @@ -58,7 +58,7 @@ unsafe extern "C" { err: *mut c_char, err_cap: u32, ) -> c_int; - fn kvspaceNewChar(kind: *const c_char, s: *const c_char, out: *mut *mut u8, out_len: *mut u32) -> c_int; + fn kvspaceNewChar(bytes: *const u8, len: u32, out: *mut *mut u8, out_len: *mut u32) -> c_int; fn kvspaceDecodeHead(data: *const u8, data_len: u32, out: *mut kvspaceHead_t) -> c_int; // rwirext ABI(kvspace 不提供的 runtime 语义;句柄传扩展自连的 kvspace) @@ -163,7 +163,8 @@ fn kv_get(kv: *mut c_void, key: &str) -> String { fn kv_set(kv: *mut c_void, key: &str, val: &str) { let mut out: *mut u8 = null_mut(); let mut out_len: u32 = 0; - if unsafe { kvspaceNewChar(cs("char/utf8").as_ptr(), cs(val).as_ptr(), &mut out, &mut out_len) } != 0 + let vb = cs(val); + if unsafe { kvspaceNewChar(vb.as_ptr() as *const u8, vb.as_bytes().len() as u32, &mut out, &mut out_len) } != 0 || out.is_null() { return; diff --git a/runtime/src/runtime_internal.h b/runtime/src/runtime_internal.h index a0d0ddd3..5d632139 100644 --- a/runtime/src/runtime_internal.h +++ b/runtime/src/runtime_internal.h @@ -42,8 +42,7 @@ extern int kvspaceTlvEncodePtr(const char *kind, const uint8_t *raw, uint32_t extern int kvspaceDecodeHead(const uint8_t *data, uint32_t data_len, kvspaceHead_t *out); extern int kvspaceNewPtr(const char *kind, const char *target, int32_t array_len, uint8_t **out, uint32_t *out_len); -extern int kvspaceNewChar(const char *kind, const char *s, uint8_t **out, uint32_t *out_len); -extern int kvspaceNewCharByte(const uint8_t *bytes, uint32_t len, uint8_t **out, uint32_t *out_len); +extern int kvspaceNewChar(const uint8_t *bytes, uint32_t len, uint8_t **out, uint32_t *out_len); extern int kvspaceNewBool(uint8_t v, uint8_t **out, uint32_t *out_len); extern int kvspaceNewInt64(int64_t v, uint8_t **out, uint32_t *out_len); extern int kvspaceNewFloat64(double v, uint8_t **out, uint32_t *out_len);