/*
* 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.
*/
package stdx.encoding.json.stream
import std.collection.*
import std.collection.concurrent.ConcurrentHashMap
import std.convert.Parsable
@FastNative
foreign func CJ_JSON_FloatPrint(num: Float64, dest: CPointer<UInt8>, destSize: Int64): Int64
@FastNative
foreign func strlen(str: CPointer<UInt8>): UIntNative
@FastNative
foreign func memcpy_s(dest: CPointer<UInt8>, destMax: UIntNative, src: CPointer<UInt8>, count: UIntNative): Int32
public interface JsonSerializable {
func toJson(w: JsonWriter): Unit
}
func isInvalidJsonFloat(buffer: Array<UInt8>, start: Int64, length: Int64): Bool {
let value = Float64.parse(String.fromUtf8(buffer[start..start+length]))
return value.isNaN() || value.isInf()
}
extend Int64 <: JsonSerializable {
@OverflowWrapping
public func toJson(w: JsonWriter): Unit {
w.beforeValue()
if (this < 0) {
w.buffer[w.curPos] = b'-'
w.curPos++
w.curPos += uitoa(UInt64(-this), w.buffer[w.curPos..])
} else {
w.curPos += uitoa(UInt64(this), w.buffer[w.curPos..])
}
}
}
extend Int32 <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
Int64(this).toJson(w)
}
}
extend Int16 <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
Int64(this).toJson(w)
}
}
extend Int8 <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
Int64(this).toJson(w)
}
}
extend IntNative <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
Int64(this).toJson(w)
}
}
extend UInt64 <: JsonSerializable {
@OverflowWrapping
public func toJson(w: JsonWriter): Unit {
w.beforeValue()
w.curPos += uitoa(this, w.buffer[w.curPos..])
}
}
extend UInt32 <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
UInt64(this).toJson(w)
}
}
extend UInt16 <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
UInt64(this).toJson(w)
}
}
extend UInt8 <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
UInt64(this).toJson(w)
}
}
extend UIntNative <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
UInt64(this).toJson(w)
}
}
extend Float64 <: JsonSerializable {
@OverflowWrapping
public func toJson(w: JsonWriter): Unit {
w.beforeValue()
unsafe {
let dest = acquireArrayRawData(w.buffer)
let printedLen = CJ_JSON_FloatPrint(this, dest.pointer + w.curPos, w.buffer.size - w.curPos)
releaseArrayRawData(dest)
if (printedLen <= 0 || isInvalidJsonFloat(w.buffer, w.curPos, printedLen)) {
throw IllegalStateException("Failed to serialize JSON float.")
}
w.curPos += printedLen
}
// the result of CJ_JSON_FloatPrint have at least 6 decimal points
// there is no out-of-bounds risk
while (w.buffer[w.curPos - 1] == b'0') {
w.curPos--
}
if (w.buffer[w.curPos - 1] == b'.') {
w.curPos--
}
}
}
extend Float32 <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
Float64(this).toJson(w)
}
}
extend Float16 <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
Float64(this).toJson(w)
}
}
extend Bool <: JsonSerializable {
@OverflowWrapping
public func toJson(w: JsonWriter): Unit {
w.beforeValue()
if (this) {
w.buffer[w.curPos] = b't'
w.buffer[w.curPos + 1] = b'r'
w.buffer[w.curPos + 2] = b'u'
w.buffer[w.curPos + 3] = b'e'
w.curPos += 4
} else {
w.buffer[w.curPos] = b'f'
w.buffer[w.curPos + 1] = b'a'
w.buffer[w.curPos + 2] = b'l'
w.buffer[w.curPos + 3] = b's'
w.buffer[w.curPos + 4] = b'e'
w.curPos += 5
}
}
}
extend<T> Array<T> <: JsonSerializable where T <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
writeJsonArray<T>(w, this)
}
}
func writeJsonArray<T>(w: JsonWriter, items: Iterable<T>): Unit where T <: JsonSerializable {
w.startArray()
for (item in items) {
w.writeValue<T>(item)
}
w.endArray()
}
extend<T> ArrayList<T> <: JsonSerializable where T <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
writeJsonArray<T>(w, this)
}
}
extend<V> HashMap<String, V> <: JsonSerializable where V <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
w.startObject()
for ((k, v) in this) {
w.writeName(k).writeValue(v)
}
w.endObject()
}
}
extend<T> Option<T> <: JsonSerializable where T <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
if (let Some(v) <- this) {
w.writeValue<T>(v)
} else {
w.writeNullValue()
}
}
}
extend<T> HashSet<T> <: JsonSerializable where T <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
writeJsonArray<T>(w, this)
}
}
extend<T> LinkedList<T> <: JsonSerializable where T <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
writeJsonArray<T>(w, this)
}
}
extend<T> ArrayQueue<T> <: JsonSerializable where T <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
writeJsonArray<T>(w, this)
}
}
extend<T> ArrayDeque<T> <: JsonSerializable where T <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
writeJsonArray<T>(w, this)
}
}
extend<T> ArrayStack<T> <: JsonSerializable where T <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
w.startArray()
let list = this.toArray()
list.reverse()
for (item in list) {
w.writeValue<T>(item)
}
w.endArray()
}
}
extend<T> TreeSet<T> <: JsonSerializable where T <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
w.startArray()
for (item in this) {
w.writeValue<T>(item)
}
w.endArray()
}
}
extend<V> TreeMap<String, V> <: JsonSerializable where V <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
w.startObject()
for ((k, v) in this) {
w.writeName(k).writeValue(v)
}
w.endObject()
}
}
extend<V> ConcurrentHashMap<String, V> <: JsonSerializable where V <: JsonSerializable {
public func toJson(w: JsonWriter): Unit {
w.startObject()
for ((k, v) in this) {
w.writeName(k).writeValue(v)
}
w.endObject()
}
}