jsonenc.um
type Encoder
type Encoder* = struct {
// Contains private fields
fn mk
Creates an encoder.
fn mk*(pretty: bool = true): Encoder {
fn Encoder.startObject
fn (this: ^Encoder) startObject*() {
fn Encoder.endObject
fn (this: ^Encoder) endObject*() {
fn Encoder.startArray
fn (this: ^Encoder) startArray*() {
fn Encoder.endArray
fn (this: ^Encoder) endArray*() {
fn Encoder.putKey
fn (this: ^Encoder) putKey*(key: str) {
fn Encoder.putVal
fn (this: ^Encoder) putVal*(a: any) {
fn Encoder.toStr
fn (this: ^Encoder) toStr*(): str {
type State = int
const (
object = State(0)
array = State(1)
)
//~~type Encoder
type Encoder* = struct {
// Contains private fields
//~~
buffer: str
pretty: bool
nestLevel: int
putComma: bool
state: []State
}
//~~fn mk
// Creates an encoder.
fn mk*(pretty: bool = true): Encoder {
//~~
return {
buffer: "",
pretty: pretty,
state: { object } }
}
fn (this: ^Encoder) write(s: str) {
this.buffer += s
}
fn (this: ^Encoder) writec(c: char) {
this.buffer += str(c)
}
fn (this: ^Encoder) newLine() {
if this.putComma {
this.writec(',')
this.putComma = false
}
if !this.pretty {
return
}
this.writec('\n')
for i:=0; i < this.nestLevel; i++ {
this.writec('\t')
}
}
fn (this: ^Encoder) getState(): State {
return this.state[len(this.state) - 1]
}
//~~fn Encoder.startObject
fn (this: ^Encoder) startObject*() {
//~~
if this.getState() == array {
this.newLine()
}
this.writec('{')
this.putComma = false
this.nestLevel++
this.state = append(this.state, object)
}
//~~fn Encoder.endObject
fn (this: ^Encoder) endObject*() {
//~~
this.nestLevel--
if this.pretty {
this.putComma = false
this.newLine()
}
this.writec('}')
this.putComma = true
if this.nestLevel < 0 {
exit(1, "Incorrect nesting")
}
this.state = slice(this.state, 0, len(this.state) - 1)
}
//~~fn Encoder.startArray
fn (this: ^Encoder) startArray*() {
//~~
if this.getState() == array {
this.newLine()
}
this.writec('[')
this.putComma = false
this.nestLevel++
this.state = append(this.state, array)
}
//~~fn Encoder.endArray
fn (this: ^Encoder) endArray*() {
//~~
this.nestLevel--
if this.pretty {
this.putComma = false
this.newLine()
}
this.writec(']')
this.putComma = true
if this.nestLevel < 0 {
exit(1, "Incorrect nesting")
}
this.state = slice(this.state, 0, len(this.state) - 1)
}
//~~fn Encoder.putKey
fn (this: ^Encoder) putKey*(key: str) {
//~~
this.newLine()
this.write(sprintf("\"%s\": ", key))
}
//~~fn Encoder.putVal
fn (this: ^Encoder) putVal*(a: any) {
//~~
if this.getState() == array {
this.newLine()
}
if ^map[str]any(a) != null {
this.startObject()
for k,v in map[str]any(a) {
this.putKey(k)
this.putVal(v)
}
this.endObject()
return
}
if ^[]any(a) != null {
this.startArray()
for v in []any(a) {
this.putVal(v)
}
this.endArray()
return
}
this.write(sprintf("%v", a))
this.putComma = true
}
//~~fn Encoder.toStr
fn (this: ^Encoder) toStr*(): str {
//~~
return this.buffer
}
fn main() {
enc := mk()
enc.startObject()
enc.putKey("x")
enc.putVal(12.0)
enc.putKey("y")
enc.putVal(20.1)
enc.putKey("numbers")
enc.startArray()
enc.putVal(1)
enc.putVal(false)
enc.putVal("hello I'm a string")
enc.putVal(map[str]any{
"a": 123,
"b": []any{ 1, 2, 3 }
})
enc.endArray()
enc.endObject()
printf("%s\n", enc.toStr())
}