/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* This source file is part of the Cangjie project, licensed under Apache-2.0
* with Runtime Library Exception.
*
* See https://cangjie-lang.cn/pages/LICENSE for license information.
*/
/**
* @file
*
* This is a library for ToJson interface.
*/
package stdx.encoding.json
import std.collection.*
import stdx.serialization.serialization.*
/**
* This interface used for conversions JsonValue.
*/
public interface ToJson {
/**
* Convert DataModel to JsonValue.
*
* @return json-converted JsonValue.
*
* @since 0.20.2
*
* @throws JsonException if DataModel cannot be converted to JsonValue.
*/
func toJson(): JsonValue
/**
* Parses JsonValue data into DataModel.
*
* @param jv JsonValue in JSON data format.
* @return parsed DataModel.
*
* @since 0.20.2
*
* @throws JsonException if jv cannot be converted to DataModel.
*/
static func fromJson(jv: JsonValue): DataModel
}
/**
* Extended DataModel to add func toJson() and func fromJson().
*/
extend DataModel <: ToJson {
/**
* Parses JsonValue data into DataModel.
*
* @param jv JsonValue in JSON data format.
* @return parsed DataModel.
*
* @since 0.17.4
*
* @throws JsonException if jv cannot be converted to DataModel.
*/
public static func fromJson(jv: JsonValue): DataModel {
match (jv) {
case jb: JsonBool => DataModelBool(jb.getValue())
case ji: JsonInt => DataModelInt(ji.getValue())
case jf: JsonFloat => DataModelFloat(jf.getValue())
case js: JsonString => DataModelString(js.getValue())
case ja: JsonArray => buildDMSeq(ja)
case jo: JsonObject => buildDMStruct(jo)
case _ => DataModelNull()
}
}
/**
* Parses JsonArray data into DataModelSeq.
*
* @throws JsonException if any item of ja cannot be converted to DataModel.
*/
private static func buildDMSeq(ja: JsonArray): DataModelSeq {
let dms: DataModelSeq = DataModelSeq()
let list: ArrayList<DataModel> = dms.getItems()
let ji = ja.getItems()
list.reserve(ji.size)
for (i in 0..ji.size) {
list.add(fromJson(ji[i]))
}
return dms
}
/**
* Parses JsonObject data into DataModelStruct.
*
* @throws JsonException if any value in jo cannot be converted to DataModel.
*/
private static func buildDMStruct(jo: JsonObject): DataModelStruct {
let dms: DataModelStruct = DataModelStruct()
let list: ArrayList<Field> = dms.getFields()
let map: HashMap<String, JsonValue> = jo.getFields()
list.reserve(map.size)
for ((str, jv) in map) {
let dm = match (jv) {
case jb: JsonBool => DataModelBool(jb.getValue())
case ji: JsonInt => DataModelInt(ji.getValue())
case jf: JsonFloat => DataModelFloat(jf.getValue())
case js: JsonString => DataModelString(js.getValue())
case _: JsonNull => DataModelNull()
case ja: JsonArray => buildDMSeq(ja)
case jo: JsonObject => buildDMStruct(jo)
case _ => throw JsonException("Unmatched JsonValue type!")
}
list.add(Field(str, dm))
}
return dms
}
/**
* Convert DataModel to JsonValue.
*
* @return json-converted JsonValue.
*
* @since 0.20.2
*
* @throws JsonException if DataModel cannot be converted to JsonValue.
*/
public func toJson(): JsonValue {
match (this) {
case _: DataModelNull => return JsonNull()
case dmb: DataModelBool => return JsonBool(dmb.getValue())
case dmi: DataModelInt => return JsonInt(dmi.getValue())
case dmf: DataModelFloat => return JsonFloat(dmf.getValue())
case dmstr: DataModelString => return JsonString(dmstr.getValue())
case dmseq: DataModelSeq => return toJson(dmseq)
case dms: DataModelStruct => return toJson(dms)
case _ => throw JsonException("Unmatched DataModel type!")
}
}
/**
* Convert DataModelSeq to JsonArray.
*
* @throws JsonException if DataModel cannot be converted to JsonValue.
*/
private func toJson(dmseq: DataModelSeq): JsonArray {
let ji = dmseq.getItems()
let jv: JsonArray = JsonArray(ji.size)
for (i in 0..ji.size) {
jv.add(ji[i].toJson())
}
return jv
}
/**
* Convert DataModelStruct to JsonObject.
*
* @throws JsonException if DataModel cannot be converted to JsonValue.
*/
private func toJson(dms: DataModelStruct): JsonObject {
let ji = dms.getFields()
let jo: JsonObject = JsonObject(ji.size)
for (i in 0..ji.size) {
let fie = ji[i]
let value: JsonValue = fie.getData().toJson()
jo.put(fie.getName(), value)
}
return jo
}
}