- SSOT using profiles (aliases/packages via nyash.toml), AST prelude merge - Parser/member guards; Builder pin/PHI and instance→function rewrite (dev on) - VM refactors (handlers split) and JSON roundtrip/nested stabilization - CURRENT_TASK.md updated with scope and acceptance criteria Notes: dev-only guards remain togglable via env; no default behavior changes for prod.
376 lines
16 KiB
Rust
376 lines
16 KiB
Rust
//! JsonNodeBox implementation
|
|
|
|
use crate::constants::*;
|
|
use crate::ffi::*;
|
|
use crate::provider::{provider_kind, NodeRep, ProviderKind, NEXT_ID, NODES};
|
|
use crate::tlv_helpers::*;
|
|
use serde_json::Value;
|
|
use std::ffi::{CStr, CString};
|
|
use std::os::raw::{c_char, c_void};
|
|
use std::sync::{atomic::Ordering, Arc};
|
|
|
|
pub extern "C" fn jsonnode_resolve(name: *const c_char) -> u32 {
|
|
if name.is_null() {
|
|
return 0;
|
|
}
|
|
let s = unsafe { CStr::from_ptr(name) }.to_string_lossy();
|
|
match s.as_ref() {
|
|
"birth" => JN_BIRTH,
|
|
"kind" => JN_KIND,
|
|
"get" => JN_GET,
|
|
"size" => JN_SIZE,
|
|
"at" => JN_AT,
|
|
"str" => JN_STR,
|
|
"int" => JN_INT,
|
|
"bool" => JN_BOOL,
|
|
_ => 0,
|
|
}
|
|
}
|
|
|
|
pub extern "C" fn jsonnode_invoke_id(
|
|
instance_id: u32,
|
|
method_id: u32,
|
|
args: *const u8,
|
|
args_len: usize,
|
|
result: *mut u8,
|
|
result_len: *mut usize,
|
|
) -> i32 {
|
|
unsafe {
|
|
let node_rep = match NODES.lock() {
|
|
Ok(m) => match m.get(&instance_id) {
|
|
Some(v) => v.clone(),
|
|
None => return E_HANDLE,
|
|
},
|
|
Err(_) => return E_PLUGIN,
|
|
};
|
|
|
|
match method_id {
|
|
JN_BIRTH => {
|
|
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
|
if let Ok(mut m) = NODES.lock() {
|
|
m.insert(id, NodeRep::Serde(Arc::new(Value::Null)));
|
|
} else {
|
|
return E_PLUGIN;
|
|
}
|
|
return write_u32(id, result, result_len);
|
|
}
|
|
JN_KIND => match provider_kind() {
|
|
ProviderKind::Serde => {
|
|
let k = match node_rep {
|
|
NodeRep::Serde(ref a) => match &**a {
|
|
Value::Null => "null",
|
|
Value::Bool(_) => "bool",
|
|
Value::Number(n) => {
|
|
if n.is_i64() {
|
|
"int"
|
|
} else {
|
|
"real"
|
|
}
|
|
}
|
|
Value::String(_) => "string",
|
|
Value::Array(_) => "array",
|
|
Value::Object(_) => "object",
|
|
},
|
|
_ => "null",
|
|
};
|
|
write_tlv_string(k, result, result_len)
|
|
}
|
|
ProviderKind::Yyjson => {
|
|
let v = if let NodeRep::Yy { ptr, .. } = node_rep {
|
|
ptr as *mut c_void
|
|
} else {
|
|
std::ptr::null_mut()
|
|
};
|
|
let k = if v.is_null() {
|
|
"null"
|
|
} else if nyjson_is_obj(v) != 0 {
|
|
"object"
|
|
} else if nyjson_is_arr(v) != 0 {
|
|
"array"
|
|
} else if nyjson_is_str(v) != 0 {
|
|
"string"
|
|
} else if nyjson_is_int(v) != 0 {
|
|
"int"
|
|
} else if nyjson_is_real(v) != 0 {
|
|
"real"
|
|
} else if nyjson_is_bool(v) != 0 {
|
|
"bool"
|
|
} else {
|
|
"null"
|
|
};
|
|
write_tlv_string(k, result, result_len)
|
|
}
|
|
},
|
|
JN_GET => {
|
|
let key = match read_arg_string(args, args_len, 0) {
|
|
Some(s) => s,
|
|
None => return E_ARGS,
|
|
};
|
|
match provider_kind() {
|
|
ProviderKind::Serde => {
|
|
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
|
if let NodeRep::Serde(ref a) = node_rep {
|
|
if let Value::Object(map) = &**a {
|
|
if let Some(child) = map.get(&key) {
|
|
if let Ok(mut mm) = NODES.lock() {
|
|
mm.insert(id, NodeRep::Serde(Arc::new(child.clone())));
|
|
}
|
|
return write_tlv_handle(T_JSON_NODE, id, result, result_len);
|
|
}
|
|
}
|
|
}
|
|
if let Ok(mut mm) = NODES.lock() {
|
|
mm.insert(id, NodeRep::Serde(Arc::new(Value::Null)));
|
|
}
|
|
write_tlv_handle(T_JSON_NODE, id, result, result_len)
|
|
}
|
|
ProviderKind::Yyjson => {
|
|
let v = if let NodeRep::Yy { ptr, .. } = node_rep {
|
|
ptr as *mut c_void
|
|
} else {
|
|
std::ptr::null_mut()
|
|
};
|
|
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
|
let mut out_ptr: *mut c_void = std::ptr::null_mut();
|
|
if !v.is_null() && nyjson_is_obj(v) != 0 {
|
|
let c = CString::new(key).unwrap_or_default();
|
|
out_ptr = nyjson_obj_get_key(v, c.as_ptr());
|
|
}
|
|
let doc_id = if let NodeRep::Yy { doc_id, .. } = node_rep {
|
|
doc_id
|
|
} else {
|
|
0
|
|
};
|
|
let rep = if out_ptr.is_null() {
|
|
NodeRep::Yy { doc_id, ptr: 0 }
|
|
} else {
|
|
NodeRep::Yy {
|
|
doc_id,
|
|
ptr: out_ptr as usize,
|
|
}
|
|
};
|
|
if let Ok(mut mm) = NODES.lock() {
|
|
mm.insert(id, rep);
|
|
}
|
|
write_tlv_handle(T_JSON_NODE, id, result, result_len)
|
|
}
|
|
}
|
|
}
|
|
JN_SIZE => match provider_kind() {
|
|
ProviderKind::Serde => {
|
|
let n = match node_rep {
|
|
NodeRep::Serde(ref a) => match &**a {
|
|
Value::Array(a) => a.len() as i64,
|
|
Value::Object(o) => o.len() as i64,
|
|
_ => 0,
|
|
},
|
|
_ => 0,
|
|
};
|
|
write_tlv_i64(n, result, result_len)
|
|
}
|
|
ProviderKind::Yyjson => {
|
|
let v = if let NodeRep::Yy { ptr, .. } = node_rep {
|
|
ptr as *mut c_void
|
|
} else {
|
|
std::ptr::null_mut()
|
|
};
|
|
let n = if !v.is_null() {
|
|
if nyjson_is_arr(v) != 0 {
|
|
nyjson_arr_size_val(v) as i64
|
|
} else if nyjson_is_obj(v) != 0 {
|
|
nyjson_obj_size_val(v) as i64
|
|
} else {
|
|
0
|
|
}
|
|
} else {
|
|
0
|
|
};
|
|
write_tlv_i64(n, result, result_len)
|
|
}
|
|
},
|
|
JN_AT => {
|
|
let idx = match read_arg_i64(args, args_len, 0) {
|
|
Some(v) => v,
|
|
None => return E_ARGS,
|
|
};
|
|
if idx < 0 {
|
|
return E_ARGS;
|
|
}
|
|
match provider_kind() {
|
|
ProviderKind::Serde => {
|
|
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
|
if let NodeRep::Serde(ref a) = node_rep {
|
|
if let Value::Array(arr) = &**a {
|
|
let i = idx as usize;
|
|
if i < arr.len() {
|
|
if let Ok(mut mm) = NODES.lock() {
|
|
mm.insert(id, NodeRep::Serde(Arc::new(arr[i].clone())));
|
|
}
|
|
return write_tlv_handle(T_JSON_NODE, id, result, result_len);
|
|
}
|
|
}
|
|
}
|
|
if let Ok(mut mm) = NODES.lock() {
|
|
mm.insert(id, NodeRep::Serde(Arc::new(Value::Null)));
|
|
}
|
|
write_tlv_handle(T_JSON_NODE, id, result, result_len)
|
|
}
|
|
ProviderKind::Yyjson => {
|
|
let v = if let NodeRep::Yy { ptr, .. } = node_rep {
|
|
ptr as *mut c_void
|
|
} else {
|
|
std::ptr::null_mut()
|
|
};
|
|
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
|
let mut child: *mut c_void = std::ptr::null_mut();
|
|
if !v.is_null() && nyjson_is_arr(v) != 0 {
|
|
child = nyjson_arr_get_val(v, idx as usize);
|
|
}
|
|
let doc_id = if let NodeRep::Yy { doc_id, .. } = node_rep {
|
|
doc_id
|
|
} else {
|
|
0
|
|
};
|
|
let rep = if child.is_null() {
|
|
NodeRep::Yy { doc_id, ptr: 0 }
|
|
} else {
|
|
NodeRep::Yy {
|
|
doc_id,
|
|
ptr: child as usize,
|
|
}
|
|
};
|
|
if let Ok(mut mm) = NODES.lock() {
|
|
mm.insert(id, rep);
|
|
}
|
|
write_tlv_handle(T_JSON_NODE, id, result, result_len)
|
|
}
|
|
}
|
|
}
|
|
JN_STR => match provider_kind() {
|
|
ProviderKind::Serde => {
|
|
if let NodeRep::Serde(ref a) = node_rep {
|
|
match &**a {
|
|
Value::String(s) => write_tlv_string(s, result, result_len),
|
|
Value::Object(o) => {
|
|
if let Some(Value::String(s)) = o.get("value") {
|
|
write_tlv_string(s, result, result_len)
|
|
} else {
|
|
write_tlv_string("", result, result_len)
|
|
}
|
|
}
|
|
_ => write_tlv_string("", result, result_len),
|
|
}
|
|
} else {
|
|
write_tlv_string("", result, result_len)
|
|
}
|
|
}
|
|
ProviderKind::Yyjson => {
|
|
let v = if let NodeRep::Yy { ptr, .. } = node_rep {
|
|
ptr as *mut c_void
|
|
} else {
|
|
std::ptr::null_mut()
|
|
};
|
|
if !v.is_null() && nyjson_is_str(v) != 0 {
|
|
let s = nyjson_get_str_val(v);
|
|
if s.is_null() {
|
|
write_tlv_string("", result, result_len)
|
|
} else {
|
|
let rs = CStr::from_ptr(s).to_string_lossy().to_string();
|
|
write_tlv_string(&rs, result, result_len)
|
|
}
|
|
} else if !v.is_null() && nyjson_is_obj(v) != 0 {
|
|
let key = CString::new("value").unwrap();
|
|
let child = nyjson_obj_get_key(v, key.as_ptr());
|
|
if !child.is_null() && nyjson_is_str(child) != 0 {
|
|
let s = nyjson_get_str_val(child);
|
|
if s.is_null() {
|
|
write_tlv_string("", result, result_len)
|
|
} else {
|
|
let rs = CStr::from_ptr(s).to_string_lossy().to_string();
|
|
write_tlv_string(&rs, result, result_len)
|
|
}
|
|
} else {
|
|
write_tlv_string("", result, result_len)
|
|
}
|
|
} else {
|
|
write_tlv_string("", result, result_len)
|
|
}
|
|
}
|
|
},
|
|
JN_INT => match provider_kind() {
|
|
ProviderKind::Serde => {
|
|
if let NodeRep::Serde(ref a) = node_rep {
|
|
match &**a {
|
|
Value::Number(n) => {
|
|
write_tlv_i64(n.as_i64().unwrap_or(0), result, result_len)
|
|
}
|
|
Value::Object(o) => {
|
|
if let Some(Value::Number(n)) = o.get("value") {
|
|
write_tlv_i64(n.as_i64().unwrap_or(0), result, result_len)
|
|
} else {
|
|
write_tlv_i64(0, result, result_len)
|
|
}
|
|
}
|
|
_ => write_tlv_i64(0, result, result_len),
|
|
}
|
|
} else {
|
|
write_tlv_i64(0, result, result_len)
|
|
}
|
|
}
|
|
ProviderKind::Yyjson => {
|
|
let v = if let NodeRep::Yy { ptr, .. } = node_rep {
|
|
ptr as *mut c_void
|
|
} else {
|
|
std::ptr::null_mut()
|
|
};
|
|
if !v.is_null() && nyjson_is_int(v) != 0 {
|
|
write_tlv_i64(nyjson_get_sint_val(v) as i64, result, result_len)
|
|
} else if !v.is_null() && nyjson_is_obj(v) != 0 {
|
|
let key = CString::new("value").unwrap();
|
|
let child = nyjson_obj_get_key(v, key.as_ptr());
|
|
if !child.is_null() && nyjson_is_int(child) != 0 {
|
|
write_tlv_i64(nyjson_get_sint_val(child) as i64, result, result_len)
|
|
} else {
|
|
write_tlv_i64(0, result, result_len)
|
|
}
|
|
} else {
|
|
write_tlv_i64(0, result, result_len)
|
|
}
|
|
}
|
|
},
|
|
JN_BOOL => match provider_kind() {
|
|
ProviderKind::Serde => {
|
|
if let NodeRep::Serde(ref a) = node_rep {
|
|
if let Value::Bool(b) = **a {
|
|
write_tlv_bool(b, result, result_len)
|
|
} else {
|
|
write_tlv_bool(false, result, result_len)
|
|
}
|
|
} else {
|
|
write_tlv_bool(false, result, result_len)
|
|
}
|
|
}
|
|
ProviderKind::Yyjson => {
|
|
let v = if let NodeRep::Yy { ptr, .. } = node_rep {
|
|
ptr as *mut c_void
|
|
} else {
|
|
std::ptr::null_mut()
|
|
};
|
|
if !v.is_null() && nyjson_is_bool(v) != 0 {
|
|
write_tlv_bool(nyjson_get_bool_val(v) != 0, result, result_len)
|
|
} else {
|
|
write_tlv_bool(false, result, result_len)
|
|
}
|
|
}
|
|
},
|
|
JN_FINI => {
|
|
if let Ok(mut m) = NODES.lock() {
|
|
m.remove(&instance_id);
|
|
}
|
|
return write_tlv_void(result, result_len);
|
|
}
|
|
_ => E_METHOD,
|
|
}
|
|
}
|
|
}
|