-
Notifications
You must be signed in to change notification settings - Fork 67
/
marshal.go
145 lines (133 loc) · 3.47 KB
/
marshal.go
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package jsonio
import (
"bytes"
"encoding/hex"
"encoding/json"
"time"
"github.com/brimdata/zed"
"github.com/brimdata/zed/zcode"
"github.com/brimdata/zed/zson"
)
func marshalAny(typ zed.Type, bytes zcode.Bytes) interface{} {
if bytes == nil {
return nil
}
switch typ := typ.(type) {
case *zed.TypeNamed:
return marshalAny(typ.Type, bytes)
case *zed.TypeOfUint8, *zed.TypeOfUint16, *zed.TypeOfUint32, *zed.TypeOfUint64:
return zed.DecodeUint(bytes)
case *zed.TypeOfInt8, *zed.TypeOfInt16, *zed.TypeOfInt32, *zed.TypeOfInt64:
return zed.DecodeInt(bytes)
case *zed.TypeOfDuration:
return zed.DecodeDuration(bytes).String()
case *zed.TypeOfTime:
return zed.DecodeTime(bytes).Time().Format(time.RFC3339Nano)
case *zed.TypeOfFloat16:
return zed.DecodeFloat16(bytes)
case *zed.TypeOfFloat32:
return zed.DecodeFloat32(bytes)
case *zed.TypeOfFloat64:
return zed.DecodeFloat64(bytes)
case *zed.TypeOfBool:
return zed.DecodeBool(bytes)
case *zed.TypeOfBytes:
return "0x" + hex.EncodeToString(bytes)
case *zed.TypeOfString:
return string(bytes)
case *zed.TypeOfIP:
return zed.DecodeIP(bytes).String()
case *zed.TypeOfNet:
return zed.DecodeNet(bytes).String()
case *zed.TypeOfNull:
return nil
case *zed.TypeRecord:
return marshalRecord(typ, bytes)
case *zed.TypeArray:
return marshalArray(typ, bytes)
case *zed.TypeSet:
return marshalSet(typ, bytes)
case *zed.TypeMap:
return marshalMap(typ, bytes)
case *zed.TypeUnion:
return marshalAny(typ.Untag(bytes))
case *zed.TypeEnum:
return marshalEnum(typ, bytes)
case *zed.TypeError:
return map[string]interface{}{"error": marshalAny(typ.Type, bytes)}
default:
return zson.MustFormatValue(zed.NewValue(typ, bytes))
}
}
func marshalRecord(typ *zed.TypeRecord, bytes zcode.Bytes) interface{} {
it := bytes.Iter()
rec := record{}
for _, f := range typ.Fields {
rec = append(rec, field{f.Name, marshalAny(f.Type, it.Next())})
}
return rec
}
// record represents a Zed record and encodes as a JSON object. In contrast to
// a map, it preserves field order.
type record []field
type field struct {
name string
value interface{}
}
func (r record) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(false)
buf.WriteByte('{')
for i, field := range r {
if i > 0 {
buf.WriteByte(',')
}
if err := enc.Encode(field.name); err != nil {
return nil, err
}
buf.WriteByte(':')
if err := enc.Encode(field.value); err != nil {
return nil, err
}
}
buf.WriteByte('}')
return buf.Bytes(), nil
}
func marshalArray(typ *zed.TypeArray, bytes zcode.Bytes) interface{} {
a := make([]interface{}, 0)
it := bytes.Iter()
for !it.Done() {
a = append(a, marshalAny(typ.Type, it.Next()))
}
return a
}
func marshalSet(typ *zed.TypeSet, bytes zcode.Bytes) interface{} {
s := make([]interface{}, 0)
it := bytes.Iter()
for !it.Done() {
s = append(s, marshalAny(typ.Type, it.Next()))
}
return s
}
type Entry struct {
Key interface{} `json:"key"`
Value interface{} `json:"value"`
}
func marshalMap(typ *zed.TypeMap, bytes zcode.Bytes) interface{} {
var entries []Entry
it := bytes.Iter()
for !it.Done() {
key := marshalAny(typ.KeyType, it.Next())
val := marshalAny(typ.ValType, it.Next())
entries = append(entries, Entry{key, val})
}
return entries
}
func marshalEnum(typ *zed.TypeEnum, bytes zcode.Bytes) interface{} {
selector := int(zed.DecodeUint(bytes))
if selector >= len(typ.Symbols) {
return "<bad enum>"
}
return typ.Symbols[selector]
}