summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/raylib/mrblib/jamstack_json.rb
blob: ff96e48a789bf00b20a9a09a97554a2bf1508cdf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# Minimal JSON encoder (this mruby gembox has no JSON gem). Shared by the agent
# bridge (R1) and the Log pipeline (R2). Handles the value types we actually emit:
# nil/true/false, Integer, Float (non-finite -> null, since NaN/Infinity are not
# valid JSON), String, Symbol, Array, Hash. Anything else falls back to its to_s.
# Byte-wise string escaping: bytes >= 0x20 pass through, so UTF-8 multibyte
# sequences (all bytes >= 0x80) are preserved.
module Jamstack
  module JSON
    class << self
      def generate(o)
        s = ""
        emit(o, s)
        s
      end

      private

      def emit(o, s)
        case o
        when nil     then s << 'null'
        when true    then s << 'true'
        when false   then s << 'false'
        when Integer then s << o.to_s
        when Float   then s << (o.finite? ? o.to_s : 'null')
        when String  then estr(o, s)
        when Symbol  then estr(o.to_s, s)
        when Array
          s << '['
          first = true
          o.each { |e| s << ',' unless first; first = false; emit(e, s) }
          s << ']'
        when Hash
          s << '{'
          first = true
          o.each do |k, v|
            s << ',' unless first
            first = false
            estr(k.to_s, s)
            s << ':'
            emit(v, s)
          end
          s << '}'
        else
          estr(o.to_s, s)
        end
      end

      def estr(str, s)
        s << '"'
        str.each_byte do |b|
          case b
          when 34 then s << '\\"'
          when 92 then s << '\\\\'
          when 10 then s << '\\n'
          when 9  then s << '\\t'
          when 13 then s << '\\r'
          else
            s << (b < 0x20 ? format('\\u%04x', b) : b.chr)
          end
        end
        s << '"'
      end
    end
  end
end