forked from torbiak/gopl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
encode.go
110 lines (96 loc) · 2.51 KB
/
encode.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
// ex12.8 can unmarshall s-expressions from an io.Reader.
package sexpr
import (
"bytes"
"fmt"
"reflect"
)
// Marshal encodes a Go value in S-expression form.
func Marshal(v interface{}) ([]byte, error) {
var buf bytes.Buffer
if err := encode(&buf, reflect.ValueOf(v), 0); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// encode writes to buf an S-expression representation of v.
func encode(buf *bytes.Buffer, v reflect.Value, indent int) error {
switch v.Kind() {
case reflect.Invalid:
buf.WriteString("nil")
case reflect.Int, reflect.Int8, reflect.Int16,
reflect.Int32, reflect.Int64:
fmt.Fprintf(buf, "%d", v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16,
reflect.Uint32, reflect.Uint64, reflect.Uintptr:
fmt.Fprintf(buf, "%d", v.Uint())
case reflect.String:
fmt.Fprintf(buf, "%q", v.String())
case reflect.Ptr:
return encode(buf, v.Elem(), indent)
case reflect.Array, reflect.Slice: // (value ...)
buf.WriteByte('(')
indent += 1
for i := 0; i < v.Len(); i++ {
if i > 0 {
fmt.Fprintf(buf, "\n%*s", indent, "")
}
if err := encode(buf, v.Index(i), indent); err != nil {
return err
}
}
buf.WriteByte(')')
case reflect.Struct: // ((name value) ...)
buf.WriteByte('(')
indent += 1
for i := 0; i < v.NumField(); i++ {
zero := reflect.Zero(v.Field(i).Type()).Interface()
if reflect.DeepEqual(v.Field(i).Interface(), zero) {
continue
}
if i > 0 {
fmt.Fprintf(buf, "\n%*s", indent, "")
}
start := buf.Len()
fmt.Fprintf(buf, "(%s ", v.Type().Field(i).Name)
if err := encode(buf, v.Field(i), indent+buf.Len()-start); err != nil {
return err
}
buf.WriteByte(')')
}
buf.WriteByte(')')
case reflect.Map: // ((key value) ...)
buf.WriteByte('(')
indent += 1
for i, key := range v.MapKeys() {
if i > 0 {
fmt.Fprintf(buf, "\n%*s", indent, "")
}
start := buf.Len()
buf.WriteByte('(')
if err := encode(buf, key, 0); err != nil {
return err
}
buf.WriteByte(' ')
if err := encode(buf, v.MapIndex(key), indent+buf.Len()-start); err != nil {
return err
}
buf.WriteByte(')')
}
buf.WriteByte(')')
case reflect.Bool: // t | nil
if v.Bool() {
buf.WriteByte('t')
} else {
buf.WriteString("nil")
}
case reflect.Float32, reflect.Float64:
fmt.Fprintf(buf, "%g", v.Float())
case reflect.Complex64, reflect.Complex128:
c := v.Complex()
fmt.Fprintf(buf, "#C(%g %g)", real(c), imag(c))
default: // chan, func
return fmt.Errorf("unsupported type: %s", v.Type())
}
return nil
}