forked from gocarina/gocsv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathencode.go
74 lines (67 loc) · 2.31 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
package gocsv
import (
"fmt"
"io"
"reflect"
)
type encoder struct {
out io.Writer
}
func newEncoder(out io.Writer) *encoder {
return &encoder{out}
}
func (encode *encoder) writeTo(in interface{}) error {
inValue, inType := getConcreteReflectValueAndType(in) // Get the concrete type (not pointer) (Slice<?> or Array<?>)
if err := encode.ensureInType(inType); err != nil {
return err
}
inInnerWasPointer, inInnerType := getConcreteContainerInnerType(inType) // Get the concrete inner type (not pointer) (Container<"?">)
if err := encode.ensureInInnerType(inInnerType); err != nil {
return err
}
csvWriter := getCSVWriter(encode.out) // Get the CSV writer
inInnerStructInfo := getStructInfo(inInnerType) // Get the inner struct info to get CSV annotations
csvHeadersLabels := make([]string, len(inInnerStructInfo.Fields))
for i, fieldInfo := range inInnerStructInfo.Fields { // Used to write the header (first line) in CSV
csvHeadersLabels[i] = fieldInfo.Key
}
csvWriter.Write(csvHeadersLabels)
inLen := inValue.Len()
for i := 0; i < inLen; i++ { // Iterate over container rows
for j, fieldInfo := range inInnerStructInfo.Fields {
csvHeadersLabels[j] = ""
inInnerFieldValue, err := encode.getInnerField(inValue.Index(i), inInnerWasPointer, fieldInfo.Num) // Get the correct field header <-> position
if err != nil {
return err
}
csvHeadersLabels[j] = inInnerFieldValue
}
csvWriter.Write(csvHeadersLabels)
}
csvWriter.Flush()
return nil
}
// Check if the inType is an array or a slice
func (encode *encoder) ensureInType(outType reflect.Type) error {
switch outType.Kind() {
case reflect.Slice:
fallthrough
case reflect.Array:
return nil
}
return fmt.Errorf("cannot use " + outType.String() + ", only slice or array supported")
}
// Check if the inInnerType is of type struct
func (encode *encoder) ensureInInnerType(outInnerType reflect.Type) error {
switch outInnerType.Kind() {
case reflect.Struct:
return nil
}
return fmt.Errorf("cannot use " + outInnerType.String() + ", only struct supported")
}
func (encode *encoder) getInnerField(outInner reflect.Value, outInnerWasPointer bool, fieldPosition int) (string, error) {
if outInnerWasPointer {
return getFieldAsString(outInner.Elem().Field(fieldPosition))
}
return getFieldAsString(outInner.Field(fieldPosition))
}