///|
/// A JS block keeps the fragment array bounded instead of copying all fragments
/// into a second large FixedArray at the end. FFI only joins text, never analyzes.
#cfg(target="js")
priv struct JsonText {
blocks : Array[String]
fragments : FixedArray[String]
mut used : Int
}
///|
#cfg(target="js")
fn json_text() -> JsonText {
{ blocks: [], fragments: FixedArray::make(1024, ""), used: 0, }
}
///|
#cfg(target="js")
fn JsonText::write_string(self : JsonText, value : String) -> Unit {
if self.used == self.fragments.length() {
self.blocks.push(join_json_chunks(self.fragments))
self.used = 0
}
self.fragments[self.used] = value
self.used += 1
}
///|
#cfg(target="js")
fn JsonText::write_char(self : JsonText, value : Char) -> Unit {
self.write_string(value.to_string())
}
///|
#cfg(target="js")
fn JsonText::to_string(self : JsonText) -> String {
let tail = join_json_chunks(
FixedArray::makei(self.used, i => self.fragments[i]),
)
if self.blocks.is_empty() {
return tail
}
join_json_chunks(
FixedArray::makei(self.blocks.length() + 1, i => {
if i == self.blocks.length() {
tail
} else {
self.blocks[i]
}
}),
)
}
///|
/// Preserve the existing encoding path on other targets.
#cfg(not(target="js"))
priv struct JsonText {
chunks : Array[String]
}
///|
#cfg(not(target="js"))
fn json_text() -> JsonText {
{ chunks: [], }
}
///|
#cfg(not(target="js"))
fn JsonText::write_string(self : JsonText, value : String) -> Unit {
self.chunks.push(value)
}
///|
#cfg(not(target="js"))
fn JsonText::write_char(self : JsonText, value : Char) -> Unit {
self.chunks.push(value.to_string())
}
///|
#cfg(not(target="js"))
fn JsonText::to_string(self : JsonText) -> String {
join_json_chunks(FixedArray::makei(self.chunks.length(), i => self.chunks[i]))
}
///|
#cfg(target="js")
extern "js" fn join_json_chunks(parts : FixedArray[String]) -> String =
#| (parts) => parts.join("")
///|
#cfg(not(target="js"))
fn join_json_chunks(parts : FixedArray[String]) -> String {
let b = StringBuilder()
for part in parts {
b.write_string(part)
}
b.to_string()
}