-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstructrowsview.go
109 lines (101 loc) · 2.82 KB
/
structrowsview.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
package retable
import (
"fmt"
"reflect"
)
type StructRowsView struct {
title string
columns []string
indices []int // nil for 1:1 mapping of columns to struct fields
rows reflect.Value // slice of structs
cachedRow int
cachedValues []any
cachedReflectValues []reflect.Value
}
func NewStructRowsView(title string, columns []string, indices []int, rows reflect.Value) View {
if rows.Kind() != reflect.Slice && rows.Kind() != reflect.Array {
panic(fmt.Errorf("rows must be a slice or array, got %s", rows.Type()))
}
if is1on1Mapping(columns, indices) {
indices = nil
} else if indices != nil {
colMapped := make([]bool, len(columns))
for _, index := range indices {
if index < 0 {
continue
}
if index >= len(columns) {
panic(fmt.Errorf("index %d out of range for %d columns", index, len(columns)))
}
if colMapped[index] {
panic(fmt.Errorf("index %d mapped to column %q more than once", index, columns[index]))
}
colMapped[index] = true
}
for col, mapped := range colMapped {
if !mapped {
panic(fmt.Errorf("column %q not mapped", columns[col]))
}
}
}
return &StructRowsView{
title: title,
columns: columns,
indices: indices,
rows: rows,
cachedRow: -1,
}
}
func is1on1Mapping(columns []string, indices []int) bool {
if indices == nil {
return true
}
if len(columns) != len(indices) {
return false
}
for i, index := range indices {
if index != i {
return false
}
}
return true
}
func (view *StructRowsView) Title() string { return view.title }
func (view *StructRowsView) Columns() []string { return view.columns }
func (view *StructRowsView) NumRows() int { return view.rows.Len() }
func (view *StructRowsView) Cell(row, col int) any {
if row < 0 || col < 0 || row >= view.rows.Len() || col >= len(view.columns) {
return nil
}
if row != view.cachedRow {
view.cachedRow = row
view.cachedValues = nil
view.cachedReflectValues = nil
}
if view.cachedValues == nil {
if view.indices != nil {
view.cachedValues = IndexedStructFieldAnyValues(view.rows.Index(row), len(view.columns), view.indices)
} else {
view.cachedValues = StructFieldAnyValues(view.rows.Index(row))
}
}
return view.cachedValues[col]
}
func (view *StructRowsView) ReflectCell(row, col int) reflect.Value {
if row < 0 || col < 0 || row >= view.rows.Len() || col >= len(view.columns) {
return reflect.Value{}
}
if row != view.cachedRow {
view.cachedRow = row
view.cachedValues = nil
view.cachedReflectValues = nil
}
if view.cachedReflectValues == nil {
if view.indices != nil {
view.cachedReflectValues = IndexedStructFieldReflectValues(view.rows.Index(row), len(view.columns), view.indices)
} else {
view.cachedReflectValues = StructFieldReflectValues(view.rows.Index(row))
}
}
return view.cachedReflectValues[col]
}