use shape_value::heap_value::HeapValue;
#[derive(Debug, Clone, PartialEq)]
pub enum JsonValue {
Null,
Bool(bool),
Int(i64),
Number(f64),
String(String),
Bytes(Vec<u8>),
Array(Vec<JsonValue>),
Object(Vec<(String, JsonValue)>),
}
impl JsonValue {
pub fn type_name(&self) -> &'static str {
match self {
JsonValue::Null => "null",
JsonValue::Bool(_) => "bool",
JsonValue::Int(_) => "int",
JsonValue::Number(_) => "number",
JsonValue::String(_) => "string",
JsonValue::Bytes(_) => "bytes",
JsonValue::Array(_) => "array",
JsonValue::Object(_) => "object",
}
}
}
pub fn heap_to_json_value(hv: &HeapValue) -> Result<JsonValue, String> {
match hv {
HeapValue::String(s) => Ok(JsonValue::String((**s).clone())),
HeapValue::BigInt(n) => Ok(JsonValue::Int(**n)),
HeapValue::Char(c) => Ok(JsonValue::String(c.to_string())),
HeapValue::HashMap(kref) => {
use shape_value::heap_value::HashMapKindedRef;
let n = kref.len();
let mut out: Vec<(String, JsonValue)> = Vec::with_capacity(n);
let keys_ptr = match kref {
HashMapKindedRef::I64(arc) => arc.keys,
HashMapKindedRef::F64(arc) => arc.keys,
HashMapKindedRef::Bool(arc) => arc.keys,
HashMapKindedRef::Char(arc) => arc.keys,
HashMapKindedRef::String(arc) => arc.keys,
HashMapKindedRef::Decimal(arc) => arc.keys,
HashMapKindedRef::TypedObject(arc) => arc.keys,
HashMapKindedRef::TraitObject(arc) => arc.keys,
HashMapKindedRef::HashMap(arc) => arc.keys,
};
for i in 0..n {
let key: String = unsafe {
let ptr = shape_value::v2::typed_array::TypedArray::get_unchecked(
keys_ptr, i as u32,
);
shape_value::v2::string_obj::StringObj::as_str(ptr).to_owned()
};
let value: JsonValue = match kref {
HashMapKindedRef::I64(arc) => {
let v: i64 = unsafe { *(*arc.values).data.add(i) };
JsonValue::Int(v)
}
HashMapKindedRef::F64(arc) => {
let v: f64 = unsafe { *(*arc.values).data.add(i) };
JsonValue::Number(v)
}
HashMapKindedRef::Bool(arc) => {
let v: u8 = unsafe { *(*arc.values).data.add(i) };
JsonValue::Bool(v != 0)
}
HashMapKindedRef::Char(arc) => {
let v: char = unsafe { *(*arc.values).data.add(i) };
JsonValue::String(v.to_string())
}
HashMapKindedRef::String(arc) => {
let ptr: *const shape_value::v2::string_obj::StringObj =
unsafe { *(*arc.values).data.add(i) };
JsonValue::String(unsafe {
shape_value::v2::string_obj::StringObj::as_str(ptr).to_owned()
})
}
HashMapKindedRef::Decimal(_) => {
return Err("HeapValue::HashMap<string, decimal> → JsonValue: \
decimal serialization policy not yet decided (precision \
preservation vs lossy f64 cast). Surface-and-stop per \
playbook §6."
.to_string());
}
HashMapKindedRef::TypedObject(_) => {
return Err("HeapValue::HashMap<string, TypedObject> → JsonValue: \
nested TypedObject serialization requires the schema \
walker which is its own cluster. Surface-and-stop."
.to_string());
}
HashMapKindedRef::TraitObject(_) => {
return Err("HeapValue::HashMap<string, TraitObject> → JsonValue: \
no canonical JSON shape for TraitObject. Surface-and-stop."
.to_string());
}
HashMapKindedRef::HashMap(arc) => {
let inner_ref: &HashMapKindedRef =
unsafe { &*(*arc.values).data.add(i) };
let inner_hv = HeapValue::HashMap(inner_ref.clone());
heap_to_json_value(&inner_hv)?
}
};
out.push((key, value));
}
Ok(JsonValue::Object(out))
}
HeapValue::HashSet(d) => Ok(JsonValue::Array(
d.keys
.iter()
.map(|k| JsonValue::String((**k).clone()))
.collect(),
)),
HeapValue::Deque(d) => {
let mut elems: Vec<JsonValue> = Vec::with_capacity(d.items.len());
for v in d.items.iter() {
elems.push(heap_to_json_value(v)?);
}
Ok(JsonValue::Array(elems))
}
HeapValue::TypedObject(storage) => typed_object_to_json_value(
storage.schema_id,
&storage.slots,
storage.heap_mask,
),
HeapValue::Future(_) => Err("cannot serialize: Future".into()),
HeapValue::IoHandle(_) => Err("cannot serialize: IoHandle".into()),
HeapValue::NativeView(_) => Err("cannot serialize: NativeView (C view)".into()),
HeapValue::ClosureRaw(_) => Err("cannot serialize: closure".into()),
HeapValue::TaskGroup(_) => Err("cannot serialize: TaskGroup".into()),
HeapValue::Decimal(_) => {
Err("Decimal serialization policy not yet decided (N7 architectural-choice deferral)".into())
}
HeapValue::DataTable(_) => Err(
"DataTable serialization policy not yet decided (N7 architectural-choice deferral)"
.into(),
),
HeapValue::Content(_) => {
Err("Content serialization policy not yet decided (N7 architectural-choice deferral)".into())
}
HeapValue::Temporal(_) => {
Err("Temporal serialization policy not yet decided (N7 architectural-choice deferral)".into())
}
HeapValue::TableView(_) => {
Err("TableView serialization policy not yet decided (N7 architectural-choice deferral)".into())
}
HeapValue::Instant(_) => Err(
"Instant serialization policy not yet decided (N7 architectural-choice deferral; Instant is monotonic, not absolute — ISO-8601 inapplicable without epoch convention)"
.into(),
),
HeapValue::NativeScalar(_) => Err(
"NativeScalar serialization policy not yet decided (N7 architectural-choice deferral; Ptr inner kind is hostile to JSON)"
.into(),
),
HeapValue::FilterExpr(_) => Err("cannot serialize: FilterExpr".into()),
HeapValue::Reference(_) => Err("cannot serialize: Reference".into()),
HeapValue::Iterator(_) => Err("cannot serialize: Iterator".into()),
HeapValue::Channel(_) => Err("cannot serialize: Channel".into()),
HeapValue::PriorityQueue(d) => Ok(JsonValue::Array(
d.heap
.iter()
.map(|v| JsonValue::Int(*v))
.collect(),
)),
HeapValue::Range(r) => Ok(JsonValue::Array(
r.to_vec_i64()
.into_iter()
.map(JsonValue::Int)
.collect(),
)),
HeapValue::Result(_) => Err("cannot serialize: Result".into()),
HeapValue::Option(_) => Err("cannot serialize: Option".into()),
HeapValue::Mutex(_) => Err("cannot serialize: Mutex".into()),
HeapValue::Atomic(_) => Err("cannot serialize: Atomic".into()),
HeapValue::Lazy(_) => Err("cannot serialize: Lazy".into()),
HeapValue::TraitObject(_) => Err("cannot serialize: TraitObject".into()),
HeapValue::ModuleFn(_) => Err("cannot serialize: ModuleFn".into()),
HeapValue::Matrix(_) => Err(
"Matrix serialization policy not yet decided (N7 architectural-choice deferral; multiple natural encodings: nested array-of-arrays vs flat row-major vs {rows, cols, data})"
.into(),
),
HeapValue::MatrixSlice(_) => Err(
"MatrixSlice serialization policy not yet decided (N7 architectural-choice deferral; structurally inherits Matrix's encoding question)"
.into(),
),
}
}
fn typed_object_to_json_value(
schema_id: u64,
slots: &[shape_value::ValueSlot],
heap_mask: u64,
) -> Result<JsonValue, String> {
use crate::type_schema::{lookup_schema_by_id_public, FieldType};
let schema = lookup_schema_by_id_public(schema_id as u32).ok_or_else(|| {
format!(
"heap_to_json_value: unknown TypedObject schema id {}",
schema_id
)
})?;
let mut pairs: Vec<(String, JsonValue)> = Vec::with_capacity(schema.fields.len());
for field in &schema.fields {
let idx = field.index as usize;
if idx >= slots.len() {
return Err(format!(
"heap_to_json_value: TypedObject field '{}' index {} out of bounds (slots.len()={})",
field.name,
idx,
slots.len()
));
}
let slot = &slots[idx];
let is_heap = (heap_mask & (1u64 << field.index)) != 0;
let child = match (&field.field_type, is_heap) {
(FieldType::I64, false)
| (FieldType::I8, false)
| (FieldType::U8, false)
| (FieldType::I16, false)
| (FieldType::U16, false)
| (FieldType::I32, false)
| (FieldType::U32, false)
| (FieldType::U64, false) => JsonValue::Int(slot.as_i64()),
(FieldType::F64, false) => JsonValue::Number(slot.as_f64()),
(FieldType::Bool, false) => JsonValue::Bool(slot.as_bool()),
(FieldType::Timestamp, false) => {
return Err(format!(
"Timestamp serialization policy not yet decided (N7 architectural-choice deferral; field '{}')",
field.name
));
}
(FieldType::Decimal, _) => {
return Err(format!(
"Decimal serialization policy not yet decided (N7 architectural-choice deferral; field '{}')",
field.name
));
}
(_, true) => heap_to_json_value(slot.as_heap_value())?,
(other, false) => {
return Err(format!(
"heap_to_json_value: TypedObject field '{}' has field_type {} but heap_mask bit clear (corrupt mask?)",
field.name, other
));
}
};
pairs.push((field.wire_name().to_string(), child));
}
Ok(JsonValue::Object(pairs))
}
pub fn json_value_to_serde_json(jv: &JsonValue) -> serde_json::Value {
match jv {
JsonValue::Null => serde_json::Value::Null,
JsonValue::Bool(b) => serde_json::Value::Bool(*b),
JsonValue::Int(i) => serde_json::Value::Number((*i).into()),
JsonValue::Number(f) => serde_json::Number::from_f64(*f)
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null),
JsonValue::String(s) => serde_json::Value::String(s.clone()),
JsonValue::Bytes(bytes) => serde_json::Value::Array(
bytes
.iter()
.map(|&b| serde_json::Value::Number(b.into()))
.collect(),
),
JsonValue::Array(arr) => {
serde_json::Value::Array(arr.iter().map(json_value_to_serde_json).collect())
}
JsonValue::Object(pairs) => {
let mut map = serde_json::Map::with_capacity(pairs.len());
for (k, v) in pairs.iter() {
map.insert(k.clone(), json_value_to_serde_json(v));
}
serde_json::Value::Object(map)
}
}
}
pub fn json_value_to_serde_yaml(jv: &JsonValue) -> serde_yaml::Value {
match jv {
JsonValue::Null => serde_yaml::Value::Null,
JsonValue::Bool(b) => serde_yaml::Value::Bool(*b),
JsonValue::Int(i) => serde_yaml::Value::Number((*i).into()),
JsonValue::Number(f) => serde_yaml::Value::Number((*f).into()),
JsonValue::String(s) => serde_yaml::Value::String(s.clone()),
JsonValue::Bytes(bytes) => serde_yaml::Value::Sequence(
bytes
.iter()
.map(|&b| serde_yaml::Value::Number((b as u64).into()))
.collect(),
),
JsonValue::Array(arr) => {
serde_yaml::Value::Sequence(arr.iter().map(json_value_to_serde_yaml).collect())
}
JsonValue::Object(pairs) => {
let mut map = serde_yaml::Mapping::with_capacity(pairs.len());
for (k, v) in pairs.iter() {
map.insert(
serde_yaml::Value::String(k.clone()),
json_value_to_serde_yaml(v),
);
}
serde_yaml::Value::Mapping(map)
}
}
}
pub fn json_value_to_toml_value(jv: &JsonValue) -> toml::Value {
match jv {
JsonValue::Null => toml::Value::String("null".to_string()),
JsonValue::Bool(b) => toml::Value::Boolean(*b),
JsonValue::Int(i) => toml::Value::Integer(*i),
JsonValue::Number(f) => toml::Value::Float(*f),
JsonValue::String(s) => toml::Value::String(s.clone()),
JsonValue::Bytes(bytes) => toml::Value::Array(
bytes
.iter()
.map(|&b| toml::Value::Integer(b as i64))
.collect(),
),
JsonValue::Array(arr) => {
toml::Value::Array(arr.iter().map(json_value_to_toml_value).collect())
}
JsonValue::Object(pairs) => {
let mut map = toml::map::Map::new();
for (k, v) in pairs.iter() {
map.insert(k.clone(), json_value_to_toml_value(v));
}
toml::Value::Table(map)
}
}
}
pub fn json_value_to_msgpack_bytes(jv: &JsonValue) -> Result<Vec<u8>, String> {
let serde_json_v = json_value_to_serde_json(jv);
rmp_serde::to_vec(&serde_json_v).map_err(|e| format!("msgpack encode failed: {}", e))
}