monitoring dashboard dependency vendor

Signed-off-by: junotx <junotx@126.com>
This commit is contained in:
junotx
2021-03-12 16:58:19 +08:00
parent 4f5c1378f8
commit 0c1f994695
462 changed files with 44469 additions and 51096 deletions

89
vendor/github.com/jszwec/csvutil/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,89 @@
# Created by https://www.gitignore.io/api/osx,go,windows,linux
### OSX ###
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Go ###
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
### Windows ###
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*

21
vendor/github.com/jszwec/csvutil/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Jacek Szwec
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

668
vendor/github.com/jszwec/csvutil/README.md generated vendored Normal file
View File

@@ -0,0 +1,668 @@
csvutil [![PkgGoDev](https://pkg.go.dev/badge/github.com/jszwec/csvutil@v1.4.0?tab=doc)](https://pkg.go.dev/github.com/jszwec/csvutil?tab=doc) ![Go](https://github.com/jszwec/csvutil/workflows/Go/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/jszwec/csvutil)](https://goreportcard.com/report/github.com/jszwec/csvutil) [![codecov](https://codecov.io/gh/jszwec/csvutil/branch/master/graph/badge.svg)](https://codecov.io/gh/jszwec/csvutil)
=================
<p align="center">
<img style="float: right;" src="https://user-images.githubusercontent.com/3941256/33054906-52b4bc08-ce4a-11e7-9651-b70c5a47c921.png"/ width=200>
</p>
Package csvutil provides fast, idiomatic, and dependency free mapping between CSV and Go (golang) values.
This package is not a CSV parser, it is based on the [Reader](https://godoc.org/github.com/jszwec/csvutil#Reader) and [Writer](https://godoc.org/github.com/jszwec/csvutil#Writer)
interfaces which are implemented by eg. std Go (golang) [csv package](https://golang.org/pkg/encoding/csv). This gives a possibility
of choosing any other CSV writer or reader which may be more performant.
Installation
------------
go get github.com/jszwec/csvutil
Requirements
-------------
* Go1.7+
Index
------
1. [Examples](#examples)
1. [Unmarshal](#examples_unmarshal)
2. [Marshal](#examples_marshal)
3. [Unmarshal and metadata](#examples_unmarshal_and_metadata)
4. [But my CSV file has no header...](#examples_but_my_csv_has_no_header)
5. [Decoder.Map - data normalization](#examples_decoder_map)
6. [Different separator/delimiter](#examples_different_separator)
7. [Custom Types](#examples_custom_types)
8. [Custom time.Time format](#examples_time_format)
9. [Custom struct tags](#examples_struct_tags)
10. [Slice and Map fields](#examples_slice_and_map_field)
11. [Nested/Embedded structs](#examples_nested_structs)
12. [Inline tag](#examples_inlined_structs)
2. [Performance](#performance)
1. [Unmarshal](#performance_unmarshal)
2. [Marshal](#performance_marshal)
Example <a name="examples"></a>
--------
### Unmarshal <a name="examples_unmarshal"></a>
Nice and easy Unmarshal is using the Go std [csv.Reader](https://golang.org/pkg/encoding/csv/#Reader) with its default options. Use [Decoder](https://godoc.org/github.com/jszwec/csvutil#Decoder) for streaming and more advanced use cases.
```go
var csvInput = []byte(`
name,age,CreatedAt
jacek,26,2012-04-01T15:00:00Z
john,,0001-01-01T00:00:00Z`,
)
type User struct {
Name string `csv:"name"`
Age int `csv:"age,omitempty"`
CreatedAt time.Time
}
var users []User
if err := csvutil.Unmarshal(csvInput, &users); err != nil {
fmt.Println("error:", err)
}
for _, u := range users {
fmt.Printf("%+v\n", u)
}
// Output:
// {Name:jacek Age:26 CreatedAt:2012-04-01 15:00:00 +0000 UTC}
// {Name:john Age:0 CreatedAt:0001-01-01 00:00:00 +0000 UTC}
```
### Marshal <a name="examples_marshal"></a>
Marshal is using the Go std [csv.Writer](https://golang.org/pkg/encoding/csv/#Writer) with its default options. Use [Encoder](https://godoc.org/github.com/jszwec/csvutil#Encoder) for streaming or to use a different Writer.
```go
type Address struct {
City string
Country string
}
type User struct {
Name string
Address
Age int `csv:"age,omitempty"`
CreatedAt time.Time
}
users := []User{
{
Name: "John",
Address: Address{"Boston", "USA"},
Age: 26,
CreatedAt: time.Date(2010, 6, 2, 12, 0, 0, 0, time.UTC),
},
{
Name: "Alice",
Address: Address{"SF", "USA"},
},
}
b, err := csvutil.Marshal(users)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(b))
// Output:
// Name,City,Country,age,CreatedAt
// John,Boston,USA,26,2010-06-02T12:00:00Z
// Alice,SF,USA,,0001-01-01T00:00:00Z
```
### Unmarshal and metadata <a name="examples_unmarshal_and_metadata"></a>
It may happen that your CSV input will not always have the same header. In addition
to your base fields you may get extra metadata that you would still like to store.
[Decoder](https://godoc.org/github.com/jszwec/csvutil#Decoder) provides
[Unused](https://godoc.org/github.com/jszwec/csvutil#Decoder.Unused) method, which after each call to
[Decode](https://godoc.org/github.com/jszwec/csvutil#Decoder.Decode) can report which header indexes
were not used during decoding. Based on that, it is possible to handle and store all these extra values.
```go
type User struct {
Name string `csv:"name"`
City string `csv:"city"`
Age int `csv:"age"`
OtherData map[string]string `csv:"-"`
}
csvReader := csv.NewReader(strings.NewReader(`
name,age,city,zip
alice,25,la,90005
bob,30,ny,10005`))
dec, err := csvutil.NewDecoder(csvReader)
if err != nil {
log.Fatal(err)
}
header := dec.Header()
var users []User
for {
u := User{OtherData: make(map[string]string)}
if err := dec.Decode(&u); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
for _, i := range dec.Unused() {
u.OtherData[header[i]] = dec.Record()[i]
}
users = append(users, u)
}
fmt.Println(users)
// Output:
// [{alice la 25 map[zip:90005]} {bob ny 30 map[zip:10005]}]
```
### But my CSV file has no header... <a name="examples_but_my_csv_has_no_header"></a>
Some CSV files have no header, but if you know how it should look like, it is
possible to define a struct and generate it. All that is left to do, is to pass
it to a decoder.
```go
type User struct {
ID int
Name string
Age int `csv:",omitempty"`
City string
}
csvReader := csv.NewReader(strings.NewReader(`
1,John,27,la
2,Bob,,ny`))
// in real application this should be done once in init function.
userHeader, err := csvutil.Header(User{}, "csv")
if err != nil {
log.Fatal(err)
}
dec, err := csvutil.NewDecoder(csvReader, userHeader...)
if err != nil {
log.Fatal(err)
}
var users []User
for {
var u User
if err := dec.Decode(&u); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
users = append(users, u)
}
fmt.Printf("%+v", users)
// Output:
// [{ID:1 Name:John Age:27 City:la} {ID:2 Name:Bob Age:0 City:ny}]
```
### Decoder.Map - data normalization <a name="examples_decoder_map"></a>
The Decoder's [Map](https://godoc.org/github.com/jszwec/csvutil#Decoder.Map) function is a powerful tool that can help clean up or normalize
the incoming data before the actual decoding takes place.
Lets say we want to decode some floats and the csv input contains some NaN values, but these values are represented by the 'n/a' string. An attempt to decode 'n/a' into float will end up with error, because strconv.ParseFloat expects 'NaN'. Knowing that, we can implement a Map function that will normalize our 'n/a' string and turn it to 'NaN' only for float types.
```go
dec, err := NewDecoder(r)
if err != nil {
log.Fatal(err)
}
dec.Map = func(field, column string, v interface{}) string {
if _, ok := v.(float64); ok && field == "n/a" {
return "NaN"
}
return field
}
```
Now our float64 fields will be decoded properly into NaN. What about float32, float type aliases and other NaN formats? Look at the full example [here](https://gist.github.com/jszwec/2bb94f8f3612e0162eb16003701f727e).
### Different separator/delimiter <a name="examples_different_separator"></a>
Some files may use different value separators, for example TSV files would use `\t`. The following examples show how to set up a Decoder and Encoder for such use case.
#### Decoder:
```go
csvReader := csv.NewReader(r)
csvReader.Comma = '\t'
dec, err := NewDecoder(csvReader)
if err != nil {
log.Fatal(err)
}
var users []User
for {
var u User
if err := dec.Decode(&u); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
users = append(users, u)
}
```
#### Encoder:
```go
var buf bytes.Buffer
w := csv.NewWriter(&buf)
w.Comma = '\t'
enc := csvutil.NewEncoder(w)
for _, u := range users {
if err := enc.Encode(u); err != nil {
log.Fatal(err)
}
}
w.Flush()
if err := w.Error(); err != nil {
log.Fatal(err)
}
```
### Custom Types and Overrides <a name="examples_custom_types"></a>
There are multiple ways to customize or override your type's behavior.
1. a type implements [csvutil.Marshaler](https://pkg.go.dev/github.com/jszwec/csvutil#Marshaler) and/or [csvutil.Unmarshaler](https://pkg.go.dev/github.com/jszwec/csvutil#Unmarshaler)
```go
type Foo int64
func (f Foo) MarshalCSV() ([]byte, error) {
return strconv.AppendInt(nil, int64(f), 16), nil
}
func (f *Foo) UnmarshalCSV(data []byte) error {
i, err := strconv.ParseInt(string(data), 16, 64)
if err != nil {
return err
}
*f = Foo(i)
return nil
}
```
2. a type implements [encoding.TextUnmarshaler](https://golang.org/pkg/encoding/#TextUnmarshaler) and/or [encoding.TextMarshaler](https://golang.org/pkg/encoding/#TextMarshaler)
```go
type Foo int64
func (f Foo) MarshalText() ([]byte, error) {
return strconv.AppendInt(nil, int64(f), 16), nil
}
func (f *Foo) UnmarshalText(data []byte) error {
i, err := strconv.ParseInt(string(data), 16, 64)
if err != nil {
return err
}
*f = Foo(i)
return nil
}
```
3. a type is registered using [Encoder.Register](https://pkg.go.dev/github.com/jszwec/csvutil#Encoder.Register) and/or [Decoder.Register](https://pkg.go.dev/github.com/jszwec/csvutil#Decoder.Register)
```go
type Foo int64
enc.Register(func(f Foo) ([]byte, error) {
return strconv.AppendInt(nil, int64(f), 16), nil
})
dec.Register(func(data []byte, f *Foo) error {
v, err := strconv.ParseInt(string(data), 16, 64)
if err != nil {
return err
}
*f = Foo(v)
return nil
})
```
4. a type implements an interface that was registered using [Encoder.Register](https://pkg.go.dev/github.com/jszwec/csvutil#Encoder.Register) and/or [Decoder.Register](https://pkg.go.dev/github.com/jszwec/csvutil#Decoder.Register)
```go
type Foo int64
func (f Foo) String() string {
return strconv.FormatInt(int64(f), 16)
}
func (f *Foo) Scan(state fmt.ScanState, verb rune) error {
// too long; look here: https://github.com/jszwec/csvutil/blob/master/example_decoder_register_test.go#L19
}
enc.Register(func(s fmt.Stringer) ([]byte, error) {
return []byte(s.String()), nil
})
dec.Register(func(data []byte, s fmt.Scanner) error {
_, err := fmt.Sscan(string(data), s)
return err
})
```
The order of precedence for both Encoder and Decoder is:
1. type is registered
2. type implements an interface that was registered
3. csvutil.{Un,M}arshaler
4. encoding.Text{Un,M}arshaler
For more examples look [here](https://pkg.go.dev/github.com/jszwec/csvutil?readme=expanded#pkg-examples)
### Custom time.Time format <a name="examples_time_format"></a>
Type [time.Time](https://golang.org/pkg/time/#Time) can be used as is in the struct fields by both Decoder and Encoder
due to the fact that both have builtin support for [encoding.TextUnmarshaler](https://golang.org/pkg/encoding/#TextUnmarshaler) and [encoding.TextMarshaler](https://golang.org/pkg/encoding/#TextMarshaler). This means that by default
Time has a specific format; look at [MarshalText](https://golang.org/pkg/time/#Time.MarshalText) and [UnmarshalText](https://golang.org/pkg/time/#Time.UnmarshalText). There are two ways to override it, which one you choose depends on your use case:
1. Via Register func (based on encoding/json)
```go
const format = "2006/01/02 15:04:05"
marshalTime := func(t time.Time) ([]byte, error) {
return t.AppendFormat(nil, format), nil
}
unmarshalTime := func(data []byte, t *time.Time) error {
tt, err := time.Parse(format, string(data))
if err != nil {
return err
}
*t = tt
return nil
}
enc := csvutil.NewEncoder(w)
enc.Register(marshalTime)
dec, err := csvutil.NewDecoder(r)
if err != nil {
return err
}
dec.Register(unmarshalTime)
```
2. With custom type:
```go
type Time struct {
time.Time
}
const format = "2006/01/02 15:04:05"
func (t Time) MarshalCSV() ([]byte, error) {
var b [len(format)]byte
return t.AppendFormat(b[:0], format), nil
}
func (t *Time) UnmarshalCSV(data []byte) error {
tt, err := time.Parse(format, string(data))
if err != nil {
return err
}
*t = Time{Time: tt}
return nil
}
```
### Custom struct tags <a name="examples_struct_tags"></a>
Like in other Go encoding packages struct field tags can be used to set
custom names or options. By default encoders and decoders are looking at `csv` tag.
However, this can be overriden by manually setting the Tag field.
```go
type Foo struct {
Bar int `custom:"bar"`
}
```
```go
dec, err := csvutil.NewDecoder(r)
if err != nil {
log.Fatal(err)
}
dec.Tag = "custom"
```
```go
enc := csvutil.NewEncoder(w)
enc.Tag = "custom"
```
### Slice and Map fields <a name="examples_slice_and_map_field"></a>
There is no default encoding/decoding support for slice and map fields because there is no CSV spec for such values.
In such case, it is recommended to create a custom type alias and implement Marshaler and Unmarshaler interfaces.
Please note that slice and map aliases behave differently than aliases of other types - there is no need for type casting.
```go
type Strings []string
func (s Strings) MarshalCSV() ([]byte, error) {
return []byte(strings.Join(s, ",")), nil // strings.Join takes []string but it will also accept Strings
}
type StringMap map[string]string
func (sm StringMap) MarshalCSV() ([]byte, error) {
return []byte(fmt.Sprint(sm)), nil
}
func main() {
b, err := csvutil.Marshal([]struct {
Strings Strings `csv:"strings"`
Map StringMap `csv:"map"`
}{
{[]string{"a", "b"}, map[string]string{"a": "1"}}, // no type casting is required for slice and map aliases
{Strings{"c", "d"}, StringMap{"b": "1"}},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", b)
// Output:
// strings,map
// "a,b",map[a:1]
// "c,d",map[b:1]
}
```
### Nested/Embedded structs <a name="examples_nested_structs"></a>
Both Encoder and Decoder support nested or embedded structs.
Playground: https://play.golang.org/p/ZySjdVkovbf
```go
package main
import (
"fmt"
"github.com/jszwec/csvutil"
)
type Address struct {
Street string `csv:"street"`
City string `csv:"city"`
}
type User struct {
Name string `csv:"name"`
Address
}
func main() {
users := []User{
{
Name: "John",
Address: Address{
Street: "Boylston",
City: "Boston",
},
},
}
b, err := csvutil.Marshal(users)
if err != nil {
panic(err)
}
fmt.Printf("%s\n", b)
var out []User
if err := csvutil.Unmarshal(b, &out); err != nil {
panic(err)
}
fmt.Printf("%+v\n", out)
// Output:
//
// name,street,city
// John,Boylston,Boston
//
// [{Name:John Address:{Street:Boylston City:Boston}}]
}
```
### Inline tag <a name="examples_inlined_structs"></a>
Fields with inline tag behave similarly to embedded struct fields. However,
it gives a possibility to specify the prefix for all underlying fields. This
can be useful when one structure can define multiple CSV columns because they
are different from each other only by a certain prefix. Look at the example below.
Playground: https://play.golang.org/p/jyEzeskSnj7
```go
package main
import (
"fmt"
"github.com/jszwec/csvutil"
)
func main() {
type Address struct {
Street string `csv:"street"`
City string `csv:"city"`
}
type User struct {
Name string `csv:"name"`
Address Address `csv:",inline"`
HomeAddress Address `csv:"home_address_,inline"`
WorkAddress Address `csv:"work_address_,inline"`
Age int `csv:"age,omitempty"`
}
users := []User{
{
Name: "John",
Address: Address{"Washington", "Boston"},
HomeAddress: Address{"Boylston", "Boston"},
WorkAddress: Address{"River St", "Cambridge"},
Age: 26,
},
}
b, err := csvutil.Marshal(users)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%s\n", b)
// Output:
// name,street,city,home_address_street,home_address_city,work_address_street,work_address_city,age
// John,Washington,Boston,Boylston,Boston,River St,Cambridge,26
}
```
Performance
------------
csvutil provides the best encoding and decoding performance with small memory usage.
### Unmarshal <a name="performance_unmarshal"></a>
[benchmark code](https://gist.github.com/jszwec/e8515e741190454fa3494bcd3e1f100f)
#### csvutil:
```
BenchmarkUnmarshal/csvutil.Unmarshal/1_record-12 280696 4516 ns/op 7332 B/op 26 allocs/op
BenchmarkUnmarshal/csvutil.Unmarshal/10_records-12 95750 11517 ns/op 8356 B/op 35 allocs/op
BenchmarkUnmarshal/csvutil.Unmarshal/100_records-12 14997 83146 ns/op 18532 B/op 125 allocs/op
BenchmarkUnmarshal/csvutil.Unmarshal/1000_records-12 1485 750143 ns/op 121094 B/op 1025 allocs/op
BenchmarkUnmarshal/csvutil.Unmarshal/10000_records-12 154 7587205 ns/op 1136662 B/op 10025 allocs/op
BenchmarkUnmarshal/csvutil.Unmarshal/100000_records-12 14 76126616 ns/op 11808744 B/op 100025 allocs/op
```
#### gocsv:
```
BenchmarkUnmarshal/gocsv.Unmarshal/1_record-12 141330 7499 ns/op 7795 B/op 97 allocs/op
BenchmarkUnmarshal/gocsv.Unmarshal/10_records-12 54252 21664 ns/op 13891 B/op 307 allocs/op
BenchmarkUnmarshal/gocsv.Unmarshal/100_records-12 6920 159662 ns/op 72644 B/op 2380 allocs/op
BenchmarkUnmarshal/gocsv.Unmarshal/1000_records-12 752 1556083 ns/op 650248 B/op 23083 allocs/op
BenchmarkUnmarshal/gocsv.Unmarshal/10000_records-12 72 17086623 ns/op 7017469 B/op 230092 allocs/op
BenchmarkUnmarshal/gocsv.Unmarshal/100000_records-12 7 163610749 ns/op 75004923 B/op 2300105 allocs/op
```
#### easycsv:
```
BenchmarkUnmarshal/easycsv.ReadAll/1_record-12 101527 10662 ns/op 8855 B/op 81 allocs/op
BenchmarkUnmarshal/easycsv.ReadAll/10_records-12 23325 51437 ns/op 24072 B/op 391 allocs/op
BenchmarkUnmarshal/easycsv.ReadAll/100_records-12 2402 447296 ns/op 170538 B/op 3454 allocs/op
BenchmarkUnmarshal/easycsv.ReadAll/1000_records-12 272 4370854 ns/op 1595683 B/op 34057 allocs/op
BenchmarkUnmarshal/easycsv.ReadAll/10000_records-12 24 47502457 ns/op 18861808 B/op 340068 allocs/op
BenchmarkUnmarshal/easycsv.ReadAll/100000_records-12 3 468974170 ns/op 189427066 B/op 3400082 allocs/op
```
### Marshal <a name="performance_marshal"></a>
[benchmark code](https://gist.github.com/jszwec/31980321e1852ebb5615a44ccf374f17)
#### csvutil:
```
BenchmarkMarshal/csvutil.Marshal/1_record-12 279558 4390 ns/op 9952 B/op 12 allocs/op
BenchmarkMarshal/csvutil.Marshal/10_records-12 82478 15608 ns/op 10800 B/op 21 allocs/op
BenchmarkMarshal/csvutil.Marshal/100_records-12 10275 117288 ns/op 28208 B/op 112 allocs/op
BenchmarkMarshal/csvutil.Marshal/1000_records-12 1075 1147473 ns/op 168508 B/op 1014 allocs/op
BenchmarkMarshal/csvutil.Marshal/10000_records-12 100 11985382 ns/op 1525973 B/op 10017 allocs/op
BenchmarkMarshal/csvutil.Marshal/100000_records-12 9 113640813 ns/op 22455873 B/op 100021 allocs/op
```
#### gocsv:
```
BenchmarkMarshal/gocsv.Marshal/1_record-12 203052 6077 ns/op 5914 B/op 81 allocs/op
BenchmarkMarshal/gocsv.Marshal/10_records-12 50132 24585 ns/op 9284 B/op 360 allocs/op
BenchmarkMarshal/gocsv.Marshal/100_records-12 5480 212008 ns/op 51916 B/op 3151 allocs/op
BenchmarkMarshal/gocsv.Marshal/1000_records-12 514 2053919 ns/op 444506 B/op 31053 allocs/op
BenchmarkMarshal/gocsv.Marshal/10000_records-12 52 21066666 ns/op 4332377 B/op 310064 allocs/op
BenchmarkMarshal/gocsv.Marshal/100000_records-12 5 207408929 ns/op 51169419 B/op 3100077 allocs/op
```

2
vendor/github.com/jszwec/csvutil/_config.yml generated vendored Normal file
View File

@@ -0,0 +1,2 @@
theme: jekyll-theme-cayman
markdown: GFM

178
vendor/github.com/jszwec/csvutil/cache.go generated vendored Normal file
View File

@@ -0,0 +1,178 @@
package csvutil
import (
"reflect"
"sort"
)
type field struct {
name string
baseType reflect.Type
typ reflect.Type
tag tag
index []int
}
type fields []field
func (fs fields) Len() int { return len(fs) }
func (fs fields) Swap(i, j int) { fs[i], fs[j] = fs[j], fs[i] }
func (fs fields) Less(i, j int) bool {
for k, n := range fs[i].index {
if n != fs[j].index[k] {
return n < fs[j].index[k]
}
}
return len(fs[i].index) < len(fs[j].index)
}
type typeKey struct {
tag string
reflect.Type
}
type fieldMap map[string]fields
func (m fieldMap) insert(f field) {
fs, ok := m[f.name]
if !ok {
m[f.name] = append(fs, f)
return
}
// insert only fields with the shortest path.
if len(fs[0].index) != len(f.index) {
return
}
// fields that are tagged have priority.
if !f.tag.empty {
m[f.name] = append([]field{f}, fs...)
return
}
m[f.name] = append(fs, f)
}
func (m fieldMap) fields() fields {
out := make(fields, 0, len(m))
for _, v := range m {
for i, f := range v {
if f.tag.empty != v[0].tag.empty {
v = v[:i]
break
}
}
if len(v) > 1 {
continue
}
out = append(out, v[0])
}
sort.Sort(out)
return out
}
func buildFields(k typeKey) fields {
type key struct {
reflect.Type
tag
}
q := fields{{typ: k.Type}}
visited := make(map[key]struct{})
fm := make(fieldMap)
for len(q) > 0 {
f := q[0]
q = q[1:]
key := key{f.typ, f.tag}
if _, ok := visited[key]; ok {
continue
}
visited[key] = struct{}{}
depth := len(f.index)
numField := f.typ.NumField()
for i := 0; i < numField; i++ {
sf := f.typ.Field(i)
if sf.PkgPath != "" && !sf.Anonymous {
// unexported field
continue
}
if sf.Anonymous {
t := sf.Type
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if sf.PkgPath != "" && t.Kind() != reflect.Struct {
// ignore embedded unexported non-struct fields.
continue
}
}
tag := parseTag(k.tag, sf)
if tag.ignore {
continue
}
if f.tag.prefix != "" {
tag.prefix += f.tag.prefix
}
ft := sf.Type
if ft.Kind() == reflect.Ptr {
ft = ft.Elem()
}
newf := field{
name: tag.prefix + tag.name,
baseType: sf.Type,
typ: ft,
tag: tag,
index: makeIndex(f.index, i),
}
if sf.Anonymous && ft.Kind() == reflect.Struct && tag.empty {
q = append(q, newf)
continue
}
if tag.inline && ft.Kind() == reflect.Struct {
q = append(q, newf)
continue
}
fm.insert(newf)
// look for duplicate nodes on the same level. Nodes won't be
// revisited, so write all fields for the current type now.
for _, v := range q {
if len(v.index) != depth {
break
}
if v.typ == f.typ && v.tag.prefix == tag.prefix {
// other nodes can have different path.
fm.insert(field{
name: tag.prefix + tag.name,
baseType: sf.Type,
typ: ft,
tag: tag,
index: makeIndex(v.index, i),
})
}
}
}
}
return fm.fields()
}
func makeIndex(index []int, v int) []int {
out := make([]int, len(index), len(index)+1)
copy(out, index)
return append(out, v)
}

30
vendor/github.com/jszwec/csvutil/cache_go17.go generated vendored Normal file
View File

@@ -0,0 +1,30 @@
// +build !go1.9
package csvutil
import (
"sync"
)
var fieldCache = struct {
mtx sync.RWMutex
m map[typeKey][]field
}{m: make(map[typeKey][]field)}
func cachedFields(k typeKey) fields {
fieldCache.mtx.RLock()
fields, ok := fieldCache.m[k]
fieldCache.mtx.RUnlock()
if ok {
return fields
}
fields = buildFields(k)
fieldCache.mtx.Lock()
fieldCache.m[k] = fields
fieldCache.mtx.Unlock()
return fields
}

18
vendor/github.com/jszwec/csvutil/cache_go19.go generated vendored Normal file
View File

@@ -0,0 +1,18 @@
// +build go1.9
package csvutil
import (
"sync"
)
var fieldCache sync.Map // map[typeKey][]field
func cachedFields(k typeKey) fields {
if v, ok := fieldCache.Load(k); ok {
return v.(fields)
}
v, _ := fieldCache.LoadOrStore(k, buildFields(k))
return v.(fields)
}

223
vendor/github.com/jszwec/csvutil/csvutil.go generated vendored Normal file
View File

@@ -0,0 +1,223 @@
package csvutil
import (
"bytes"
"encoding/csv"
"io"
"reflect"
)
const defaultTag = "csv"
var (
_bytes = reflect.TypeOf(([]byte)(nil))
_error = reflect.TypeOf((*error)(nil)).Elem()
)
// Unmarshal parses the CSV-encoded data and stores the result in the slice or
// the array pointed to by v. If v is nil or not a pointer to a struct slice or
// struct array, Unmarshal returns an InvalidUnmarshalError.
//
// Unmarshal uses the std encoding/csv.Reader for parsing and csvutil.Decoder
// for populating the struct elements in the provided slice. For exact decoding
// rules look at the Decoder's documentation.
//
// The first line in data is treated as a header. Decoder will use it to map
// csv columns to struct's fields.
//
// In case of success the provided slice will be reinitialized and its content
// fully replaced with decoded data.
func Unmarshal(data []byte, v interface{}) error {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr || val.IsNil() {
return &InvalidUnmarshalError{Type: reflect.TypeOf(v)}
}
switch val.Type().Elem().Kind() {
case reflect.Slice, reflect.Array:
default:
return &InvalidUnmarshalError{Type: val.Type()}
}
typ := val.Type().Elem()
if walkType(typ.Elem()).Kind() != reflect.Struct {
return &InvalidUnmarshalError{Type: val.Type()}
}
dec, err := NewDecoder(newCSVReader(bytes.NewReader(data)))
if err == io.EOF {
return nil
} else if err != nil {
return err
}
// for the array just call decodeArray directly; for slice values call the
// optimized code for better performance.
if typ.Kind() == reflect.Array {
return dec.decodeArray(val.Elem())
}
c := countRecords(data)
slice := reflect.MakeSlice(typ, c, c)
var i int
for ; ; i++ {
// just in case countRecords counts it wrong.
if i >= c && i >= slice.Len() {
slice = reflect.Append(slice, reflect.New(typ.Elem()).Elem())
}
if err := dec.Decode(slice.Index(i).Addr().Interface()); err == io.EOF {
break
} else if err != nil {
return err
}
}
val.Elem().Set(slice.Slice3(0, i, i))
return nil
}
// Marshal returns the CSV encoding of slice or array v. If v is not a slice or
// elements are not structs then Marshal returns InvalidMarshalError.
//
// Marshal uses the std encoding/csv.Writer with its default settings for csv
// encoding.
//
// Marshal will always encode the CSV header even for the empty slice.
//
// For the exact encoding rules look at Encoder.Encode method.
func Marshal(v interface{}) ([]byte, error) {
val := walkValue(reflect.ValueOf(v))
if !val.IsValid() {
return nil, &InvalidMarshalError{}
}
switch val.Kind() {
case reflect.Array, reflect.Slice:
default:
return nil, &InvalidMarshalError{Type: reflect.ValueOf(v).Type()}
}
typ := walkType(val.Type().Elem())
if typ.Kind() != reflect.Struct {
return nil, &InvalidMarshalError{Type: reflect.ValueOf(v).Type()}
}
var buf bytes.Buffer
w := csv.NewWriter(&buf)
enc := NewEncoder(w)
if err := enc.encodeHeader(typ); err != nil {
return nil, err
}
if err := enc.encodeArray(val); err != nil {
return nil, err
}
w.Flush()
if err := w.Error(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func countRecords(s []byte) (n int) {
var prev byte
inQuote := false
for {
if len(s) == 0 && prev != '"' {
return n
}
i := bytes.IndexAny(s, "\n\"")
if i == -1 {
return n + 1
}
switch s[i] {
case '\n':
if !inQuote && (i > 0 || prev == '"') {
n++
}
case '"':
inQuote = !inQuote
}
prev = s[i]
s = s[i+1:]
}
}
// Header scans the provided struct type and generates a CSV header for it.
//
// Field names are written in the same order as struct fields are defined.
// Embedded struct's fields are treated as if they were part of the outer struct.
// Fields that are embedded types and that are tagged are treated like any
// other field.
//
// Unexported fields and fields with tag "-" are ignored.
//
// Tagged fields have the priority over non tagged fields with the same name.
//
// Following the Go visibility rules if there are multiple fields with the same
// name (tagged or not tagged) on the same level and choice between them is
// ambiguous, then all these fields will be ignored.
//
// It is a good practice to call Header once for each type. The suitable place
// for calling it is init function. Look at Decoder.DecodingDataWithNoHeader
// example.
//
// If tag is left empty the default "csv" will be used.
//
// Header will return UnsupportedTypeError if the provided value is nil or is
// not a struct.
func Header(v interface{}, tag string) ([]string, error) {
typ, err := valueType(v)
if err != nil {
return nil, err
}
if tag == "" {
tag = defaultTag
}
fields := cachedFields(typeKey{tag, typ})
h := make([]string, len(fields))
for i, f := range fields {
h[i] = f.name
}
return h, nil
}
func valueType(v interface{}) (reflect.Type, error) {
val := reflect.ValueOf(v)
if !val.IsValid() {
return nil, &UnsupportedTypeError{}
}
loop:
for {
switch val.Kind() {
case reflect.Ptr, reflect.Interface:
el := val.Elem()
if !el.IsValid() {
break loop
}
val = el
default:
break loop
}
}
typ := walkType(val.Type())
if typ.Kind() != reflect.Struct {
return nil, &UnsupportedTypeError{Type: typ}
}
return typ, nil
}

12
vendor/github.com/jszwec/csvutil/csvutil_go17.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
// +build !go1.9
package csvutil
import (
"encoding/csv"
"io"
)
func newCSVReader(r io.Reader) *csv.Reader {
return csv.NewReader(r)
}

14
vendor/github.com/jszwec/csvutil/csvutil_go19.go generated vendored Normal file
View File

@@ -0,0 +1,14 @@
// +build go1.9
package csvutil
import (
"encoding/csv"
"io"
)
func newCSVReader(r io.Reader) *csv.Reader {
rr := csv.NewReader(r)
rr.ReuseRecord = true
return rr
}

247
vendor/github.com/jszwec/csvutil/decode.go generated vendored Normal file
View File

@@ -0,0 +1,247 @@
package csvutil
import (
"encoding"
"encoding/base64"
"reflect"
"strconv"
)
var (
textUnmarshaler = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
csvUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
)
var intDecoders = map[int]decodeFunc{
8: decodeIntN(8),
16: decodeIntN(16),
32: decodeIntN(32),
64: decodeIntN(64),
}
var uintDecoders = map[int]decodeFunc{
8: decodeUintN(8),
16: decodeUintN(16),
32: decodeUintN(32),
64: decodeUintN(64),
}
var (
decodeFloat32 = decodeFloatN(32)
decodeFloat64 = decodeFloatN(64)
)
type decodeFunc func(s string, v reflect.Value) error
func decodeFuncValue(f reflect.Value) decodeFunc {
isIface := f.Type().In(1).Kind() == reflect.Interface
return func(s string, v reflect.Value) error {
if isIface && v.Type().Kind() == reflect.Interface && v.IsNil() {
return &UnmarshalTypeError{Value: s, Type: v.Type()}
}
out := f.Call([]reflect.Value{
reflect.ValueOf([]byte(s)),
v,
})
err, _ := out[0].Interface().(error)
return err
}
}
func decodeFuncValuePtr(f reflect.Value) decodeFunc {
return func(s string, v reflect.Value) error {
out := f.Call([]reflect.Value{
reflect.ValueOf([]byte(s)),
v.Addr(),
})
err, _ := out[0].Interface().(error)
return err
}
}
func decodeString(s string, v reflect.Value) error {
v.SetString(s)
return nil
}
func decodeIntN(bits int) decodeFunc {
return func(s string, v reflect.Value) error {
n, err := strconv.ParseInt(s, 10, bits)
if err != nil {
return &UnmarshalTypeError{Value: s, Type: v.Type()}
}
v.SetInt(n)
return nil
}
}
func decodeUintN(bits int) decodeFunc {
return func(s string, v reflect.Value) error {
n, err := strconv.ParseUint(s, 10, bits)
if err != nil {
return &UnmarshalTypeError{Value: s, Type: v.Type()}
}
v.SetUint(n)
return nil
}
}
func decodeFloatN(bits int) decodeFunc {
return func(s string, v reflect.Value) error {
n, err := strconv.ParseFloat(s, bits)
if err != nil {
return &UnmarshalTypeError{Value: s, Type: v.Type()}
}
v.SetFloat(n)
return nil
}
}
func decodeBool(s string, v reflect.Value) error {
b, err := strconv.ParseBool(s)
if err != nil {
return &UnmarshalTypeError{Value: s, Type: v.Type()}
}
v.SetBool(b)
return nil
}
func decodePtrTextUnmarshaler(s string, v reflect.Value) error {
return decodeTextUnmarshaler(s, v.Addr())
}
func decodeTextUnmarshaler(s string, v reflect.Value) error {
return v.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(s))
}
func decodePtrFieldUnmarshaler(s string, v reflect.Value) error {
return decodeFieldUnmarshaler(s, v.Addr())
}
func decodeFieldUnmarshaler(s string, v reflect.Value) error {
return v.Interface().(Unmarshaler).UnmarshalCSV([]byte(s))
}
func decodePtr(typ reflect.Type, funcMap map[reflect.Type]reflect.Value, ifaceFuncs []reflect.Value) (decodeFunc, error) {
next, err := decodeFn(typ.Elem(), funcMap, ifaceFuncs)
if err != nil {
return nil, err
}
return func(s string, v reflect.Value) error {
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
return next(s, v.Elem())
}, nil
}
func decodeInterface(funcMap map[reflect.Type]reflect.Value, ifaceFuncs []reflect.Value) decodeFunc {
return func(s string, v reflect.Value) error {
if v.NumMethod() != 0 {
return &UnmarshalTypeError{
Value: s,
Type: v.Type(),
}
}
if v.IsNil() {
v.Set(reflect.ValueOf(s))
return nil
}
el := walkValue(v)
if !el.CanSet() {
if el.IsValid() {
// we may get a value receiver unmarshalers or registered funcs
// underneath the interface in which case we should call
// Unmarshal/Registered func.
typ := el.Type()
if f, ok := funcMap[typ]; ok {
return decodeFuncValue(f)(s, el)
}
for _, f := range ifaceFuncs {
if typ.AssignableTo(f.Type().In(1)) {
return decodeFuncValue(f)(s, el)
}
}
if typ.Implements(csvUnmarshaler) {
return decodeFieldUnmarshaler(s, el)
}
if typ.Implements(textUnmarshaler) {
return decodeTextUnmarshaler(s, el)
}
}
v.Set(reflect.ValueOf(s))
return nil
}
fn, err := decodeFn(el.Type(), funcMap, ifaceFuncs)
if err != nil {
return err
}
return fn(s, el)
}
}
func decodeBytes(s string, v reflect.Value) error {
b, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return err
}
v.SetBytes(b)
return nil
}
func decodeFn(typ reflect.Type, funcMap map[reflect.Type]reflect.Value, ifaceFuncs []reflect.Value) (decodeFunc, error) {
if f, ok := funcMap[typ]; ok {
return decodeFuncValue(f), nil
}
if f, ok := funcMap[reflect.PtrTo(typ)]; ok {
return decodeFuncValuePtr(f), nil
}
for _, f := range ifaceFuncs {
argType := f.Type().In(1)
if typ.AssignableTo(argType) {
return decodeFuncValue(f), nil
}
if reflect.PtrTo(typ).AssignableTo(argType) {
return decodeFuncValuePtr(f), nil
}
}
if reflect.PtrTo(typ).Implements(csvUnmarshaler) {
return decodePtrFieldUnmarshaler, nil
}
if reflect.PtrTo(typ).Implements(textUnmarshaler) {
return decodePtrTextUnmarshaler, nil
}
switch typ.Kind() {
case reflect.Ptr:
return decodePtr(typ, funcMap, ifaceFuncs)
case reflect.Interface:
return decodeInterface(funcMap, ifaceFuncs), nil
case reflect.String:
return decodeString, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return intDecoders[typ.Bits()], nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return uintDecoders[typ.Bits()], nil
case reflect.Float32:
return decodeFloat32, nil
case reflect.Float64:
return decodeFloat64, nil
case reflect.Bool:
return decodeBool, nil
case reflect.Slice:
if typ.Elem().Kind() == reflect.Uint8 {
return decodeBytes, nil
}
}
return nil, &UnsupportedTypeError{Type: typ}
}

487
vendor/github.com/jszwec/csvutil/decoder.go generated vendored Normal file
View File

@@ -0,0 +1,487 @@
package csvutil
import (
"io"
"reflect"
)
type decField struct {
columnIndex int
field
decodeFunc
zero interface{}
}
// A Decoder reads and decodes string records into structs.
type Decoder struct {
// Tag defines which key in the struct field's tag to scan for names and
// options (Default: 'csv').
Tag string
// If true, Decoder will return a MissingColumnsError if it discovers
// that any of the columns are missing. This means that a CSV input
// will be required to contain all columns that were defined in the
// provided struct.
DisallowMissingColumns bool
// If not nil, Map is a function that is called for each field in the csv
// record before decoding the data. It allows mapping certain string values
// for specific columns or types to a known format. Decoder calls Map with
// the current column name (taken from header) and a zero non-pointer value
// of a type to which it is going to decode data into. Implementations
// should use type assertions to recognize the type.
//
// The good example of use case for Map is if NaN values are represented by
// eg 'n/a' string, implementing a specific Map function for all floats
// could map 'n/a' back into 'NaN' to allow successful decoding.
//
// Use Map with caution. If the requirements of column or type are not met
// Map should return 'field', since it is the original value that was
// read from the csv input, this would indicate no change.
//
// If struct field is an interface v will be of type string, unless the
// struct field contains a settable pointer value - then v will be a zero
// value of that type.
//
// Map must be set before the first call to Decode and not changed after it.
Map func(field, col string, v interface{}) string
r Reader
typeKey typeKey
hmap map[string]int
header []string
record []string
cache []decField
unused []int
funcMap map[reflect.Type]reflect.Value
ifaceFuncs []reflect.Value
}
// NewDecoder returns a new decoder that reads from r.
//
// Decoder will match struct fields according to the given header.
//
// If header is empty NewDecoder will read one line and treat it as a header.
//
// Records coming from r must be of the same length as the header.
//
// NewDecoder may return io.EOF if there is no data in r and no header was
// provided by the caller.
func NewDecoder(r Reader, header ...string) (dec *Decoder, err error) {
if len(header) == 0 {
header, err = r.Read()
if err != nil {
return nil, err
}
}
h := make([]string, len(header))
copy(h, header)
header = h
m := make(map[string]int, len(header))
for i, h := range header {
m[h] = i
}
return &Decoder{
r: r,
header: header,
hmap: m,
unused: make([]int, 0, len(header)),
}, nil
}
// Decode reads the next string record or records from its input and stores it
// in the value pointed to by v which must be a pointer to a struct, struct slice
// or struct array.
//
// Decode matches all exported struct fields based on the header. Struct fields
// can be adjusted by using tags.
//
// The "omitempty" option specifies that the field should be omitted from
// the decoding if record's field is an empty string.
//
// Examples of struct field tags and their meanings:
// // Decode matches this field with "myName" header column.
// Field int `csv:"myName"`
//
// // Decode matches this field with "Field" header column.
// Field int
//
// // Decode matches this field with "myName" header column and decoding is not
// // called if record's field is an empty string.
// Field int `csv:"myName,omitempty"`
//
// // Decode matches this field with "Field" header column and decoding is not
// // called if record's field is an empty string.
// Field int `csv:",omitempty"`
//
// // Decode ignores this field.
// Field int `csv:"-"`
//
// // Decode treats this field exactly as if it was an embedded field and
// // matches header columns that start with "my_prefix_" to all fields of this
// // type.
// Field Struct `csv:"my_prefix_,inline"`
//
// // Decode treats this field exactly as if it was an embedded field.
// Field Struct `csv:",inline"`
//
// By default decode looks for "csv" tag, but this can be changed by setting
// Decoder.Tag field.
//
// To Decode into a custom type v must implement csvutil.Unmarshaler or
// encoding.TextUnmarshaler.
//
// Anonymous struct fields with tags are treated like normal fields and they
// must implement csvutil.Unmarshaler or encoding.TextUnmarshaler unless inline
// tag is specified.
//
// Anonymous struct fields without tags are populated just as if they were
// part of the main struct. However, fields in the main struct have bigger
// priority and they are populated first. If main struct and anonymous struct
// field have the same fields, the main struct's fields will be populated.
//
// Fields of type []byte expect the data to be base64 encoded strings.
//
// Float fields are decoded to NaN if a string value is 'NaN'. This check
// is case insensitive.
//
// Interface fields are decoded to strings unless they contain settable pointer
// value.
//
// Pointer fields are decoded to nil if a string value is empty.
//
// If v is a slice, Decode resets it and reads the input until EOF, storing all
// decoded values in the given slice. Decode returns nil on EOF.
//
// If v is an array, Decode reads the input until EOF or until it decodes all
// corresponding array elements. If the input contains less elements than the
// array, the additional Go array elements are set to zero values. Decode
// returns nil on EOF unless there were no records decoded.
//
// Fields with inline tags that have a non-empty prefix must not be cyclic
// structures. Passing such values to Decode will result in an infinite loop.
func (d *Decoder) Decode(v interface{}) (err error) {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr || val.IsNil() {
return &InvalidDecodeError{Type: reflect.TypeOf(v)}
}
elem := indirect(val.Elem())
switch elem.Kind() {
case reflect.Struct:
return d.decodeStruct(elem)
case reflect.Slice:
return d.decodeSlice(elem)
case reflect.Array:
return d.decodeArray(elem)
case reflect.Interface, reflect.Invalid:
elem = walkValue(elem)
if elem.Kind() != reflect.Invalid {
return &InvalidDecodeError{Type: elem.Type()}
}
return &InvalidDecodeError{Type: val.Type()}
default:
return &InvalidDecodeError{Type: reflect.PtrTo(elem.Type())}
}
}
// Record returns the most recently read record. The slice is valid until the
// next call to Decode.
func (d *Decoder) Record() []string {
return d.record
}
// Header returns the first line that came from the reader, or returns the
// defined header by the caller.
func (d *Decoder) Header() []string {
header := make([]string, len(d.header))
copy(header, d.header)
return header
}
// Unused returns a list of column indexes that were not used during decoding
// due to lack of matching struct field.
func (d *Decoder) Unused() []int {
if len(d.unused) == 0 {
return nil
}
indices := make([]int, len(d.unused))
copy(indices, d.unused)
return indices
}
// Register registers a custom decoding function for a concrete type or interface.
// The argument f must be of type:
// func([]byte, T) error
//
// T must be a concrete type such as *time.Time, or interface that has at least one
// method.
//
// During decoding, fields are matched by the concrete type first. If match is not
// found then Decoder looks if field implements any of the registered interfaces
// in order they were registered.
//
// Register panics if:
// - f does not match the right signature
// - f is an empty interface
// - f was already registered
//
// Register is based on the encoding/json proposal:
// https://github.com/golang/go/issues/5901.
func (d *Decoder) Register(f interface{}) {
v := reflect.ValueOf(f)
typ := v.Type()
if typ.Kind() != reflect.Func ||
typ.NumIn() != 2 || typ.NumOut() != 1 ||
typ.In(0) != _bytes || typ.Out(0) != _error {
panic("csvutil: func must be of type func([]byte, T) error")
}
argType := typ.In(1)
if argType.Kind() == reflect.Interface && argType.NumMethod() == 0 {
panic("csvutil: func argument type must not be an empty interface")
}
if d.funcMap == nil {
d.funcMap = make(map[reflect.Type]reflect.Value)
}
if _, ok := d.funcMap[argType]; ok {
panic("csvutil: func " + typ.String() + " already registered")
}
d.funcMap[argType] = v
if argType.Kind() == reflect.Interface {
d.ifaceFuncs = append(d.ifaceFuncs, v)
}
}
func (d *Decoder) decodeSlice(slice reflect.Value) error {
typ := slice.Type().Elem()
if walkType(typ).Kind() != reflect.Struct {
return &InvalidDecodeError{Type: reflect.PtrTo(slice.Type())}
}
slice.SetLen(0)
var c int
for ; ; c++ {
v := reflect.New(typ)
err := d.decodeStruct(indirect(v))
if err == io.EOF {
if c == 0 {
return io.EOF
}
break
}
// we want to ensure that we append this element to the slice even if it
// was partially decoded due to error. This is how JSON pkg does it.
slice.Set(reflect.Append(slice, v.Elem()))
if err != nil {
return err
}
}
slice.Set(slice.Slice3(0, c, c))
return nil
}
func (d *Decoder) decodeArray(v reflect.Value) error {
if walkType(v.Type().Elem()).Kind() != reflect.Struct {
return &InvalidDecodeError{Type: reflect.PtrTo(v.Type())}
}
l := v.Len()
var i int
for ; i < l; i++ {
if err := d.decodeStruct(indirect(v.Index(i))); err == io.EOF {
if i == 0 {
return io.EOF
}
break
} else if err != nil {
return err
}
}
zero := reflect.Zero(v.Type().Elem())
for i := i; i < l; i++ {
v.Index(i).Set(zero)
}
return nil
}
func (d *Decoder) decodeStruct(v reflect.Value) (err error) {
d.record, err = d.r.Read()
if err != nil {
return err
}
if len(d.record) != len(d.header) {
return ErrFieldCount
}
return d.unmarshal(d.record, v)
}
func (d *Decoder) unmarshal(record []string, v reflect.Value) error {
fields, err := d.fields(typeKey{d.tag(), v.Type()})
if err != nil {
return err
}
fieldLoop:
for _, f := range fields {
isBlank := record[f.columnIndex] == ""
if f.tag.omitEmpty && isBlank {
continue
}
fv := v
for n, i := range f.index {
fv = fv.Field(i)
if fv.Kind() == reflect.Ptr {
if fv.IsNil() {
if isBlank && n == len(f.index)-1 { // ensure we are on the leaf.
continue fieldLoop
}
// this can happen if a field is an unexported embedded
// pointer type. In Go prior to 1.10 it was possible to
// set such value because of a bug in the reflect package
// https://github.com/golang/go/issues/21353
if !fv.CanSet() {
return errPtrUnexportedStruct(fv.Type())
}
fv.Set(reflect.New(fv.Type().Elem()))
}
if isBlank && n == len(f.index)-1 { // ensure we are on the leaf.
fv.Set(reflect.Zero(fv.Type()))
continue fieldLoop
}
if n != len(f.index)-1 {
fv = fv.Elem() // walk pointer until we are on the the leaf.
}
}
}
s := record[f.columnIndex]
if d.Map != nil && f.zero != nil {
zero := f.zero
if fv := walkPtr(fv); fv.Kind() == reflect.Interface && !fv.IsNil() {
if v := walkValue(fv); v.CanSet() {
zero = reflect.Zero(v.Type()).Interface()
}
}
s = d.Map(s, d.header[f.columnIndex], zero)
}
if err := f.decodeFunc(s, fv); err != nil {
return err
}
}
return nil
}
func (d *Decoder) fields(k typeKey) ([]decField, error) {
if k == d.typeKey {
return d.cache, nil
}
var (
fields = cachedFields(k)
decFields = make([]decField, 0, len(fields))
used = make([]bool, len(d.header))
missingCols []string
)
for _, f := range fields {
i, ok := d.hmap[f.name]
if !ok {
if d.DisallowMissingColumns {
missingCols = append(missingCols, f.name)
}
continue
}
fn, err := decodeFn(f.baseType, d.funcMap, d.ifaceFuncs)
if err != nil {
return nil, err
}
df := decField{
columnIndex: i,
field: f,
decodeFunc: fn,
}
if d.Map != nil {
switch f.typ.Kind() {
case reflect.Interface:
df.zero = "" // interface values are decoded to strings
default:
df.zero = reflect.Zero(walkType(f.typ)).Interface()
}
}
decFields = append(decFields, df)
used[i] = true
}
if len(missingCols) > 0 {
return nil, &MissingColumnsError{
Columns: missingCols,
}
}
d.unused = d.unused[:0]
for i, b := range used {
if !b {
d.unused = append(d.unused, i)
}
}
d.cache, d.typeKey = decFields, k
return d.cache, nil
}
func (d *Decoder) tag() string {
if d.Tag == "" {
return defaultTag
}
return d.Tag
}
func indirect(v reflect.Value) reflect.Value {
for {
switch v.Kind() {
case reflect.Interface:
if v.IsNil() {
return v
}
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() {
v = e
continue
}
return v
case reflect.Ptr:
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
v = v.Elem()
default:
return v
}
}
}

6
vendor/github.com/jszwec/csvutil/doc.go generated vendored Normal file
View File

@@ -0,0 +1,6 @@
// Package csvutil provides fast and idiomatic mapping between CSV and Go values.
//
// This package does not provide a CSV parser itself, it is based on the Reader and Writer
// interfaces which are implemented by eg. std csv package. This gives a possibility
// of choosing any other CSV writer or reader which may be more performant.
package csvutil

245
vendor/github.com/jszwec/csvutil/encode.go generated vendored Normal file
View File

@@ -0,0 +1,245 @@
package csvutil
import (
"encoding"
"encoding/base64"
"reflect"
"strconv"
)
var (
textMarshaler = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
csvMarshaler = reflect.TypeOf((*Marshaler)(nil)).Elem()
)
var (
encodeFloat32 = encodeFloatN(32)
encodeFloat64 = encodeFloatN(64)
)
type encodeFunc func(buf []byte, v reflect.Value, omitempty bool) ([]byte, error)
func encodeFuncValue(fn reflect.Value) encodeFunc {
return func(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
out := fn.Call([]reflect.Value{v})
err, _ := out[1].Interface().(error)
if err != nil {
return nil, err
}
return append(buf, out[0].Bytes()...), nil
}
}
func encodeFuncValuePtr(fn reflect.Value) encodeFunc {
return func(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
if !v.CanAddr() {
fallback, err := encodeFn(v.Type(), false, nil, nil)
if err != nil {
return nil, err
}
return fallback(buf, v, omitempty)
}
out := fn.Call([]reflect.Value{v.Addr()})
err, _ := out[1].Interface().(error)
if err != nil {
return nil, err
}
return append(buf, out[0].Bytes()...), nil
}
}
func encodeString(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
return append(buf, v.String()...), nil
}
func encodeInt(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
n := v.Int()
if n == 0 && omitempty {
return buf, nil
}
return strconv.AppendInt(buf, n, 10), nil
}
func encodeUint(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
n := v.Uint()
if n == 0 && omitempty {
return buf, nil
}
return strconv.AppendUint(buf, n, 10), nil
}
func encodeFloatN(bits int) encodeFunc {
return func(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
f := v.Float()
if f == 0 && omitempty {
return buf, nil
}
return strconv.AppendFloat(buf, f, 'G', -1, bits), nil
}
}
func encodeBool(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
t := v.Bool()
if !t && omitempty {
return buf, nil
}
return strconv.AppendBool(buf, t), nil
}
func encodeInterface(funcMap map[reflect.Type]reflect.Value, funcs []reflect.Value) encodeFunc {
return func(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
if !v.IsValid() || v.IsNil() || !v.Elem().IsValid() {
return buf, nil
}
v = v.Elem()
canAddr := v.Kind() == reflect.Ptr
switch v.Kind() {
case reflect.Ptr, reflect.Interface:
if v.IsNil() {
return buf, nil
}
default:
}
enc, err := encodeFn(v.Type(), canAddr, funcMap, funcs)
if err != nil {
return nil, err
}
return enc(buf, v, omitempty)
}
}
func encodePtrMarshaler(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
if v.CanAddr() {
return encodeMarshaler(buf, v.Addr(), omitempty)
}
fallback, err := encodeFn(v.Type(), false, nil, nil)
if err != nil {
return nil, err
}
return fallback(buf, v, omitempty)
}
func encodeTextMarshaler(buf []byte, v reflect.Value, _ bool) ([]byte, error) {
if v.Kind() == reflect.Ptr && v.IsNil() {
return buf, nil
}
b, err := v.Interface().(encoding.TextMarshaler).MarshalText()
if err != nil {
return nil, &MarshalerError{Type: v.Type(), MarshalerType: "MarshalText", Err: err}
}
return append(buf, b...), nil
}
func encodePtrTextMarshaler(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
if v.CanAddr() {
return encodeTextMarshaler(buf, v.Addr(), omitempty)
}
fallback, err := encodeFn(v.Type(), false, nil, nil)
if err != nil {
return nil, err
}
return fallback(buf, v, omitempty)
}
func encodeMarshaler(buf []byte, v reflect.Value, _ bool) ([]byte, error) {
if v.Kind() == reflect.Ptr && v.IsNil() {
return buf, nil
}
b, err := v.Interface().(Marshaler).MarshalCSV()
if err != nil {
return nil, &MarshalerError{Type: v.Type(), MarshalerType: "MarshalCSV", Err: err}
}
return append(buf, b...), nil
}
func encodePtr(typ reflect.Type, canAddr bool, funcMap map[reflect.Type]reflect.Value, funcs []reflect.Value) (encodeFunc, error) {
next, err := encodeFn(typ.Elem(), canAddr, funcMap, funcs)
if err != nil {
return nil, err
}
return func(buf []byte, v reflect.Value, omitempty bool) ([]byte, error) {
if v.IsNil() {
return buf, nil
}
return next(buf, v.Elem(), omitempty)
}, nil
}
func encodeBytes(buf []byte, v reflect.Value, _ bool) ([]byte, error) {
data := v.Bytes()
l := len(buf)
buf = append(buf, make([]byte, base64.StdEncoding.EncodedLen(len(data)))...)
base64.StdEncoding.Encode(buf[l:], data)
return buf, nil
}
func encodeFn(typ reflect.Type, canAddr bool, funcMap map[reflect.Type]reflect.Value, funcs []reflect.Value) (encodeFunc, error) {
if v, ok := funcMap[typ]; ok {
return encodeFuncValue(v), nil
}
if v, ok := funcMap[reflect.PtrTo(typ)]; ok && canAddr {
return encodeFuncValuePtr(v), nil
}
for _, v := range funcs {
argType := v.Type().In(0)
if typ.AssignableTo(argType) {
return encodeFuncValue(v), nil
}
if canAddr && reflect.PtrTo(typ).AssignableTo(argType) {
return encodeFuncValuePtr(v), nil
}
}
if typ.Implements(csvMarshaler) {
return encodeMarshaler, nil
}
if canAddr && reflect.PtrTo(typ).Implements(csvMarshaler) {
return encodePtrMarshaler, nil
}
if typ.Implements(textMarshaler) {
return encodeTextMarshaler, nil
}
if canAddr && reflect.PtrTo(typ).Implements(textMarshaler) {
return encodePtrTextMarshaler, nil
}
switch typ.Kind() {
case reflect.String:
return encodeString, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return encodeInt, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return encodeUint, nil
case reflect.Float32:
return encodeFloat32, nil
case reflect.Float64:
return encodeFloat64, nil
case reflect.Bool:
return encodeBool, nil
case reflect.Interface:
return encodeInterface(funcMap, funcs), nil
case reflect.Ptr:
return encodePtr(typ, canAddr, funcMap, funcs)
case reflect.Slice:
if typ.Elem().Kind() == reflect.Uint8 {
return encodeBytes, nil
}
}
return nil, &UnsupportedTypeError{Type: typ}
}

356
vendor/github.com/jszwec/csvutil/encoder.go generated vendored Normal file
View File

@@ -0,0 +1,356 @@
package csvutil
import (
"reflect"
)
const defaultBufSize = 4096
type encField struct {
field
encodeFunc
}
type encCache struct {
fields []encField
buf []byte
index []int
record []string
}
func newEncCache(k typeKey, funcMap map[reflect.Type]reflect.Value, funcs []reflect.Value) (_ *encCache, err error) {
fields := cachedFields(k)
encFields := make([]encField, len(fields))
for i, f := range fields {
fn, err := encodeFn(f.baseType, true, funcMap, funcs)
if err != nil {
return nil, err
}
encFields[i] = encField{
field: f,
encodeFunc: fn,
}
}
return &encCache{
fields: encFields,
buf: make([]byte, 0, defaultBufSize),
index: make([]int, len(encFields)),
record: make([]string, len(encFields)),
}, nil
}
// Encoder writes structs CSV representations to the output stream.
type Encoder struct {
// Tag defines which key in the struct field's tag to scan for names and
// options (Default: 'csv').
Tag string
// If AutoHeader is true, a struct header is encoded during the first call
// to Encode automatically (Default: true).
AutoHeader bool
w Writer
c *encCache
noHeader bool
typeKey typeKey
funcMap map[reflect.Type]reflect.Value
ifaceFuncs []reflect.Value
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w Writer) *Encoder {
return &Encoder{
w: w,
noHeader: true,
AutoHeader: true,
}
}
// Register registers a custom encoding function for a concrete type or interface.
// The argument f must be of type:
// func(T) ([]byte, error)
//
// T must be a concrete type such as Foo or *Foo, or interface that has at
// least one method.
//
// During encoding, fields are matched by the concrete type first. If match is not
// found then Encoder looks if field implements any of the registered interfaces
// in order they were registered.
//
// Register panics if:
// - f does not match the right signature
// - f is an empty interface
// - f was already registered
//
// Register is based on the encoding/json proposal:
// https://github.com/golang/go/issues/5901.
func (e *Encoder) Register(f interface{}) {
v := reflect.ValueOf(f)
typ := v.Type()
if typ.Kind() != reflect.Func ||
typ.NumIn() != 1 || typ.NumOut() != 2 ||
typ.Out(0) != _bytes || typ.Out(1) != _error {
panic("csvutil: func must be of type func(T) ([]byte, error)")
}
argType := typ.In(0)
if argType.Kind() == reflect.Interface && argType.NumMethod() == 0 {
panic("csvutil: func argument type must not be an empty interface")
}
if e.funcMap == nil {
e.funcMap = make(map[reflect.Type]reflect.Value)
}
if _, ok := e.funcMap[argType]; ok {
panic("csvutil: func " + typ.String() + " already registered")
}
e.funcMap[argType] = v
if argType.Kind() == reflect.Interface {
e.ifaceFuncs = append(e.ifaceFuncs, v)
}
}
// Encode writes the CSV encoding of v to the output stream. The provided
// argument v must be a struct, struct slice or struct array.
//
// Only the exported fields will be encoded.
//
// First call to Encode will write a header unless EncodeHeader was called first
// or AutoHeader is false. Header names can be customized by using tags
// ('csv' by default), otherwise original Field names are used.
//
// Header and fields are written in the same order as struct fields are defined.
// Embedded struct's fields are treated as if they were part of the outer struct.
// Fields that are embedded types and that are tagged are treated like any
// other field, but they have to implement Marshaler or encoding.TextMarshaler
// interfaces.
//
// Marshaler interface has the priority over encoding.TextMarshaler.
//
// Tagged fields have the priority over non tagged fields with the same name.
//
// Following the Go visibility rules if there are multiple fields with the same
// name (tagged or not tagged) on the same level and choice between them is
// ambiguous, then all these fields will be ignored.
//
// Nil values will be encoded as empty strings. Same will happen if 'omitempty'
// tag is set, and the value is a default value like 0, false or nil interface.
//
// Bool types are encoded as 'true' or 'false'.
//
// Float types are encoded using strconv.FormatFloat with precision -1 and 'G'
// format. NaN values are encoded as 'NaN' string.
//
// Fields of type []byte are being encoded as base64-encoded strings.
//
// Fields can be excluded from encoding by using '-' tag option.
//
// Examples of struct tags:
//
// // Field appears as 'myName' header in CSV encoding.
// Field int `csv:"myName"`
//
// // Field appears as 'Field' header in CSV encoding.
// Field int
//
// // Field appears as 'myName' header in CSV encoding and is an empty string
// // if Field is 0.
// Field int `csv:"myName,omitempty"`
//
// // Field appears as 'Field' header in CSV encoding and is an empty string
// // if Field is 0.
// Field int `csv:",omitempty"`
//
// // Encode ignores this field.
// Field int `csv:"-"`
//
// // Encode treats this field exactly as if it was an embedded field and adds
// // "my_prefix_" to each field's name.
// Field Struct `csv:"my_prefix_,inline"`
//
// // Encode treats this field exactly as if it was an embedded field.
// Field Struct `csv:",inline"`
//
// Fields with inline tags that have a non-empty prefix must not be cyclic
// structures. Passing such values to Encode will result in an infinite loop.
//
// Encode doesn't flush data. The caller is responsible for calling Flush() if
// the used Writer supports it.
func (e *Encoder) Encode(v interface{}) error {
return e.encode(reflect.ValueOf(v))
}
// EncodeHeader writes the CSV header of the provided struct value to the output
// stream. The provided argument v must be a struct value.
//
// The first Encode method call will not write header if EncodeHeader was called
// before it. This method can be called in cases when a data set could be
// empty, but header is desired.
//
// EncodeHeader is like Header function, but it works with the Encoder and writes
// directly to the output stream. Look at Header documentation for the exact
// header encoding rules.
func (e *Encoder) EncodeHeader(v interface{}) error {
typ, err := valueType(v)
if err != nil {
return err
}
return e.encodeHeader(typ)
}
func (e *Encoder) encode(v reflect.Value) error {
val := walkValue(v)
if !val.IsValid() {
return &InvalidEncodeError{}
}
switch val.Kind() {
case reflect.Struct:
return e.encodeStruct(val)
case reflect.Array, reflect.Slice:
if walkType(val.Type().Elem()).Kind() != reflect.Struct {
return &InvalidEncodeError{v.Type()}
}
return e.encodeArray(val)
default:
return &InvalidEncodeError{v.Type()}
}
}
func (e *Encoder) encodeStruct(v reflect.Value) error {
if e.AutoHeader && e.noHeader {
if err := e.encodeHeader(v.Type()); err != nil {
return err
}
}
return e.marshal(v)
}
func (e *Encoder) encodeArray(v reflect.Value) error {
l := v.Len()
for i := 0; i < l; i++ {
if err := e.encodeStruct(walkValue(v.Index(i))); err != nil {
return err
}
}
return nil
}
func (e *Encoder) encodeHeader(typ reflect.Type) error {
fields, _, _, record, err := e.cache(typ)
if err != nil {
return err
}
for i, f := range fields {
record[i] = f.name
}
if err := e.w.Write(record); err != nil {
return err
}
e.noHeader = false
return nil
}
func (e *Encoder) marshal(v reflect.Value) error {
fields, buf, index, record, err := e.cache(v.Type())
if err != nil {
return err
}
for i, f := range fields {
v := walkIndex(v, f.index)
omitempty := f.tag.omitEmpty
if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
// We should disable omitempty for pointer and interface values,
// because if it's nil we will automatically encode it as an empty
// string. However, the initialized pointer should not be affected,
// even if it's a default value.
omitempty = false
}
if !v.IsValid() {
index[i] = 0
continue
}
b, err := f.encodeFunc(buf, v, omitempty)
if err != nil {
return err
}
index[i], buf = len(b)-len(buf), b
}
out := string(buf)
for i, n := range index {
record[i], out = out[:n], out[n:]
}
e.c.buf = buf[:0]
return e.w.Write(record)
}
func (e *Encoder) tag() string {
if e.Tag == "" {
return defaultTag
}
return e.Tag
}
func (e *Encoder) cache(typ reflect.Type) ([]encField, []byte, []int, []string, error) {
if k := (typeKey{e.tag(), typ}); k != e.typeKey {
c, err := newEncCache(k, e.funcMap, e.ifaceFuncs)
if err != nil {
return nil, nil, nil, nil, err
}
e.c, e.typeKey = c, k
}
return e.c.fields, e.c.buf[:0], e.c.index, e.c.record, nil
}
func walkIndex(v reflect.Value, index []int) reflect.Value {
for _, i := range index {
v = walkPtr(v)
if !v.IsValid() {
return reflect.Value{}
}
v = v.Field(i)
}
return v
}
func walkPtr(v reflect.Value) reflect.Value {
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
return v
}
func walkValue(v reflect.Value) reflect.Value {
for {
switch v.Kind() {
case reflect.Ptr, reflect.Interface:
v = v.Elem()
default:
return v
}
}
}
func walkType(typ reflect.Type) reflect.Type {
for typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
return typ
}

156
vendor/github.com/jszwec/csvutil/error.go generated vendored Normal file
View File

@@ -0,0 +1,156 @@
package csvutil
import (
"bytes"
"errors"
"fmt"
"reflect"
"strconv"
)
// ErrFieldCount is returned when header's length doesn't match the length of
// the read record.
var ErrFieldCount = errors.New("wrong number of fields in record")
// An UnmarshalTypeError describes a string value that was not appropriate for
// a value of a specific Go type.
type UnmarshalTypeError struct {
Value string // string value
Type reflect.Type // type of Go value it could not be assigned to
}
func (e *UnmarshalTypeError) Error() string {
return "csvutil: cannot unmarshal " + strconv.Quote(e.Value) + " into Go value of type " + e.Type.String()
}
// An UnsupportedTypeError is returned when attempting to encode or decode
// a value of an unsupported type.
type UnsupportedTypeError struct {
Type reflect.Type
}
func (e *UnsupportedTypeError) Error() string {
if e.Type == nil {
return "csvutil: unsupported type: nil"
}
return "csvutil: unsupported type: " + e.Type.String()
}
// An InvalidDecodeError describes an invalid argument passed to Decode.
// (The argument to Decode must be a non-nil struct pointer)
type InvalidDecodeError struct {
Type reflect.Type
}
func (e *InvalidDecodeError) Error() string {
if e.Type == nil {
return "csvutil: Decode(nil)"
}
if e.Type.Kind() != reflect.Ptr {
return "csvutil: Decode(non-pointer " + e.Type.String() + ")"
}
typ := walkType(e.Type)
switch typ.Kind() {
case reflect.Struct:
case reflect.Slice, reflect.Array:
if typ.Elem().Kind() != reflect.Struct {
return "csvutil: Decode(invalid type " + e.Type.String() + ")"
}
default:
return "csvutil: Decode(invalid type " + e.Type.String() + ")"
}
return "csvutil: Decode(nil " + e.Type.String() + ")"
}
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
// (The argument to Unmarshal must be a non-nil slice of structs pointer)
type InvalidUnmarshalError struct {
Type reflect.Type
}
func (e *InvalidUnmarshalError) Error() string {
if e.Type == nil {
return "csvutil: Unmarshal(nil)"
}
if e.Type.Kind() != reflect.Ptr {
return "csvutil: Unmarshal(non-pointer " + e.Type.String() + ")"
}
return "csvutil: Unmarshal(invalid type " + e.Type.String() + ")"
}
// InvalidEncodeError is returned by Encode when the provided value was invalid.
type InvalidEncodeError struct {
Type reflect.Type
}
func (e *InvalidEncodeError) Error() string {
if e.Type == nil {
return "csvutil: Encode(nil)"
}
return "csvutil: Encode(" + e.Type.String() + ")"
}
// InvalidMarshalError is returned by Marshal when the provided value was invalid.
type InvalidMarshalError struct {
Type reflect.Type
}
func (e *InvalidMarshalError) Error() string {
if e.Type == nil {
return "csvutil: Marshal(nil)"
}
if walkType(e.Type).Kind() == reflect.Slice {
return "csvutil: Marshal(non struct slice " + e.Type.String() + ")"
}
if walkType(e.Type).Kind() == reflect.Array {
return "csvutil: Marshal(non struct array " + e.Type.String() + ")"
}
return "csvutil: Marshal(invalid type " + e.Type.String() + ")"
}
// MarshalerError is returned by Encoder when MarshalCSV or MarshalText returned
// an error.
type MarshalerError struct {
Type reflect.Type
MarshalerType string
Err error
}
func (e *MarshalerError) Error() string {
return "csvutil: error calling " + e.MarshalerType + " for type " + e.Type.String() + ": " + e.Err.Error()
}
// Unwrap implements Unwrap interface for errors package in Go1.13+.
func (e *MarshalerError) Unwrap() error {
return e.Err
}
func errPtrUnexportedStruct(typ reflect.Type) error {
return fmt.Errorf("csvutil: cannot decode into a pointer to unexported struct: %s", typ)
}
// MissingColumnsError is returned by Decoder only when DisallowMissingColumns
// option was set to true. It contains a list of all missing columns.
type MissingColumnsError struct {
Columns []string
}
func (e *MissingColumnsError) Error() string {
var b bytes.Buffer
b.WriteString("csvutil: missing columns: ")
for i, c := range e.Columns {
if i > 0 {
b.WriteString(", ")
}
fmt.Fprintf(&b, "%q", c)
}
return b.String()
}

3
vendor/github.com/jszwec/csvutil/go.mod generated vendored Normal file
View File

@@ -0,0 +1,3 @@
module github.com/jszwec/csvutil
go 1.13

29
vendor/github.com/jszwec/csvutil/interface.go generated vendored Normal file
View File

@@ -0,0 +1,29 @@
package csvutil
// Reader provides the interface for reading a single CSV record.
//
// If there is no data left to be read, Read returns (nil, io.EOF).
//
// It is implemented by csv.Reader.
type Reader interface {
Read() ([]string, error)
}
// Writer provides the interface for writing a single CSV record.
//
// It is implemented by csv.Writer.
type Writer interface {
Write([]string) error
}
// Unmarshaler is the interface implemented by types that can unmarshal
// a single record's field description of themselves.
type Unmarshaler interface {
UnmarshalCSV([]byte) error
}
// Marshaler is the interface implemented by types that can marshal themselves
// into valid string.
type Marshaler interface {
MarshalCSV() ([]byte, error)
}

47
vendor/github.com/jszwec/csvutil/tag.go generated vendored Normal file
View File

@@ -0,0 +1,47 @@
package csvutil
import (
"reflect"
"strings"
)
type tag struct {
name string
prefix string
empty bool
omitEmpty bool
ignore bool
inline bool
}
func parseTag(tagname string, field reflect.StructField) (t tag) {
tags := strings.Split(field.Tag.Get(tagname), ",")
if len(tags) == 1 && tags[0] == "" {
t.name = field.Name
t.empty = true
return
}
switch tags[0] {
case "-":
t.ignore = true
return
case "":
t.name = field.Name
default:
t.name = tags[0]
}
for _, tagOpt := range tags[1:] {
switch tagOpt {
case "omitempty":
t.omitEmpty = true
case "inline":
if walkType(field.Type).Kind() == reflect.Struct {
t.inline = true
t.prefix = tags[0]
}
}
}
return
}