
Json.pudu
Pudu90 lines3.3 KB
1/** @Log.Domain.Json.Module — captured values written as JSON text */2module PuduLangLog.Domain.Json34import Std.Decimal as Decimal5import Std.Option as Option6import PuduLangLog.Domain.Dates as Dates7import PuduLangLog.Domain.Numbers as Numbers8import PuduLangLog as Log91011const HEX: Str = "0123456789ABCDEF"121314export fn quote(text: Str) -> Str {15 var pieces: Array[Str] = ["\""]16 for character in text.chars() {17 let code = character.code()18 if character == '"' {19 pieces = pieces.push("\\\"")20 } else if character == '\\' {21 pieces = pieces.push("\\\\")22 } else if character == '\n' {23 pieces = pieces.push("\\n")24 } else if character == '\r' {25 pieces = pieces.push("\\r")26 } else if character == '\t' {27 pieces = pieces.push("\\t")28 } else if code == 12 {29 pieces = pieces.push("\\f")30 } else if code < 32 {31 pieces = pieces.push("\\u00" + HEX.slice(code / 16, code / 16 + 1) + HEX.slice(code % 16, code % 16 + 1))32 } else {33 pieces = pieces.push(character.toText())34 }35 }36 pieces.push("\"").join("")37}383940export fn scalar(atom: &Log.Scalar) -> Str {41 match atom {42 case Log.Null => "null"43 case Log.Boolean(flag) => if flag { "true" } else { "false" }44 case Log.Integer(number) => show(number)45 case Log.Real(number) => if Numbers.digitsOfReal(number) == None { quote(show(number)) } else { Numbers.realText(number) }46 case Log.Exact(number) => Decimal.toText(number)47 case Log.Text(text) => quote(text)48 case Log.Moment(moment) => quote(Dates.roundTrip(&moment))49 case Log.Span(millis) => quote(Dates.formatSpan(millis, &None))50 case Log.Binary(bytes) => quote(hexOf(&bytes))51 }52}53545556export fn value(held: &Log.Value, typeTag: &Option[Str]) -> Str {57 match held {58 case Log.Scalar(atom) => scalar(&atom)59 case Log.Sequence(items) => "[" + items.map(|item: Log.Value| value(&item, typeTag)).join(",") + "]"60 case Log.Structure(shape) => {61 var members = shape.properties.map(|property: Log.Property| quote(property.name) + ":" + value(&property.value, typeTag))62 if let (Some(name), Some(tag)) = (*typeTag, shape.tag) { members = members.push(quote(name) + ":" + quote(tag)) }63 "\{" + members.join(",") + "\}"64 }65 case Log.Dictionary(entries) => "\{" + entries.map(|entry: Log.Entry| keyOf(&entry.key) + ":" + value(&entry.value, typeTag)).join(",") + "\}"66 }67}686970fn keyOf(key: &Log.Scalar) -> Str {71 match key {72 case Log.Text(text) => quote(text)73 case Log.Null => "\"null\""74 case _ => {75 let text = scalar(key)76 if text.startsWith("\"") { text } else { quote(text) }77 }78 }79}808182export fn hexOf(bytes: &Bytes) -> Str {83 var pieces: Array[Str] = []84 for octet in bytes.toArray() {85 let code = Option.unwrapOr(convertInteger[Int](octet), 0)86 pieces = pieces.push(HEX.slice(code / 16, code / 16 + 1) + HEX.slice(code % 16, code % 16 + 1))87 }88 pieces.join("")89}90