├── .github ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── release-drafter.yml └── workflows │ ├── ci.yml │ └── release-drafter.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── README.md ├── README.md.template ├── bool.go ├── bool_test.go ├── convert.go ├── convert_example_test.go ├── convert_recipes_test.go ├── convert_test.go ├── converter.go ├── debug.go ├── example_test.go ├── examples ├── inline_recipes │ └── inline_recipes.go ├── recipes │ └── recipes.go └── usage │ └── usage.go ├── float32.go ├── float32_test.go ├── float64.go ├── float64_test.go ├── go.mod ├── go.sum ├── int.go ├── int16.go ├── int16_test.go ├── int32.go ├── int32_test.go ├── int64.go ├── int64_test.go ├── int8.go ├── int8_test.go ├── int_test.go ├── internal └── testhelpers │ └── helpers.go ├── map.go ├── map_test.go ├── option.go ├── ptr_test.go ├── recipe.go ├── recipe_test.go ├── recipes.go ├── slice.go ├── slice_test.go ├── string.go ├── string_test.go ├── struct.go ├── struct_test.go ├── time.go ├── time_test.go ├── uint.go ├── uint16.go ├── uint16_test.go ├── uint32.go ├── uint32_test.go ├── uint64.go ├── uint64_test.go ├── uint8.go ├── uint8_test.go ├── uint_test.go └── vendor ├── github.com ├── araddon │ └── dateparse │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ └── parseany.go ├── davecgh │ └── go-spew │ │ ├── LICENSE │ │ └── spew │ │ ├── bypass.go │ │ ├── bypasssafe.go │ │ ├── common.go │ │ ├── config.go │ │ ├── doc.go │ │ ├── dump.go │ │ ├── format.go │ │ └── spew.go ├── pmezard │ └── go-difflib │ │ ├── LICENSE │ │ └── difflib │ │ └── difflib.go └── stretchr │ └── testify │ ├── LICENSE │ ├── assert │ ├── assertion_compare.go │ ├── assertion_format.go │ ├── assertion_format.go.tmpl │ ├── assertion_forward.go │ ├── assertion_forward.go.tmpl │ ├── assertion_order.go │ ├── assertions.go │ ├── doc.go │ ├── errors.go │ ├── forward_assertions.go │ └── http_assertions.go │ └── require │ ├── doc.go │ ├── forward_requirements.go │ ├── require.go │ ├── require.go.tmpl │ ├── require_forward.go │ ├── require_forward.go.tmpl │ └── requirements.go ├── gopkg.in └── yaml.v3 │ ├── .travis.yml │ ├── LICENSE │ ├── NOTICE │ ├── README.md │ ├── apic.go │ ├── decode.go │ ├── emitterc.go │ ├── encode.go │ ├── go.mod │ ├── parserc.go │ ├── readerc.go │ ├── resolve.go │ ├── scannerc.go │ ├── sorter.go │ ├── writerc.go │ ├── yaml.go │ ├── yamlh.go │ └── yamlprivateh.go └── modules.txt /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | ## Problem 4 | A short description of the problem this PR is addressing. 5 | 6 | ## Solution 7 | A short description of the chosen method to resolve the problem 8 | with an overview of the logic and implementation details when needed. 9 | 10 | ## Notes 11 | Other notes that you want to share but do not fit into _Problem_ or _Solution_. 12 | 13 | ### Checklist 14 | - [ ] The title starts either with `feat(area)`, `fix(area)`, or `chore(area)` 15 | - `feat` should be used if this pull request implements a new feature 16 | - `fix` should be used if this pull request fixes a bug 17 | - `chore` should be used for maintenance changes 18 | - `area` should be describing the relevant section of the project 19 | - [ ] ran `go mod tidy` 20 | - [ ] ran `go mod vendor` 21 | - [ ] ran `docker run --rm -ti -v $PWD:/workspace -w /workspace eunts/minigo:latest --template -o /workspace/README.md /workspace/README.md.template` 22 | 23 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | open-pull-requests-limit: 10 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | time: "04:00" 9 | commit-message: 10 | prefix: "chore" 11 | labels: 12 | - "dependencies" 13 | - "go" 14 | - "chore" 15 | 16 | - package-ecosystem: "github-actions" 17 | open-pull-requests-limit: 10 18 | directory: "/" 19 | schedule: 20 | interval: "daily" 21 | time: "04:00" 22 | commit-message: 23 | prefix: "chore" 24 | labels: 25 | - "dependencies" 26 | - "github_actions" 27 | - "chore" 28 | 29 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$RESOLVED_VERSION' 2 | tag-template: 'v$RESOLVED_VERSION' 3 | categories: 4 | - title: '🚀 Features' 5 | label: 'feature' 6 | - title: '🐛 Bug Fixes' 7 | label: 'fix' 8 | - title: '🧰 Maintenance' 9 | label: 'chore' 10 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' 11 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. 12 | version-resolver: 13 | major: 14 | labels: 15 | - 'major' 16 | minor: 17 | labels: 18 | - 'minor' 19 | patch: 20 | labels: 21 | - 'patch' 22 | default: patch 23 | autolabeler: 24 | - label: 'feature' 25 | title: 26 | - '/^feat/i' 27 | - '/^feature/i' 28 | - label: 'fix' 29 | title: 30 | - '/^fix/i' 31 | - label: 'chore' 32 | title: 33 | - '/^chore/i' 34 | template: | 35 | ## Changes 36 | 37 | $CHANGES 38 | 39 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | jobs: 5 | golangci-lint: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - 9 | uses: actions/checkout@v4 10 | - 11 | name: Get go.mod details 12 | uses: Eun/go-mod-details@v1.0.6 13 | id: go-mod-details 14 | - 15 | name: Install Go 16 | uses: actions/setup-go@v5 17 | with: 18 | go-version: ${{ steps.go-mod-details.outputs.go_version }} 19 | - 20 | name: lint 21 | continue-on-error: false 22 | uses: golangci/golangci-lint-action@v4.0.0 23 | with: 24 | version: v1.38.0 25 | # Optional: show only new issues if it's a pull request. The default value is `false`. 26 | # only-new-issues: true 27 | 28 | vulns: 29 | name: Vulnerability scanner 30 | runs-on: ubuntu-latest 31 | steps: 32 | - 33 | uses: actions/checkout@v4 34 | - 35 | uses: actions/setup-go@v5 36 | # We cannot use nancy-github-action because it is outdated, so it's better to use the latest 37 | # docker image for the validation 38 | - 39 | name: nancy 40 | run: go list -json -m all | docker run -i sonatypecommunity/nancy:latest 41 | 42 | test: 43 | strategy: 44 | matrix: 45 | go-version: [1.14.x, 1.15.x] 46 | platform: [ubuntu-latest, macos-latest, windows-latest] 47 | runs-on: ${{ matrix.platform }} 48 | steps: 49 | - 50 | name: Install Go 51 | uses: actions/setup-go@v5 52 | with: 53 | go-version: ${{ matrix.go-version }} 54 | - 55 | name: Checkout code 56 | uses: actions/checkout@v4 57 | - 58 | name: Test 59 | run: go test -v -count=1 -coverprofile="coverage-${{ matrix.platform }}-${{ matrix.go-version }}.txt" -covermode=atomic ./... 60 | - 61 | name: Send coverage 62 | uses: shogo82148/actions-goveralls@v1.9.0 63 | with: 64 | path-to-profile: coverage-${{ matrix.platform }}-${{ matrix.go-version }}.txt 65 | flag-name: ${{ matrix.platform }}-${{ matrix.go-version }} 66 | parallel: true 67 | 68 | # notifies that all test jobs are finished. 69 | finish: 70 | needs: test 71 | runs-on: ubuntu-latest 72 | steps: 73 | - uses: shogo82148/actions-goveralls@v1.9.0 74 | with: 75 | parallel-finished: true 76 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | on: 3 | push: 4 | # branches to consider in the event; optional, defaults to all 5 | branches: 6 | - master 7 | jobs: 8 | update_release_draft: 9 | runs-on: ubuntu-latest 10 | steps: 11 | # Drafts your next Release notes as Pull Requests are merged into "master" 12 | - uses: release-drafter/release-drafter@v6 13 | with: 14 | config-name: release-drafter.yml 15 | env: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | /README.md 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Tobias Salzmann 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-convert [![Actions Status](https://github.com/Eun/go-convert/workflows/CI/badge.svg)](https://github.com/Eun/go-convert/actions) [![Coverage Status](https://coveralls.io/repos/github/Eun/go-convert/badge.svg?branch=master)](https://coveralls.io/github/Eun/go-convert?branch=master) [![PkgGoDev](https://img.shields.io/badge/pkg.go.dev-reference-blue)](https://pkg.go.dev/github.com/Eun/go-convert) [![GoDoc](https://godoc.org/github.com/Eun/go-convert?status.svg)](https://godoc.org/github.com/Eun/go-convert) [![go-report](https://goreportcard.com/badge/github.com/Eun/go-convert)](https://goreportcard.com/report/github.com/Eun/go-convert) 2 | Convert a value into another type. 3 | 4 | ```bash 5 | go get -u github.com/Eun/go-convert 6 | ``` 7 | ## Usage 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | 14 | "github.com/Eun/go-convert" 15 | ) 16 | 17 | func main() { 18 | // convert a int to a string 19 | var s string 20 | convert.MustConvert(1, &s) 21 | fmt.Printf("%s\n", s) 22 | 23 | // convert a map into a struct 24 | type User struct { 25 | ID int 26 | Name string 27 | } 28 | var u User 29 | convert.MustConvert(map[string]string{ 30 | "Name": "Joe", 31 | "ID": "10", 32 | }, &u) 33 | fmt.Printf("%#v\n", u) 34 | 35 | // convert Id to int and Groups to []int and keep the rest 36 | m := map[string]interface{}{ 37 | "Id": 0, 38 | "Groups": []int{}, 39 | } 40 | // convert a map into well defined map 41 | convert.MustConvert( 42 | map[string]interface{}{ 43 | "Id": "1", 44 | "Name": "Joe", 45 | "Groups": []string{"3", "6"}, 46 | "Country": "US", 47 | }, 48 | &m, 49 | ) 50 | fmt.Printf("%v\n", m) 51 | 52 | // convert a interface slice into well defined interface slice 53 | // making the first one an integer, the second a string and the third an float 54 | sl := []interface{}{0, "", 0.0} 55 | convert.MustConvert([]string{"1", "2", "3"}, &sl) 56 | fmt.Printf("%v\n", sl) 57 | } 58 | 59 | ``` 60 | 61 | ## Recipe system 62 | _go-convert_ uses a recipe system that defines how and which types should be converted in which type. 63 | A lot of recipes are already builtin (see [recipes.go](recipes.go)), however you can add your own or overwrite the builtin ones. 64 | ```go 65 | package main 66 | 67 | import ( 68 | "fmt" 69 | "strings" 70 | 71 | "github.com/Eun/go-convert" 72 | ) 73 | 74 | type Roles struct { 75 | IsAdmin bool 76 | IsDeveloper bool 77 | } 78 | 79 | type User struct { 80 | ID int 81 | Name string 82 | Roles Roles 83 | } 84 | 85 | func main() { 86 | // this is the data we want to convert 87 | data := map[string]string{ 88 | "id": "10", 89 | "Name": "Joe", 90 | "roles": "AD", // this user is Admin (A) and Developer (D) 91 | } 92 | 93 | // create a converter 94 | conv := convert.New(convert.Options{ 95 | Recipes: convert.MustMakeRecipes( 96 | // convert string into Roles 97 | func(_ convert.Converter, in string, out *Roles) error { 98 | (*out).IsAdmin = false 99 | (*out).IsDeveloper = false 100 | if strings.Contains(in, "A") { 101 | (*out).IsAdmin = true 102 | } 103 | if strings.Contains(in, "D") { 104 | (*out).IsDeveloper = true 105 | } 106 | return nil 107 | }, 108 | ), 109 | }) 110 | 111 | var user User 112 | conv.MustConvert(data, &user) 113 | // user is now an instance of User 114 | fmt.Printf("%#v\n", user) 115 | } 116 | 117 | ``` 118 | 119 | ## Adding inline recipes 120 | You can also add recipes inline by implementing a `ConvertRecipes() []Recipe` function. 121 | Example: 122 | ```go 123 | package main 124 | 125 | import ( 126 | "fmt" 127 | "strings" 128 | 129 | "github.com/Eun/go-convert" 130 | ) 131 | 132 | type Roles struct { 133 | IsAdmin bool 134 | IsDeveloper bool 135 | } 136 | 137 | type User struct { 138 | ID int 139 | Name string 140 | Roles Roles 141 | } 142 | 143 | func (user *User) ConvertRecipes() []convert.Recipe { 144 | return convert.MustMakeRecipes( 145 | // convert string into Roles 146 | func(_ convert.Converter, in string, out *Roles) error { 147 | out.IsAdmin = false 148 | out.IsDeveloper = false 149 | if strings.Contains(in, "A") { 150 | out.IsAdmin = true 151 | } 152 | if strings.Contains(in, "D") { 153 | out.IsDeveloper = true 154 | } 155 | return nil 156 | }, 157 | ) 158 | } 159 | 160 | func main() { 161 | // this is the data we want to convert 162 | data := []map[string]string{ 163 | { 164 | "id": "10", 165 | "Name": "Joe", 166 | "roles": "AD", // this user is Admin (A) and Developer (D) 167 | }, 168 | { 169 | "id": "21", 170 | "Name": "Alice", 171 | "roles": "D", // this user is Developer (D) 172 | }, 173 | } 174 | 175 | var users []User 176 | convert.MustConvert(data, &users) 177 | // users is now an instance of []User 178 | fmt.Printf("%#v\n", users) 179 | } 180 | 181 | ``` 182 | 183 | 184 | ### Notice 185 | This library is using reflection so be aware it might be slow in your usecase. 186 | -------------------------------------------------------------------------------- /README.md.template: -------------------------------------------------------------------------------- 1 | <$ 2 | import ( 3 | "fmt" 4 | "io/ioutil" 5 | ) 6 | func printFile(f string) { 7 | buf, err := ioutil.ReadFile(f) 8 | if err != nil { 9 | panic(err) 10 | } 11 | fmt.Print(string(buf)) 12 | } 13 | $># go-convert [![Actions Status](https://github.com/Eun/go-convert/workflows/CI/badge.svg)](https://github.com/Eun/go-convert/actions) [![Coverage Status](https://coveralls.io/repos/github/Eun/go-convert/badge.svg?branch=master)](https://coveralls.io/github/Eun/go-convert?branch=master) [![PkgGoDev](https://img.shields.io/badge/pkg.go.dev-reference-blue)](https://pkg.go.dev/github.com/Eun/go-convert) [![GoDoc](https://godoc.org/github.com/Eun/go-convert?status.svg)](https://godoc.org/github.com/Eun/go-convert) [![go-report](https://goreportcard.com/badge/github.com/Eun/go-convert)](https://goreportcard.com/report/github.com/Eun/go-convert) 14 | Convert a value into another type. 15 | 16 | ```bash 17 | go get -u github.com/Eun/go-convert 18 | ``` 19 | ## Usage 20 | ```go 21 | <$ printFile("./examples/usage/usage.go") $> 22 | ``` 23 | 24 | ## Recipe system 25 | _go-convert_ uses a recipe system that defines how and which types should be converted in which type. 26 | A lot of recipes are already builtin (see [recipes.go](recipes.go)), however you can add your own or overwrite the builtin ones. 27 | ```go 28 | <$ printFile("./examples/recipes/recipes.go") $> 29 | ``` 30 | 31 | ## Adding inline recipes 32 | You can also add recipes inline by implementing a `ConvertRecipes() []Recipe` function. 33 | Example: 34 | ```go 35 | <$ printFile("./examples/inline_recipes/inline_recipes.go") $> 36 | ``` 37 | 38 | 39 | ### Notice 40 | This library is using reflection so be aware it might be slow in your usecase. 41 | -------------------------------------------------------------------------------- /bool.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | ) 9 | 10 | func (stdRecipes) nilToBool(Converter, NilValue, *bool) error { 11 | return nil 12 | } 13 | 14 | func (stdRecipes) intToBool(c Converter, in int, out *bool) error { 15 | *out = in != 0 16 | return nil 17 | } 18 | 19 | func (stdRecipes) int8ToBool(c Converter, in int8, out *bool) error { 20 | *out = in != 0 21 | return nil 22 | } 23 | 24 | func (stdRecipes) int16ToBool(c Converter, in int16, out *bool) error { 25 | *out = in != 0 26 | return nil 27 | } 28 | 29 | func (stdRecipes) int32ToBool(c Converter, in int32, out *bool) error { 30 | *out = in != 0 31 | return nil 32 | } 33 | 34 | func (stdRecipes) int64ToBool(_ Converter, in int64, out *bool) error { 35 | *out = in != 0 36 | return nil 37 | } 38 | 39 | func (stdRecipes) uintToBool(c Converter, in uint, out *bool) error { 40 | *out = in != 0 41 | return nil 42 | } 43 | 44 | func (stdRecipes) uint8ToBool(c Converter, in uint8, out *bool) error { 45 | *out = in != 0 46 | return nil 47 | } 48 | 49 | func (stdRecipes) uint16ToBool(c Converter, in uint16, out *bool) error { 50 | *out = in != 0 51 | return nil 52 | } 53 | 54 | func (stdRecipes) uint32ToBool(c Converter, in uint32, out *bool) error { 55 | *out = in != 0 56 | return nil 57 | } 58 | 59 | func (stdRecipes) uint64ToBool(_ Converter, in uint64, out *bool) error { 60 | *out = in != 0 61 | return nil 62 | } 63 | 64 | func (stdRecipes) boolToBool(_ Converter, in bool, out *bool) error { 65 | *out = in 66 | return nil 67 | } 68 | 69 | func (stdRecipes) float32ToBool(_ Converter, in float32, out *bool) error { 70 | *out = in != 0.0 71 | return nil 72 | } 73 | 74 | func (stdRecipes) float64ToBool(_ Converter, in float64, out *bool) error { 75 | *out = in != 0.0 76 | return nil 77 | } 78 | 79 | func (stdRecipes) stringToBool(_ Converter, in string, out *bool) error { 80 | if in == "" { 81 | *out = false 82 | return nil 83 | } 84 | var err error 85 | *out, err = strconv.ParseBool(in) 86 | return err 87 | } 88 | 89 | func (s stdRecipes) structToBool(c Converter, in StructValue, out *bool) error { 90 | err := s.baseStructToBool(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Bool() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToBool(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | func (s stdRecipes) baseStructToBool(_ Converter, in reflect.Value, out *bool) error { 105 | if !in.CanInterface() { 106 | return errors.New("unable to make interface") 107 | } 108 | type toBool interface { 109 | Bool() bool 110 | } 111 | type toBoolWithErr interface { 112 | Bool() (bool, error) 113 | } 114 | 115 | // check for struct.String() 116 | if i, ok := in.Interface().(toBool); ok { 117 | *out = i.Bool() 118 | return nil 119 | } 120 | if i, ok := in.Interface().(toBoolWithErr); ok { 121 | var err error 122 | *out, err = i.Bool() 123 | return err 124 | } 125 | 126 | return fmt.Errorf("%s has no Bool() function", in.Type().String()) 127 | } 128 | -------------------------------------------------------------------------------- /bool_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Eun/go-convert/internal/testhelpers" 7 | ) 8 | 9 | type SomeStructWithBoolFunc struct{} 10 | 11 | func (SomeStructWithBoolFunc) Bool() bool { 12 | return true 13 | } 14 | 15 | type SomeStructWithBoolFuncPtr struct{} 16 | 17 | func (*SomeStructWithBoolFuncPtr) Bool() bool { 18 | return true 19 | } 20 | 21 | type SomeStructWithBoolErrFunc struct{} 22 | 23 | func (SomeStructWithBoolErrFunc) Bool() (bool, error) { 24 | return true, nil 25 | } 26 | 27 | type SomeStructWithBoolErrFuncPtr struct{} 28 | 29 | func (*SomeStructWithBoolErrFuncPtr) Bool() (bool, error) { 30 | return true, nil 31 | } 32 | 33 | func TestBool(t *testing.T) { 34 | tests := []testhelpers.TestCase{ 35 | // nil 36 | {nil, false, false, "", nil}, 37 | // string 38 | {"true", false, true, "", nil}, 39 | {"Hello World", false, false, `unable to convert string to bool: strconv.ParseBool: parsing "Hello World": invalid syntax`, nil}, 40 | {"", false, false, "", nil}, 41 | // bool 42 | {true, false, true, "", nil}, 43 | {false, false, false, "", nil}, 44 | // int 45 | {6, false, true, "", nil}, 46 | // int8 47 | {int8(6), false, true, "", nil}, 48 | // int16 49 | {int16(6), false, true, "", nil}, 50 | // int32 51 | {int32(6), false, true, "", nil}, 52 | // int64 53 | {int64(6), false, true, "", nil}, 54 | // uint 55 | {uint(6), false, true, "", nil}, 56 | // uint8 57 | {uint8(6), false, true, "", nil}, 58 | // uint16 59 | {uint16(6), false, true, "", nil}, 60 | // uint32 61 | {uint32(6), false, true, "", nil}, 62 | // uint64 63 | {uint64(6), false, true, "", nil}, 64 | // float32 65 | {float32(6), false, true, "", nil}, 66 | // float64 67 | {float64(6), false, true, "", nil}, 68 | // slice 69 | {[]int{'H', 'e', 'l', 'l', 'o'}, false, false, "unable to convert []int to bool: no recipe", nil}, 70 | {[]byte{'H', 'e', 'l', 'l', 'o'}, false, false, "unable to convert []uint8 to bool: no recipe", nil}, 71 | {[]rune{'H', 'e', 'l', 'l', 'o'}, false, false, "unable to convert []int32 to bool: no recipe", nil}, 72 | {[]string{"H", "e", "l", "l", "o"}, false, false, "unable to convert []string to bool: no recipe", nil}, 73 | // struct 74 | {struct{}{}, false, false, "unable to convert struct {} to bool: struct {} has no Bool() function", nil}, 75 | 76 | {SomeStructWithBoolFunc{}, false, true, "", nil}, 77 | {&SomeStructWithBoolFunc{}, false, true, "", nil}, 78 | 79 | {SomeStructWithBoolFuncPtr{}, false, true, "", nil}, 80 | {&SomeStructWithBoolFuncPtr{}, false, true, "", nil}, 81 | 82 | {SomeStructWithBoolErrFunc{}, false, true, "", nil}, 83 | {&SomeStructWithBoolErrFunc{}, false, true, "", nil}, 84 | 85 | {SomeStructWithBoolErrFuncPtr{}, false, true, "", nil}, 86 | {&SomeStructWithBoolErrFuncPtr{}, false, true, "", nil}, 87 | } 88 | 89 | for i, test := range tests { 90 | testhelpers.RunTest(t, test, i) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /convert_example_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "strings" 7 | 8 | "github.com/Eun/go-convert" 9 | ) 10 | 11 | func ExampleConvert() { 12 | // Convert a map of strings to a struct 13 | 14 | // this is the struct we want to convert to 15 | type User struct { 16 | ID int 17 | Name string 18 | } 19 | 20 | // this is the data we want to convert 21 | data := map[string]string{ 22 | "id": "10", 23 | "Name": "Joe", 24 | } 25 | 26 | var user User 27 | // do the conversion 28 | convert.MustConvert(data, &user) 29 | 30 | fmt.Printf("Hello %s, your ID is %d\n", user.Name, user.ID) 31 | } 32 | 33 | func ExampleNew() { 34 | type Roles struct { 35 | IsAdmin bool 36 | IsDeveloper bool 37 | } 38 | 39 | type User struct { 40 | ID int 41 | Name string 42 | Roles Roles 43 | } 44 | 45 | // this is the data we want to convert 46 | data := map[string]string{ 47 | "id": "10", 48 | "Name": "Joe", 49 | "roles": "AD", // this user is Admin (A) and Developer (D) 50 | } 51 | 52 | // create a converter 53 | conv := convert.New(convert.Options{ 54 | SkipUnknownFields: false, 55 | Recipes: convert.MustMakeRecipes( 56 | // convert string into Roles 57 | func(_ convert.Converter, in string, out *Roles) error { 58 | out.IsAdmin = false 59 | out.IsDeveloper = false 60 | if strings.Contains(in, "A") { 61 | out.IsAdmin = true 62 | } 63 | if strings.Contains(in, "D") { 64 | out.IsDeveloper = true 65 | } 66 | return nil 67 | }, 68 | ), 69 | }) 70 | 71 | var user User 72 | conv.MustConvert(data, &user) 73 | // user is now an instance of User 74 | fmt.Printf("%#v\n", user) 75 | } 76 | -------------------------------------------------------------------------------- /convert_recipes_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Eun/go-convert" 7 | "github.com/Eun/go-convert/internal/testhelpers" 8 | ) 9 | 10 | type StructWithConvertRecipesFunc struct { 11 | str string 12 | } 13 | 14 | func (StructWithConvertRecipesFunc) ConvertRecipes() []convert.Recipe { 15 | return []convert.Recipe{ 16 | convert.MustMakeRecipe(func(_ convert.Converter, in StructWithConvertRecipesFunc, out *string) error { 17 | *out = in.str 18 | return nil 19 | }), 20 | convert.MustMakeRecipe(func(_ convert.Converter, in string, out *StructWithConvertRecipesFunc) error { 21 | out.str = in 22 | return nil 23 | }), 24 | } 25 | } 26 | 27 | type StructWithConvertRecipesFuncPtr struct { 28 | str string 29 | } 30 | 31 | func (*StructWithConvertRecipesFuncPtr) ConvertRecipes() []convert.Recipe { 32 | return []convert.Recipe{ 33 | convert.MustMakeRecipe(func(_ convert.Converter, in StructWithConvertRecipesFuncPtr, out *string) error { 34 | *out = in.str 35 | return nil 36 | }), 37 | convert.MustMakeRecipe(func(_ convert.Converter, in string, out *StructWithConvertRecipesFuncPtr) error { 38 | out.str = in 39 | return nil 40 | }), 41 | } 42 | } 43 | 44 | func TestConvertRecipes(t *testing.T) { 45 | tests := []testhelpers.TestCase{ 46 | {StructWithConvertRecipesFunc{"Hello World"}, "", "Hello World", "", nil}, 47 | {&StructWithConvertRecipesFunc{"Hello World"}, "", "Hello World", "", nil}, 48 | {StructWithConvertRecipesFuncPtr{"Hello World"}, "", "Hello World", "", nil}, 49 | {&StructWithConvertRecipesFuncPtr{"Hello World"}, "", "Hello World", "", nil}, 50 | 51 | {"Hello World", StructWithConvertRecipesFunc{}, StructWithConvertRecipesFunc{"Hello World"}, "", nil}, 52 | {"Hello World", &StructWithConvertRecipesFunc{}, &StructWithConvertRecipesFunc{"Hello World"}, "", nil}, 53 | {"Hello World", StructWithConvertRecipesFuncPtr{}, StructWithConvertRecipesFuncPtr{"Hello World"}, "", nil}, 54 | {"Hello World", &StructWithConvertRecipesFuncPtr{}, &StructWithConvertRecipesFuncPtr{"Hello World"}, "", nil}, 55 | } 56 | 57 | for i, test := range tests { 58 | testhelpers.RunTest(t, test, i) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /convert_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "strconv" 7 | 8 | "time" 9 | 10 | "github.com/Eun/go-convert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestEdgeCases(t *testing.T) { 15 | t.Run("nil destination", func(t *testing.T) { 16 | err := convert.Convert(0, nil) 17 | require.EqualError(t, err, `destination type cannot be nil`) 18 | }) 19 | 20 | t.Run("interface destination", func(t *testing.T) { 21 | t.Run("string interface", func(t *testing.T) { 22 | var dst interface{} = "" 23 | 24 | err := convert.Convert("Hello World", &dst) 25 | require.NoError(t, err) 26 | require.Equal(t, "Hello World", dst) 27 | }) 28 | t.Run("nil interface", func(t *testing.T) { 29 | var dst interface{} 30 | 31 | err := convert.Convert("Hello World", &dst) 32 | require.NoError(t, err) 33 | require.Equal(t, "Hello World", dst) 34 | }) 35 | }) 36 | t.Run("to ptr", func(t *testing.T) { 37 | t.Run("nil", func(t *testing.T) { 38 | var dst *string 39 | err := convert.Convert("Hello World", &dst) 40 | require.NoError(t, err) 41 | require.Equal(t, "Hello World", *dst) 42 | }) 43 | 44 | t.Run("preset value", func(t *testing.T) { 45 | d := "Good Bye" 46 | dst := &d 47 | err := convert.Convert("Hello World", &dst) 48 | require.NoError(t, err) 49 | require.Equal(t, "Hello World", *dst) 50 | }) 51 | }) 52 | } 53 | 54 | func TestSimpleString(t *testing.T) { 55 | var s string 56 | convert.MustConvert(123, &s) 57 | require.Equal(t, "123", s) 58 | } 59 | 60 | func TestAddNewRecipe(t *testing.T) { 61 | var s string 62 | require.NoError(t, convert.Convert(10, &s, convert.Options{ 63 | SkipUnknownFields: false, 64 | Recipes: []convert.Recipe{ 65 | convert.MustMakeRecipe(func(_ convert.Converter, in int, out *string) error { 66 | *out = strconv.FormatInt(int64(in), 16) 67 | return nil 68 | }), 69 | }, 70 | })) 71 | require.Equal(t, "a", s) 72 | } 73 | 74 | func TestAddNewRecipeForGeneric(t *testing.T) { 75 | var s string 76 | require.NoError(t, convert.Convert(time.Time{}, &s, convert.Options{ 77 | SkipUnknownFields: false, 78 | Recipes: []convert.Recipe{ 79 | convert.MustMakeRecipe(func(c convert.Converter, in convert.StructValue, out *string) error { 80 | require.Fail(t, "Should not be called") 81 | return nil 82 | }), 83 | }, 84 | })) 85 | require.Equal(t, "0001-01-01 00:00:00 +0000 UTC", s) 86 | 87 | require.NoError(t, convert.Convert(struct { 88 | Name string 89 | }{ 90 | Name: "Joe", 91 | }, &s, convert.Options{ 92 | SkipUnknownFields: false, 93 | Recipes: []convert.Recipe{ 94 | convert.MustMakeRecipe(func(c convert.Converter, in convert.StructValue, out *string) error { 95 | *out = "I got you" 96 | return nil 97 | }), 98 | }, 99 | })) 100 | require.Equal(t, "I got you", s) 101 | } 102 | 103 | func TestConvertNilToNil(t *testing.T) { 104 | var nilValue interface{} = nil 105 | require.NoError(t, convert.Convert(nil, &nilValue)) 106 | require.Nil(t, nilValue) 107 | } 108 | -------------------------------------------------------------------------------- /converter.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // NilValue represents a nil value to convert (from/to) 8 | type NilValue struct { 9 | reflect.Value 10 | } 11 | 12 | // MapValue represents a map value to convert (from/to) 13 | type MapValue struct { 14 | reflect.Value 15 | } 16 | 17 | // StructValue represents a struct value to convert (from/to) 18 | type StructValue struct { 19 | reflect.Value 20 | } 21 | 22 | // SliceValue represents a slice value to convert (from/to) 23 | type SliceValue struct { 24 | reflect.Value 25 | } 26 | 27 | // NilType can be used to specify a recipe with the source/destination with a nil value 28 | var NilType = reflect.TypeOf((*NilValue)(nil)).Elem() 29 | 30 | // MapType can be used to specify a recipe with the source/destination with a map type 31 | var MapType = reflect.TypeOf((*MapValue)(nil)).Elem() 32 | 33 | // StructType can be used to specify a recipe with the source/destination with a struct type 34 | var StructType = reflect.TypeOf((*StructValue)(nil)).Elem() 35 | 36 | // SliceType can be used to specify a recipe with the source/destination with a slice type 37 | var SliceType = reflect.TypeOf((*SliceValue)(nil)).Elem() 38 | 39 | // Converter is the instance that will be used to convert values 40 | type Converter interface { 41 | Options() *Options 42 | Convert(src, dst interface{}, options ...Options) error 43 | MustConvert(src, dst interface{}, options ...Options) 44 | ConvertReflectValue(src, dst reflect.Value, options ...Options) error 45 | MustConvertReflectValue(src, dst reflect.Value, options ...Options) 46 | } 47 | 48 | func isGenericType(t reflect.Type) bool { 49 | switch t { 50 | case NilType: 51 | return true 52 | case MapType: 53 | return true 54 | case StructType: 55 | return true 56 | case SliceType: 57 | return true 58 | } 59 | return false 60 | } 61 | 62 | func getGenericWrapper(v reflect.Type) (wrapParam, bool) { 63 | switch v { 64 | case NilType: 65 | return func(value reflect.Value) reflect.Value { 66 | return reflect.ValueOf(NilValue{value}) 67 | }, true 68 | case MapType: 69 | return func(value reflect.Value) reflect.Value { 70 | return reflect.ValueOf(MapValue{value}) 71 | }, true 72 | case StructType: 73 | return func(value reflect.Value) reflect.Value { 74 | return reflect.ValueOf(StructValue{value}) 75 | }, true 76 | case SliceType: 77 | return func(value reflect.Value) reflect.Value { 78 | return reflect.ValueOf(SliceValue{value}) 79 | }, true 80 | } 81 | return func(value reflect.Value) reflect.Value { 82 | return value 83 | }, false 84 | } 85 | -------------------------------------------------------------------------------- /debug.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | var debug = func(format string, a ...interface{}) {} 10 | var debug2 = func(format string, a ...interface{}) {} 11 | 12 | func init() { 13 | if strings.Contains(os.Getenv("GODEBUG"), "go.convert=1") { 14 | debug = func(format string, a ...interface{}) { 15 | fmt.Fprintf(os.Stdout, format, a...) 16 | } 17 | } 18 | if strings.Contains(os.Getenv("GODEBUG"), "go.convert=2") { 19 | debug = func(format string, a ...interface{}) { 20 | fmt.Fprintf(os.Stdout, format, a...) 21 | } 22 | debug2 = func(format string, a ...interface{}) { 23 | fmt.Fprintf(os.Stdout, format, a...) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import "testing" 4 | 5 | func TestExamples(t *testing.T) { 6 | ExampleConvert() 7 | ExampleNew() 8 | } 9 | -------------------------------------------------------------------------------- /examples/inline_recipes/inline_recipes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/Eun/go-convert" 8 | ) 9 | 10 | type Roles struct { 11 | IsAdmin bool 12 | IsDeveloper bool 13 | } 14 | 15 | type User struct { 16 | ID int 17 | Name string 18 | Roles Roles 19 | } 20 | 21 | func (user *User) ConvertRecipes() []convert.Recipe { 22 | return convert.MustMakeRecipes( 23 | // convert string into Roles 24 | func(_ convert.Converter, in string, out *Roles) error { 25 | out.IsAdmin = false 26 | out.IsDeveloper = false 27 | if strings.Contains(in, "A") { 28 | out.IsAdmin = true 29 | } 30 | if strings.Contains(in, "D") { 31 | out.IsDeveloper = true 32 | } 33 | return nil 34 | }, 35 | ) 36 | } 37 | 38 | func main() { 39 | // this is the data we want to convert 40 | data := []map[string]string{ 41 | { 42 | "id": "10", 43 | "Name": "Joe", 44 | "roles": "AD", // this user is Admin (A) and Developer (D) 45 | }, 46 | { 47 | "id": "21", 48 | "Name": "Alice", 49 | "roles": "D", // this user is Developer (D) 50 | }, 51 | } 52 | 53 | var users []User 54 | convert.MustConvert(data, &users) 55 | // users is now an instance of []User 56 | fmt.Printf("%#v\n", users) 57 | } 58 | -------------------------------------------------------------------------------- /examples/recipes/recipes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/Eun/go-convert" 8 | ) 9 | 10 | type Roles struct { 11 | IsAdmin bool 12 | IsDeveloper bool 13 | } 14 | 15 | type User struct { 16 | ID int 17 | Name string 18 | Roles Roles 19 | } 20 | 21 | func main() { 22 | // this is the data we want to convert 23 | data := map[string]string{ 24 | "id": "10", 25 | "Name": "Joe", 26 | "roles": "AD", // this user is Admin (A) and Developer (D) 27 | } 28 | 29 | // create a converter 30 | conv := convert.New(convert.Options{ 31 | Recipes: convert.MustMakeRecipes( 32 | // convert string into Roles 33 | func(_ convert.Converter, in string, out *Roles) error { 34 | (*out).IsAdmin = false 35 | (*out).IsDeveloper = false 36 | if strings.Contains(in, "A") { 37 | (*out).IsAdmin = true 38 | } 39 | if strings.Contains(in, "D") { 40 | (*out).IsDeveloper = true 41 | } 42 | return nil 43 | }, 44 | ), 45 | }) 46 | 47 | var user User 48 | conv.MustConvert(data, &user) 49 | // user is now an instance of User 50 | fmt.Printf("%#v\n", user) 51 | } 52 | -------------------------------------------------------------------------------- /examples/usage/usage.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/Eun/go-convert" 7 | ) 8 | 9 | func main() { 10 | // convert a int to a string 11 | var s string 12 | convert.MustConvert(1, &s) 13 | fmt.Printf("%s\n", s) 14 | 15 | // convert a map into a struct 16 | type User struct { 17 | ID int 18 | Name string 19 | } 20 | var u User 21 | convert.MustConvert(map[string]string{ 22 | "Name": "Joe", 23 | "ID": "10", 24 | }, &u) 25 | fmt.Printf("%#v\n", u) 26 | 27 | // convert Id to int and Groups to []int and keep the rest 28 | m := map[string]interface{}{ 29 | "Id": 0, 30 | "Groups": []int{}, 31 | } 32 | // convert a map into well defined map 33 | convert.MustConvert( 34 | map[string]interface{}{ 35 | "Id": "1", 36 | "Name": "Joe", 37 | "Groups": []string{"3", "6"}, 38 | "Country": "US", 39 | }, 40 | &m, 41 | ) 42 | fmt.Printf("%v\n", m) 43 | 44 | // convert a interface slice into well defined interface slice 45 | // making the first one an integer, the second a string and the third an float 46 | sl := []interface{}{0, "", 0.0} 47 | convert.MustConvert([]string{"1", "2", "3"}, &sl) 48 | fmt.Printf("%v\n", sl) 49 | } 50 | -------------------------------------------------------------------------------- /float32.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToFloat32(Converter, NilValue, *float32) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToFloat32(c Converter, in int, out *float32) error { 15 | *out = float32(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToFloat32(c Converter, in int8, out *float32) error { 19 | *out = float32(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToFloat32(c Converter, in int16, out *float32) error { 23 | *out = float32(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToFloat32(c Converter, in int32, out *float32) error { 27 | *out = float32(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToFloat32(c Converter, in int64, out *float32) error { 31 | *out = float32(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToFloat32(c Converter, in uint, out *float32) error { 35 | *out = float32(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToFloat32(c Converter, in uint8, out *float32) error { 39 | *out = float32(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToFloat32(c Converter, in uint16, out *float32) error { 43 | *out = float32(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToFloat32(c Converter, in uint32, out *float32) error { 47 | *out = float32(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToFloat32(c Converter, in uint64, out *float32) error { 51 | *out = float32(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToFloat32(c Converter, in bool, out *float32) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToFloat32(c Converter, in float32, out *float32) error { 65 | *out = in 66 | return nil 67 | } 68 | func (stdRecipes) float64ToFloat32(c Converter, in float64, out *float32) error { 69 | *out = float32(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToFloat32(c Converter, in string, out *float32) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseFloat(in, 32) 78 | if err != nil { 79 | return err 80 | } 81 | *out = float32(i) 82 | return nil 83 | } 84 | 85 | func (stdRecipes) timeToFloat32(c Converter, in time.Time, out *float32) error { 86 | *out = float32(in.Unix()) 87 | return nil 88 | } 89 | 90 | func (s stdRecipes) structToFloat32(c Converter, in StructValue, out *float32) error { 91 | err := s.baseStructToFloat32(c, in.Value, out) 92 | if err == nil { 93 | return err 94 | } 95 | 96 | // test for *struct.Float32() 97 | v := reflect.New(in.Type()) 98 | v.Elem().Set(in.Value) 99 | if s.baseStructToFloat32(c, v, out) == nil { 100 | return nil 101 | } 102 | return err 103 | } 104 | 105 | type toFloat32 interface { 106 | Float32() float32 107 | } 108 | type toFloat32WithErr interface { 109 | Float32() (float32, error) 110 | } 111 | 112 | func (s stdRecipes) baseStructToFloat32(_ Converter, in reflect.Value, out *float32) error { 113 | if !in.CanInterface() { 114 | return errors.New("unable to make interface") 115 | } 116 | 117 | // check for struct.Float32() 118 | if i, ok := in.Interface().(toFloat32); ok { 119 | *out = i.Float32() 120 | return nil 121 | } 122 | if i, ok := in.Interface().(toFloat32WithErr); ok { 123 | var err error 124 | *out, err = i.Float32() 125 | return err 126 | } 127 | 128 | // check for struct.Float64() 129 | if i, ok := in.Interface().(toFloat64); ok { 130 | *out = float32(i.Float64()) 131 | return nil 132 | } 133 | if i, ok := in.Interface().(toFloat64WithErr); ok { 134 | f, err := i.Float64() 135 | *out = float32(f) 136 | return err 137 | } 138 | 139 | return fmt.Errorf("%s has no Float32() function", in.Type().String()) 140 | } 141 | -------------------------------------------------------------------------------- /float32_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "time" 7 | 8 | "github.com/Eun/go-convert/internal/testhelpers" 9 | ) 10 | 11 | type SomeStructWithFloat32Func struct{} 12 | 13 | func (SomeStructWithFloat32Func) Float32() float32 { 14 | return 10 15 | } 16 | 17 | type SomeStructWithFloat32FuncPtr struct{} 18 | 19 | func (*SomeStructWithFloat32FuncPtr) Float32() float32 { 20 | return 10 21 | } 22 | 23 | type SomeStructWithFloat32WithErrFunc struct{} 24 | 25 | func (SomeStructWithFloat32WithErrFunc) Float32() (float32, error) { 26 | return 10, nil 27 | } 28 | 29 | type SomeStructWithFloat32WithErrFuncPtr struct{} 30 | 31 | func (*SomeStructWithFloat32WithErrFuncPtr) Float32() (float32, error) { 32 | return 10, nil 33 | } 34 | 35 | func TestFloat32(t *testing.T) { 36 | tests := []testhelpers.TestCase{ 37 | // nil 38 | {nil, float32(0), float32(0), "", nil}, 39 | // string 40 | {"3.2", float32(0), float32(3.2), "", nil}, 41 | {"Hello World", float32(0), float32(0), `unable to convert string to float32: strconv.ParseFloat: parsing "Hello World": invalid syntax`, nil}, 42 | {"", float32(0), float32(0), "", nil}, 43 | // bool 44 | {true, float32(0), float32(1), "", nil}, 45 | {false, float32(0), float32(0), "", nil}, 46 | // int 47 | {6, float32(0), float32(6), "", nil}, 48 | // int8 49 | {int8(6), float32(0), float32(6), "", nil}, 50 | // int16 51 | {int16(6), float32(0), float32(6), "", nil}, 52 | // int32 53 | {int32(6), float32(0), float32(6), "", nil}, 54 | // int64 55 | {int64(6), float32(0), float32(6), "", nil}, 56 | // uint 57 | {uint(6), float32(0), float32(6), "", nil}, 58 | // uint8 59 | {uint8(6), float32(0), float32(6), "", nil}, 60 | // uint16 61 | {uint16(6), float32(0), float32(6), "", nil}, 62 | // uint32 63 | {uint32(6), float32(0), float32(6), "", nil}, 64 | // uint64 65 | {uint64(6), float32(0), float32(6), "", nil}, 66 | // float32 67 | {float32(6), float32(0), float32(6), "", nil}, 68 | // float64 69 | {float64(6), float32(0), float32(6), "", nil}, 70 | // slice 71 | {[]int{'H', 'e', 'l', 'l', 'o'}, float32(0), float32(0), "unable to convert []int to float32: no recipe", nil}, 72 | {[]byte{'H', 'e', 'l', 'l', 'o'}, float32(0), float32(0), "unable to convert []uint8 to float32: no recipe", nil}, 73 | {[]rune{'H', 'e', 'l', 'l', 'o'}, float32(0), float32(0), "unable to convert []int32 to float32: no recipe", nil}, 74 | {[]string{"H", "e", "l", "l", "o"}, float32(0), float32(0), "unable to convert []string to float32: no recipe", nil}, 75 | // struct 76 | {struct{}{}, float32(0), float32(0), "unable to convert struct {} to float32: struct {} has no Float32() function", nil}, 77 | // time 78 | {time.Unix(10, 10), float32(10), float32(10), "", nil}, 79 | 80 | {SomeStructWithFloat32Func{}, float32(0), float32(10), "", nil}, 81 | {&SomeStructWithFloat32Func{}, float32(0), float32(10), "", nil}, 82 | 83 | {SomeStructWithFloat32FuncPtr{}, float32(0), float32(10), "", nil}, 84 | {&SomeStructWithFloat32FuncPtr{}, float32(0), float32(10), "", nil}, 85 | 86 | {SomeStructWithFloat32WithErrFunc{}, float32(0), float32(10), "", nil}, 87 | {&SomeStructWithFloat32WithErrFunc{}, float32(0), float32(10), "", nil}, 88 | 89 | {SomeStructWithFloat32WithErrFuncPtr{}, float32(0), float32(10), "", nil}, 90 | {&SomeStructWithFloat32WithErrFuncPtr{}, float32(0), float32(10), "", nil}, 91 | 92 | {SomeStructWithFloat64Func{}, float32(0), float32(10), "", nil}, 93 | {&SomeStructWithFloat64Func{}, float32(0), float32(10), "", nil}, 94 | 95 | {SomeStructWithFloat64FuncPtr{}, float32(0), float32(10), "", nil}, 96 | {&SomeStructWithFloat64FuncPtr{}, float32(0), float32(10), "", nil}, 97 | 98 | {SomeStructWithFloat64WithErrFunc{}, float32(0), float32(10), "", nil}, 99 | {&SomeStructWithFloat64WithErrFunc{}, float32(0), float32(10), "", nil}, 100 | 101 | {SomeStructWithFloat64WithErrFuncPtr{}, float32(0), float32(10), "", nil}, 102 | {&SomeStructWithFloat64WithErrFuncPtr{}, float32(0), float32(10), "", nil}, 103 | } 104 | 105 | for i, test := range tests { 106 | testhelpers.RunTest(t, test, i) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /float64.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToFloat64(Converter, NilValue, *float64) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToFloat64(c Converter, in int, out *float64) error { 15 | *out = float64(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToFloat64(c Converter, in int8, out *float64) error { 19 | *out = float64(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToFloat64(c Converter, in int16, out *float64) error { 23 | *out = float64(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToFloat64(c Converter, in int32, out *float64) error { 27 | *out = float64(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToFloat64(c Converter, in int64, out *float64) error { 31 | *out = float64(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToFloat64(c Converter, in uint, out *float64) error { 35 | *out = float64(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToFloat64(c Converter, in uint8, out *float64) error { 39 | *out = float64(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToFloat64(c Converter, in uint16, out *float64) error { 43 | *out = float64(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToFloat64(c Converter, in uint32, out *float64) error { 47 | *out = float64(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToFloat64(c Converter, in uint64, out *float64) error { 51 | *out = float64(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToFloat64(c Converter, in bool, out *float64) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToFloat64(c Converter, in float32, out *float64) error { 65 | *out = float64(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToFloat64(c Converter, in float64, out *float64) error { 69 | *out = in 70 | return nil 71 | } 72 | func (stdRecipes) stringToFloat64(c Converter, in string, out *float64) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseFloat(in, 64) 78 | if err != nil { 79 | return err 80 | } 81 | *out = i 82 | return nil 83 | } 84 | 85 | func (stdRecipes) timeToFloat64(c Converter, in time.Time, out *float64) error { 86 | *out = float64(in.Unix()) + float64(in.Nanosecond())/1000000000 87 | return nil 88 | } 89 | 90 | func (s stdRecipes) structToFloat64(c Converter, in StructValue, out *float64) error { 91 | err := s.baseStructToFloat64(c, in.Value, out) 92 | if err == nil { 93 | return err 94 | } 95 | 96 | // test for *struct.Float64() 97 | v := reflect.New(in.Type()) 98 | v.Elem().Set(in.Value) 99 | if s.baseStructToFloat64(c, v, out) == nil { 100 | return nil 101 | } 102 | return err 103 | } 104 | 105 | type toFloat64 interface { 106 | Float64() float64 107 | } 108 | type toFloat64WithErr interface { 109 | Float64() (float64, error) 110 | } 111 | 112 | func (s stdRecipes) baseStructToFloat64(_ Converter, in reflect.Value, out *float64) error { 113 | if !in.CanInterface() { 114 | return errors.New("unable to make interface") 115 | } 116 | 117 | // check for struct.Float64() 118 | if i, ok := in.Interface().(toFloat64); ok { 119 | *out = i.Float64() 120 | return nil 121 | } 122 | if i, ok := in.Interface().(toFloat64WithErr); ok { 123 | var err error 124 | *out, err = i.Float64() 125 | return err 126 | } 127 | 128 | // check for struct.Float32() 129 | if i, ok := in.Interface().(toFloat32); ok { 130 | *out = float64(i.Float32()) 131 | return nil 132 | } 133 | if i, ok := in.Interface().(toFloat32WithErr); ok { 134 | f, err := i.Float32() 135 | *out = float64(f) 136 | return err 137 | } 138 | 139 | return fmt.Errorf("%s has no Float64() function", in.Type().String()) 140 | } 141 | -------------------------------------------------------------------------------- /float64_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "time" 7 | 8 | "github.com/Eun/go-convert/internal/testhelpers" 9 | ) 10 | 11 | type SomeStructWithFloat64Func struct{} 12 | 13 | func (SomeStructWithFloat64Func) Float64() float64 { 14 | return 10 15 | } 16 | 17 | type SomeStructWithFloat64FuncPtr struct{} 18 | 19 | func (*SomeStructWithFloat64FuncPtr) Float64() float64 { 20 | return 10 21 | } 22 | 23 | type SomeStructWithFloat64WithErrFunc struct{} 24 | 25 | func (SomeStructWithFloat64WithErrFunc) Float64() (float64, error) { 26 | return 10, nil 27 | } 28 | 29 | type SomeStructWithFloat64WithErrFuncPtr struct{} 30 | 31 | func (*SomeStructWithFloat64WithErrFuncPtr) Float64() (float64, error) { 32 | return 10, nil 33 | } 34 | 35 | func TestFloat64(t *testing.T) { 36 | tests := []testhelpers.TestCase{ 37 | // nil 38 | {nil, float64(0), float64(0), "", nil}, 39 | // string 40 | {"3.2", float64(0), float64(3.2), "", nil}, 41 | {"Hello World", float64(0), float64(0), `unable to convert string to float64: strconv.ParseFloat: parsing "Hello World": invalid syntax`, nil}, 42 | {"", float64(0), float64(0), "", nil}, 43 | // bool 44 | {true, float64(0), float64(1), "", nil}, 45 | {false, float64(0), float64(0), "", nil}, 46 | // int 47 | {6, float64(0), float64(6), "", nil}, 48 | // int8 49 | {int8(6), float64(0), float64(6), "", nil}, 50 | // int16 51 | {int16(6), float64(0), float64(6), "", nil}, 52 | // int32 53 | {int32(6), float64(0), float64(6), "", nil}, 54 | // int64 55 | {int64(6), float64(0), float64(6), "", nil}, 56 | // uint 57 | {uint(6), float64(0), float64(6), "", nil}, 58 | // uint8 59 | {uint8(6), float64(0), float64(6), "", nil}, 60 | // uint16 61 | {uint16(6), float64(0), float64(6), "", nil}, 62 | // uint32 63 | {uint32(6), float64(0), float64(6), "", nil}, 64 | // uint64 65 | {uint64(6), float64(0), float64(6), "", nil}, 66 | // float32 67 | {float32(6), float64(0), float64(6), "", nil}, 68 | // float64 69 | {float64(6), float64(0), float64(6), "", nil}, 70 | // slice 71 | {[]int{'H', 'e', 'l', 'l', 'o'}, float64(0), float64(0), "unable to convert []int to float64: no recipe", nil}, 72 | {[]byte{'H', 'e', 'l', 'l', 'o'}, float64(0), float64(0), "unable to convert []uint8 to float64: no recipe", nil}, 73 | {[]rune{'H', 'e', 'l', 'l', 'o'}, float64(0), float64(0), "unable to convert []int32 to float64: no recipe", nil}, 74 | {[]string{"H", "e", "l", "l", "o"}, float64(0), float64(0), "unable to convert []string to float64: no recipe", nil}, 75 | // struct 76 | {struct{}{}, float64(0), float64(0), "unable to convert struct {} to float64: struct {} has no Float64() function", nil}, 77 | // time 78 | {time.Unix(10, 10), float64(10.00000001), float64(10.00000001), "", nil}, 79 | 80 | {SomeStructWithFloat32Func{}, float64(0), float64(10), "", nil}, 81 | {&SomeStructWithFloat32Func{}, float64(0), float64(10), "", nil}, 82 | 83 | {SomeStructWithFloat32FuncPtr{}, float64(0), float64(10), "", nil}, 84 | {&SomeStructWithFloat32FuncPtr{}, float64(0), float64(10), "", nil}, 85 | 86 | {SomeStructWithFloat32WithErrFunc{}, float64(0), float64(10), "", nil}, 87 | {&SomeStructWithFloat32WithErrFunc{}, float64(0), float64(10), "", nil}, 88 | 89 | {SomeStructWithFloat32WithErrFuncPtr{}, float64(0), float64(10), "", nil}, 90 | {&SomeStructWithFloat32WithErrFuncPtr{}, float64(0), float64(10), "", nil}, 91 | 92 | {SomeStructWithFloat64Func{}, float64(0), float64(10), "", nil}, 93 | {&SomeStructWithFloat64Func{}, float64(0), float64(10), "", nil}, 94 | 95 | {SomeStructWithFloat64FuncPtr{}, float64(0), float64(10), "", nil}, 96 | {&SomeStructWithFloat64FuncPtr{}, float64(0), float64(10), "", nil}, 97 | 98 | {SomeStructWithFloat64WithErrFunc{}, float64(0), float64(10), "", nil}, 99 | {&SomeStructWithFloat64WithErrFunc{}, float64(0), float64(10), "", nil}, 100 | 101 | {SomeStructWithFloat64WithErrFuncPtr{}, float64(0), float64(10), "", nil}, 102 | {&SomeStructWithFloat64WithErrFuncPtr{}, float64(0), float64(10), "", nil}, 103 | } 104 | 105 | for i, test := range tests { 106 | testhelpers.RunTest(t, test, i) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Eun/go-convert 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195 7 | github.com/stretchr/testify v1.7.0 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195 h1:c4mLfegoDw6OhSJXTd2jUEQgZUQuJWtocudb97Qn9EM= 2 | github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= 3 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 8 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 9 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 12 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 14 | -------------------------------------------------------------------------------- /int.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToInt(Converter, NilValue, *int) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToInt(c Converter, in int, out *int) error { 15 | *out = in 16 | return nil 17 | } 18 | func (stdRecipes) int8ToInt(c Converter, in int8, out *int) error { 19 | *out = int(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToInt(c Converter, in int16, out *int) error { 23 | *out = int(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToInt(c Converter, in int32, out *int) error { 27 | *out = int(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToInt(c Converter, in int64, out *int) error { 31 | *out = int(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToInt(c Converter, in uint, out *int) error { 35 | *out = int(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToInt(c Converter, in uint8, out *int) error { 39 | *out = int(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToInt(c Converter, in uint16, out *int) error { 43 | *out = int(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToInt(c Converter, in uint32, out *int) error { 47 | *out = int(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToInt(c Converter, in uint64, out *int) error { 51 | *out = int(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToInt(c Converter, in bool, out *int) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToInt(c Converter, in float32, out *int) error { 65 | *out = int(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToInt(c Converter, in float64, out *int) error { 69 | *out = int(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToInt(c Converter, in string, out *int) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseInt(in, 0, 32) 78 | if err != nil { 79 | return err 80 | } 81 | *out = int(i) 82 | return nil 83 | } 84 | func (stdRecipes) timeToInt(c Converter, in time.Time, out *int) error { 85 | *out = int(in.Unix()) 86 | return nil 87 | } 88 | 89 | func (s stdRecipes) structToInt(c Converter, in StructValue, out *int) error { 90 | err := s.baseStructToInt(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Int() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToInt(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | type toInt interface { 105 | Int() int 106 | } 107 | type toIntWithErr interface { 108 | Int() (int, error) 109 | } 110 | 111 | func (s stdRecipes) baseStructToInt(_ Converter, in reflect.Value, out *int) error { 112 | if !in.CanInterface() { 113 | return errors.New("unable to make interface") 114 | } 115 | 116 | // check for struct.Int() 117 | if i, ok := in.Interface().(toInt); ok { 118 | *out = i.Int() 119 | return nil 120 | } 121 | if i, ok := in.Interface().(toIntWithErr); ok { 122 | var err error 123 | *out, err = i.Int() 124 | return err 125 | } 126 | 127 | if ok, i, err := genericIntConvert(in); ok { 128 | if err != nil { 129 | return err 130 | } 131 | *out = int(i) 132 | return nil 133 | } 134 | 135 | return fmt.Errorf("%s has no Int() function", in.Type().String()) 136 | } 137 | 138 | func genericIntConvert(in reflect.Value) (bool, int64, error) { 139 | // check for struct.Int() 140 | if i, ok := in.Interface().(toInt); ok { 141 | return true, int64(i.Int()), nil 142 | } 143 | if i, ok := in.Interface().(toIntWithErr); ok { 144 | v, err := i.Int() 145 | return true, int64(v), err 146 | } 147 | 148 | // check for struct.Int8() 149 | if i, ok := in.Interface().(toInt8); ok { 150 | return true, int64(i.Int8()), nil 151 | } 152 | if i, ok := in.Interface().(toInt8WithErr); ok { 153 | v, err := i.Int8() 154 | return true, int64(v), err 155 | } 156 | 157 | // check for struct.Int16() 158 | if i, ok := in.Interface().(toInt16); ok { 159 | return true, int64(i.Int16()), nil 160 | } 161 | if i, ok := in.Interface().(toInt16WithErr); ok { 162 | v, err := i.Int16() 163 | return true, int64(v), err 164 | } 165 | 166 | // check for struct.Int32() 167 | if i, ok := in.Interface().(toInt32); ok { 168 | return true, int64(i.Int32()), nil 169 | } 170 | if i, ok := in.Interface().(toInt32WithErr); ok { 171 | v, err := i.Int32() 172 | return true, int64(v), err 173 | } 174 | 175 | // check for struct.Int64() 176 | if i, ok := in.Interface().(toInt64); ok { 177 | return true, i.Int64(), nil 178 | } 179 | if i, ok := in.Interface().(toInt64WithErr); ok { 180 | v, err := i.Int64() 181 | return true, v, err 182 | } 183 | 184 | // check for struct.Uint() 185 | if i, ok := in.Interface().(toUint); ok { 186 | return true, int64(i.Uint()), nil 187 | } 188 | if i, ok := in.Interface().(toUintWithErr); ok { 189 | v, err := i.Uint() 190 | return true, int64(v), err 191 | } 192 | 193 | // check for struct.Uint8() 194 | if i, ok := in.Interface().(toUint8); ok { 195 | return true, int64(i.Uint8()), nil 196 | } 197 | if i, ok := in.Interface().(toUint8WithErr); ok { 198 | v, err := i.Uint8() 199 | return true, int64(v), err 200 | } 201 | 202 | // check for struct.Uint16() 203 | if i, ok := in.Interface().(toUint16); ok { 204 | return true, int64(i.Uint16()), nil 205 | } 206 | if i, ok := in.Interface().(toUint16WithErr); ok { 207 | v, err := i.Uint16() 208 | return true, int64(v), err 209 | } 210 | 211 | // check for struct.Uint32() 212 | if i, ok := in.Interface().(toUint32); ok { 213 | return true, int64(i.Uint32()), nil 214 | } 215 | if i, ok := in.Interface().(toUint32WithErr); ok { 216 | v, err := i.Uint32() 217 | return true, int64(v), err 218 | } 219 | // check for struct.Uint64() 220 | if i, ok := in.Interface().(toUint64); ok { 221 | return true, int64(i.Uint64()), nil 222 | } 223 | if i, ok := in.Interface().(toUint64WithErr); ok { 224 | v, err := i.Uint64() 225 | return true, int64(v), err 226 | } 227 | return false, 0, nil 228 | } 229 | -------------------------------------------------------------------------------- /int16.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToInt16(Converter, NilValue, *int16) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToInt16(c Converter, in int, out *int16) error { 15 | *out = int16(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToInt16(c Converter, in int8, out *int16) error { 19 | *out = int16(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToInt16(c Converter, in int16, out *int16) error { 23 | *out = in 24 | return nil 25 | } 26 | func (stdRecipes) int32ToInt16(c Converter, in int32, out *int16) error { 27 | *out = int16(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToInt16(c Converter, in int64, out *int16) error { 31 | *out = int16(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToInt16(c Converter, in uint, out *int16) error { 35 | *out = int16(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToInt16(c Converter, in uint8, out *int16) error { 39 | *out = int16(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToInt16(c Converter, in uint16, out *int16) error { 43 | *out = int16(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToInt16(c Converter, in uint32, out *int16) error { 47 | *out = int16(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToInt16(c Converter, in uint64, out *int16) error { 51 | *out = int16(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToInt16(c Converter, in bool, out *int16) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToInt16(c Converter, in float32, out *int16) error { 65 | *out = int16(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToInt16(c Converter, in float64, out *int16) error { 69 | *out = int16(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToInt16(c Converter, in string, out *int16) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseInt(in, 0, 16) 78 | if err != nil { 79 | return err 80 | } 81 | *out = int16(i) 82 | return nil 83 | } 84 | func (stdRecipes) timeToInt16(c Converter, in time.Time, out *int16) error { 85 | *out = int16(in.Unix()) 86 | return nil 87 | } 88 | 89 | func (s stdRecipes) structToInt16(c Converter, in StructValue, out *int16) error { 90 | err := s.baseStructToInt16(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Int16() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToInt16(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | type toInt16 interface { 105 | Int16() int16 106 | } 107 | type toInt16WithErr interface { 108 | Int16() (int16, error) 109 | } 110 | 111 | func (s stdRecipes) baseStructToInt16(_ Converter, in reflect.Value, out *int16) error { 112 | if !in.CanInterface() { 113 | return errors.New("unable to make interface") 114 | } 115 | 116 | // check for struct.Int16() 117 | if i, ok := in.Interface().(toInt16); ok { 118 | *out = i.Int16() 119 | return nil 120 | } 121 | if i, ok := in.Interface().(toInt16WithErr); ok { 122 | var err error 123 | *out, err = i.Int16() 124 | return err 125 | } 126 | 127 | if ok, i, err := genericIntConvert(in); ok { 128 | if err != nil { 129 | return err 130 | } 131 | *out = int16(i) 132 | return nil 133 | } 134 | 135 | return fmt.Errorf("%s has no Int16() function", in.Type().String()) 136 | } 137 | -------------------------------------------------------------------------------- /int32.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToInt32(Converter, NilValue, *int32) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToInt32(c Converter, in int, out *int32) error { 15 | *out = int32(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToInt32(c Converter, in int8, out *int32) error { 19 | *out = int32(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToInt32(c Converter, in int16, out *int32) error { 23 | *out = int32(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToInt32(c Converter, in int32, out *int32) error { 27 | *out = in 28 | return nil 29 | } 30 | func (stdRecipes) int64ToInt32(c Converter, in int64, out *int32) error { 31 | *out = int32(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToInt32(c Converter, in uint, out *int32) error { 35 | *out = int32(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToInt32(c Converter, in uint8, out *int32) error { 39 | *out = int32(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToInt32(c Converter, in uint16, out *int32) error { 43 | *out = int32(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToInt32(c Converter, in uint32, out *int32) error { 47 | *out = int32(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToInt32(c Converter, in uint64, out *int32) error { 51 | *out = int32(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToInt32(c Converter, in bool, out *int32) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToInt32(c Converter, in float32, out *int32) error { 65 | *out = int32(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToInt32(c Converter, in float64, out *int32) error { 69 | *out = int32(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToInt32(c Converter, in string, out *int32) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseInt(in, 0, 32) 78 | if err != nil { 79 | return err 80 | } 81 | *out = int32(i) 82 | return nil 83 | } 84 | func (stdRecipes) timeToInt32(c Converter, in time.Time, out *int32) error { 85 | *out = int32(in.Unix()) 86 | return nil 87 | } 88 | 89 | func (s stdRecipes) structToInt32(c Converter, in StructValue, out *int32) error { 90 | err := s.baseStructToInt32(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Int32() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToInt32(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | type toInt32 interface { 105 | Int32() int32 106 | } 107 | type toInt32WithErr interface { 108 | Int32() (int32, error) 109 | } 110 | 111 | func (s stdRecipes) baseStructToInt32(_ Converter, in reflect.Value, out *int32) error { 112 | if !in.CanInterface() { 113 | return errors.New("unable to make interface") 114 | } 115 | 116 | // check for struct.Int32() 117 | if i, ok := in.Interface().(toInt32); ok { 118 | *out = i.Int32() 119 | return nil 120 | } 121 | if i, ok := in.Interface().(toInt32WithErr); ok { 122 | var err error 123 | *out, err = i.Int32() 124 | return err 125 | } 126 | 127 | if ok, i, err := genericIntConvert(in); ok { 128 | if err != nil { 129 | return err 130 | } 131 | *out = int32(i) 132 | return nil 133 | } 134 | 135 | return fmt.Errorf("%s has no Int32() function", in.Type().String()) 136 | } 137 | -------------------------------------------------------------------------------- /int64.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToInt64(Converter, NilValue, *int64) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToInt64(c Converter, in int, out *int64) error { 15 | *out = int64(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToInt64(c Converter, in int8, out *int64) error { 19 | *out = int64(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToInt64(c Converter, in int16, out *int64) error { 23 | *out = int64(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToInt64(c Converter, in int32, out *int64) error { 27 | *out = int64(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToInt64(c Converter, in int64, out *int64) error { 31 | *out = in 32 | return nil 33 | } 34 | func (stdRecipes) uintToInt64(c Converter, in uint, out *int64) error { 35 | *out = int64(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToInt64(c Converter, in uint8, out *int64) error { 39 | *out = int64(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToInt64(c Converter, in uint16, out *int64) error { 43 | *out = int64(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToInt64(c Converter, in uint32, out *int64) error { 47 | *out = int64(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToInt64(c Converter, in uint64, out *int64) error { 51 | *out = int64(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToInt64(c Converter, in bool, out *int64) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToInt64(c Converter, in float32, out *int64) error { 65 | *out = int64(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToInt64(c Converter, in float64, out *int64) error { 69 | *out = int64(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToInt64(c Converter, in string, out *int64) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseInt(in, 0, 64) 78 | if err != nil { 79 | return err 80 | } 81 | *out = i 82 | return nil 83 | } 84 | func (stdRecipes) timeToInt64(c Converter, in time.Time, out *int64) error { 85 | *out = in.Unix() 86 | return nil 87 | } 88 | 89 | func (s stdRecipes) structToInt64(c Converter, in StructValue, out *int64) error { 90 | err := s.baseStructToInt64(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Int64() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToInt64(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | type toInt64 interface { 105 | Int64() int64 106 | } 107 | type toInt64WithErr interface { 108 | Int64() (int64, error) 109 | } 110 | 111 | func (s stdRecipes) baseStructToInt64(_ Converter, in reflect.Value, out *int64) error { 112 | if !in.CanInterface() { 113 | return errors.New("unable to make interface") 114 | } 115 | 116 | // check for struct.Int64() 117 | if i, ok := in.Interface().(toInt64); ok { 118 | *out = i.Int64() 119 | return nil 120 | } 121 | if i, ok := in.Interface().(toInt64WithErr); ok { 122 | var err error 123 | *out, err = i.Int64() 124 | return err 125 | } 126 | 127 | if ok, i, err := genericIntConvert(in); ok { 128 | if err != nil { 129 | return err 130 | } 131 | *out = i 132 | return nil 133 | } 134 | 135 | return fmt.Errorf("%s has no Int64() function", in.Type().String()) 136 | } 137 | -------------------------------------------------------------------------------- /int8.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToInt8(Converter, NilValue, *int8) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToInt8(c Converter, in int, out *int8) error { 15 | *out = int8(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToInt8(c Converter, in int8, out *int8) error { 19 | *out = in 20 | return nil 21 | } 22 | func (stdRecipes) int16ToInt8(c Converter, in int16, out *int8) error { 23 | *out = int8(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToInt8(c Converter, in int32, out *int8) error { 27 | *out = int8(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToInt8(c Converter, in int64, out *int8) error { 31 | *out = int8(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToInt8(c Converter, in uint, out *int8) error { 35 | *out = int8(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToInt8(c Converter, in uint8, out *int8) error { 39 | *out = int8(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToInt8(c Converter, in uint16, out *int8) error { 43 | *out = int8(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToInt8(c Converter, in uint32, out *int8) error { 47 | *out = int8(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToInt8(c Converter, in uint64, out *int8) error { 51 | *out = int8(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToInt8(c Converter, in bool, out *int8) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToInt8(c Converter, in float32, out *int8) error { 65 | *out = int8(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToInt8(c Converter, in float64, out *int8) error { 69 | *out = int8(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToInt8(c Converter, in string, out *int8) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseInt(in, 0, 8) 78 | if err != nil { 79 | return err 80 | } 81 | *out = int8(i) 82 | return nil 83 | } 84 | func (stdRecipes) timeToInt8(c Converter, in time.Time, out *int8) error { 85 | *out = int8(in.Unix()) 86 | return nil 87 | } 88 | 89 | func (s stdRecipes) structToInt8(c Converter, in StructValue, out *int8) error { 90 | err := s.baseStructToInt8(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Int8() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToInt8(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | type toInt8 interface { 105 | Int8() int8 106 | } 107 | type toInt8WithErr interface { 108 | Int8() (int8, error) 109 | } 110 | 111 | func (s stdRecipes) baseStructToInt8(_ Converter, in reflect.Value, out *int8) error { 112 | if !in.CanInterface() { 113 | return errors.New("unable to make interface") 114 | } 115 | 116 | // check for struct.Int8() 117 | if i, ok := in.Interface().(toInt8); ok { 118 | *out = i.Int8() 119 | return nil 120 | } 121 | if i, ok := in.Interface().(toInt8WithErr); ok { 122 | var err error 123 | *out, err = i.Int8() 124 | return err 125 | } 126 | 127 | if ok, i, err := genericIntConvert(in); ok { 128 | if err != nil { 129 | return err 130 | } 131 | *out = int8(i) 132 | return nil 133 | } 134 | 135 | return fmt.Errorf("%s has no Int8() function", in.Type().String()) 136 | } 137 | -------------------------------------------------------------------------------- /int8_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "time" 7 | 8 | "github.com/Eun/go-convert/internal/testhelpers" 9 | ) 10 | 11 | type SomeStructWithInt8Func struct{} 12 | 13 | func (SomeStructWithInt8Func) Int8() int8 { 14 | return 8 15 | } 16 | 17 | type SomeStructWithInt8FuncPtr struct{} 18 | 19 | func (*SomeStructWithInt8FuncPtr) Int8() int8 { 20 | return 8 21 | } 22 | 23 | type SomeStructWithInt8WithErrFunc struct{} 24 | 25 | func (SomeStructWithInt8WithErrFunc) Int8() (int8, error) { 26 | return 8, nil 27 | } 28 | 29 | type SomeStructWithInt8WithErrFuncPtr struct{} 30 | 31 | func (*SomeStructWithInt8WithErrFuncPtr) Int8() (int8, error) { 32 | return 8, nil 33 | } 34 | 35 | func TestInt8(t *testing.T) { 36 | tests := []testhelpers.TestCase{ 37 | // nil 38 | {nil, int8(0), int8(0), "", nil}, 39 | // string 40 | {"6", int8(0), int8(6), "", nil}, 41 | {"", int8(0), int8(0), "", nil}, 42 | {"Hello World", int8(0), int8(0), `unable to convert string to int8: strconv.ParseInt: parsing "Hello World": invalid syntax`, nil}, 43 | // bool 44 | {true, int8(0), int8(1), "", nil}, 45 | {false, int8(0), int8(0), "", nil}, 46 | // int 47 | {6, int8(0), int8(6), "", nil}, 48 | // int8 49 | {int8(6), int8(0), int8(6), "", nil}, 50 | // int16 51 | {int16(6), int8(0), int8(6), "", nil}, 52 | // int32 53 | {int32(6), int8(0), int8(6), "", nil}, 54 | // int64 55 | {int64(6), int8(0), int8(6), "", nil}, 56 | // uint 57 | {uint(6), int8(0), int8(6), "", nil}, 58 | // uint8 59 | {uint8(6), int8(0), int8(6), "", nil}, 60 | // uint16 61 | {uint16(6), int8(0), int8(6), "", nil}, 62 | // uint32 63 | {uint32(6), int8(0), int8(6), "", nil}, 64 | // uint64 65 | {uint64(6), int8(0), int8(6), "", nil}, 66 | // float32 67 | {float32(6), int8(0), int8(6), "", nil}, 68 | // float64 69 | {float64(6), int8(0), int8(6), "", nil}, 70 | // slice 71 | {[]int{'H', 'e', 'l', 'l', 'o'}, int8(0), int8(0), "unable to convert []int to int8: no recipe", nil}, 72 | {[]byte{'H', 'e', 'l', 'l', 'o'}, int8(0), int8(0), "unable to convert []uint8 to int8: no recipe", nil}, 73 | {[]rune{'H', 'e', 'l', 'l', 'o'}, int8(0), int8(0), "unable to convert []int32 to int8: no recipe", nil}, 74 | {[]string{"H", "e", "l", "l", "o"}, int8(0), int8(0), "unable to convert []string to int8: no recipe", nil}, 75 | // struct 76 | {struct{}{}, int8(0), int8(0), "unable to convert struct {} to int8: struct {} has no Int8() function", nil}, 77 | // time 78 | {time.Unix(10, 10), int8(10), int8(10), "", nil}, 79 | 80 | {SomeStructWithIntFunc{}, int8(0), int8(8), "", nil}, 81 | {&SomeStructWithIntFunc{}, int8(0), int8(8), "", nil}, 82 | 83 | {SomeStructWithIntFuncPtr{}, int8(0), int8(8), "", nil}, 84 | {&SomeStructWithIntFuncPtr{}, int8(0), int8(8), "", nil}, 85 | 86 | {SomeStructWithIntWithErrFunc{}, int8(0), int8(8), "", nil}, 87 | {&SomeStructWithIntWithErrFunc{}, int8(0), int8(8), "", nil}, 88 | 89 | {SomeStructWithIntWithErrFuncPtr{}, int8(0), int8(8), "", nil}, 90 | {&SomeStructWithIntWithErrFuncPtr{}, int8(0), int8(8), "", nil}, 91 | 92 | {SomeStructWithInt8Func{}, int8(0), int8(8), "", nil}, 93 | {&SomeStructWithInt8Func{}, int8(0), int8(8), "", nil}, 94 | 95 | {SomeStructWithInt8FuncPtr{}, int8(0), int8(8), "", nil}, 96 | {&SomeStructWithInt8FuncPtr{}, int8(0), int8(8), "", nil}, 97 | 98 | {SomeStructWithInt8WithErrFunc{}, int8(0), int8(8), "", nil}, 99 | {&SomeStructWithInt8WithErrFunc{}, int8(0), int8(8), "", nil}, 100 | 101 | {SomeStructWithInt8WithErrFuncPtr{}, int8(0), int8(8), "", nil}, 102 | {&SomeStructWithInt8WithErrFuncPtr{}, int8(0), int8(8), "", nil}, 103 | 104 | {SomeStructWithInt16Func{}, int8(0), int8(16), "", nil}, 105 | {&SomeStructWithInt16Func{}, int8(0), int8(16), "", nil}, 106 | 107 | {SomeStructWithInt16FuncPtr{}, int8(0), int8(16), "", nil}, 108 | {&SomeStructWithInt16FuncPtr{}, int8(0), int8(16), "", nil}, 109 | 110 | {SomeStructWithInt16WithErrFunc{}, int8(0), int8(16), "", nil}, 111 | {&SomeStructWithInt16WithErrFunc{}, int8(0), int8(16), "", nil}, 112 | 113 | {SomeStructWithInt16WithErrFuncPtr{}, int8(0), int8(16), "", nil}, 114 | {&SomeStructWithInt16WithErrFuncPtr{}, int8(0), int8(16), "", nil}, 115 | 116 | {SomeStructWithInt32Func{}, int8(0), int8(32), "", nil}, 117 | {&SomeStructWithInt32Func{}, int8(0), int8(32), "", nil}, 118 | 119 | {SomeStructWithInt32FuncPtr{}, int8(0), int8(32), "", nil}, 120 | {&SomeStructWithInt32FuncPtr{}, int8(0), int8(32), "", nil}, 121 | 122 | {SomeStructWithInt32WithErrFunc{}, int8(0), int8(32), "", nil}, 123 | {&SomeStructWithInt32WithErrFunc{}, int8(0), int8(32), "", nil}, 124 | 125 | {SomeStructWithInt32WithErrFuncPtr{}, int8(0), int8(32), "", nil}, 126 | {&SomeStructWithInt32WithErrFuncPtr{}, int8(0), int8(32), "", nil}, 127 | 128 | {SomeStructWithInt64Func{}, int8(0), int8(64), "", nil}, 129 | {&SomeStructWithInt64Func{}, int8(0), int8(64), "", nil}, 130 | 131 | {SomeStructWithInt64FuncPtr{}, int8(0), int8(64), "", nil}, 132 | {&SomeStructWithInt64FuncPtr{}, int8(0), int8(64), "", nil}, 133 | 134 | {SomeStructWithInt64WithErrFunc{}, int8(0), int8(64), "", nil}, 135 | {&SomeStructWithInt64WithErrFunc{}, int8(0), int8(64), "", nil}, 136 | 137 | {SomeStructWithInt64WithErrFuncPtr{}, int8(0), int8(64), "", nil}, 138 | {&SomeStructWithInt64WithErrFuncPtr{}, int8(0), int8(64), "", nil}, 139 | 140 | {SomeStructWithUintFunc{}, int8(0), int8(16), "", nil}, 141 | {&SomeStructWithUintFunc{}, int8(0), int8(16), "", nil}, 142 | 143 | {SomeStructWithUintFuncPtr{}, int8(0), int8(16), "", nil}, 144 | {&SomeStructWithUintFuncPtr{}, int8(0), int8(16), "", nil}, 145 | 146 | {SomeStructWithUintWithErrFunc{}, int8(0), int8(16), "", nil}, 147 | {&SomeStructWithUintWithErrFunc{}, int8(0), int8(16), "", nil}, 148 | 149 | {SomeStructWithUintWithErrFuncPtr{}, int8(0), int8(16), "", nil}, 150 | {&SomeStructWithUintWithErrFuncPtr{}, int8(0), int8(16), "", nil}, 151 | 152 | {SomeStructWithUint8Func{}, int8(0), int8(8), "", nil}, 153 | {&SomeStructWithUint8Func{}, int8(0), int8(8), "", nil}, 154 | 155 | {SomeStructWithUint8FuncPtr{}, int8(0), int8(8), "", nil}, 156 | {&SomeStructWithUint8FuncPtr{}, int8(0), int8(8), "", nil}, 157 | 158 | {SomeStructWithUint8WithErrFunc{}, int8(0), int8(8), "", nil}, 159 | {&SomeStructWithUint8WithErrFunc{}, int8(0), int8(8), "", nil}, 160 | 161 | {SomeStructWithUint8WithErrFuncPtr{}, int8(0), int8(8), "", nil}, 162 | {&SomeStructWithUint8WithErrFuncPtr{}, int8(0), int8(8), "", nil}, 163 | 164 | {SomeStructWithUint16Func{}, int8(0), int8(16), "", nil}, 165 | {&SomeStructWithUint16Func{}, int8(0), int8(16), "", nil}, 166 | 167 | {SomeStructWithUint16FuncPtr{}, int8(0), int8(16), "", nil}, 168 | {&SomeStructWithUint16FuncPtr{}, int8(0), int8(16), "", nil}, 169 | 170 | {SomeStructWithUint16WithErrFunc{}, int8(0), int8(16), "", nil}, 171 | {&SomeStructWithUint16WithErrFunc{}, int8(0), int8(16), "", nil}, 172 | 173 | {SomeStructWithUint16WithErrFuncPtr{}, int8(0), int8(16), "", nil}, 174 | {&SomeStructWithUint16WithErrFuncPtr{}, int8(0), int8(16), "", nil}, 175 | 176 | {SomeStructWithUint32Func{}, int8(0), int8(32), "", nil}, 177 | {&SomeStructWithUint32Func{}, int8(0), int8(32), "", nil}, 178 | 179 | {SomeStructWithUint32FuncPtr{}, int8(0), int8(32), "", nil}, 180 | {&SomeStructWithUint32FuncPtr{}, int8(0), int8(32), "", nil}, 181 | 182 | {SomeStructWithUint32WithErrFunc{}, int8(0), int8(32), "", nil}, 183 | {&SomeStructWithUint32WithErrFunc{}, int8(0), int8(32), "", nil}, 184 | 185 | {SomeStructWithUint32WithErrFuncPtr{}, int8(0), int8(32), "", nil}, 186 | {&SomeStructWithUint32WithErrFuncPtr{}, int8(0), int8(32), "", nil}, 187 | 188 | {SomeStructWithUint64Func{}, int8(0), int8(64), "", nil}, 189 | {&SomeStructWithUint64Func{}, int8(0), int8(64), "", nil}, 190 | 191 | {SomeStructWithUint64FuncPtr{}, int8(0), int8(64), "", nil}, 192 | {&SomeStructWithUint64FuncPtr{}, int8(0), int8(64), "", nil}, 193 | 194 | {SomeStructWithUint64WithErrFunc{}, int8(0), int8(64), "", nil}, 195 | {&SomeStructWithUint64WithErrFunc{}, int8(0), int8(64), "", nil}, 196 | 197 | {SomeStructWithUint64WithErrFuncPtr{}, int8(0), int8(64), "", nil}, 198 | {&SomeStructWithUint64WithErrFuncPtr{}, int8(0), int8(64), "", nil}, 199 | } 200 | 201 | for i, test := range tests { 202 | testhelpers.RunTest(t, test, i) 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /int_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/Eun/go-convert/internal/testhelpers" 8 | ) 9 | 10 | type SomeStructWithIntFunc struct{} 11 | 12 | func (SomeStructWithIntFunc) Int() int { 13 | return 8 14 | } 15 | 16 | type SomeStructWithIntFuncPtr struct{} 17 | 18 | func (*SomeStructWithIntFuncPtr) Int() int { 19 | return 8 20 | } 21 | 22 | type SomeStructWithIntWithErrFunc struct{} 23 | 24 | func (SomeStructWithIntWithErrFunc) Int() (int, error) { 25 | return 8, nil 26 | } 27 | 28 | type SomeStructWithIntWithErrFuncPtr struct{} 29 | 30 | func (*SomeStructWithIntWithErrFuncPtr) Int() (int, error) { 31 | return 8, nil 32 | } 33 | 34 | func TestInt(t *testing.T) { 35 | tests := []testhelpers.TestCase{ 36 | // nil 37 | {nil, 0, 0, "", nil}, 38 | // string 39 | {"6", 0, 6, "", nil}, 40 | {"", 0, 0, "", nil}, 41 | {"Hello World", 0, 0, `unable to convert string to int: strconv.ParseInt: parsing "Hello World": invalid syntax`, nil}, 42 | // bool 43 | {true, 0, 1, "", nil}, 44 | {false, 0, 0, "", nil}, 45 | // int 46 | {6, 0, 6, "", nil}, 47 | // int8 48 | {int8(6), 0, 6, "", nil}, 49 | // int16 50 | {int16(6), 0, 6, "", nil}, 51 | // int32 52 | {int32(6), 0, 6, "", nil}, 53 | // int64 54 | {int64(6), 0, 6, "", nil}, 55 | // uint 56 | {uint(6), 0, 6, "", nil}, 57 | // uint8 58 | {uint8(6), 0, 6, "", nil}, 59 | // uint16 60 | {uint16(6), 0, 6, "", nil}, 61 | // uint32 62 | {uint32(6), 0, 6, "", nil}, 63 | // uint64 64 | {uint64(6), 0, 6, "", nil}, 65 | // float32 66 | {float32(6), 0, 6, "", nil}, 67 | // float64 68 | {float64(6), 0, 6, "", nil}, 69 | // slice 70 | {[]int{'H', 'e', 'l', 'l', 'o'}, 0, 0, "unable to convert []int to int: no recipe", nil}, 71 | {[]byte{'H', 'e', 'l', 'l', 'o'}, 0, 0, "unable to convert []uint8 to int: no recipe", nil}, 72 | {[]rune{'H', 'e', 'l', 'l', 'o'}, 0, 0, "unable to convert []int32 to int: no recipe", nil}, 73 | {[]string{"H", "e", "l", "l", "o"}, 0, 0, "unable to convert []string to int: no recipe", nil}, 74 | // struct 75 | {struct{}{}, 0, 0, "unable to convert struct {} to int: struct {} has no Int() function", nil}, 76 | // time 77 | {time.Unix(10, 10), int(10), int(10), "", nil}, 78 | 79 | {SomeStructWithIntFunc{}, int(0), int(8), "", nil}, 80 | {&SomeStructWithIntFunc{}, int(0), int(8), "", nil}, 81 | 82 | {SomeStructWithIntFuncPtr{}, int(0), int(8), "", nil}, 83 | {&SomeStructWithIntFuncPtr{}, int(0), int(8), "", nil}, 84 | 85 | {SomeStructWithIntWithErrFunc{}, int(0), int(8), "", nil}, 86 | {&SomeStructWithIntWithErrFunc{}, int(0), int(8), "", nil}, 87 | 88 | {SomeStructWithIntWithErrFuncPtr{}, int(0), int(8), "", nil}, 89 | {&SomeStructWithIntWithErrFuncPtr{}, int(0), int(8), "", nil}, 90 | 91 | {SomeStructWithInt8Func{}, int(0), int(8), "", nil}, 92 | {&SomeStructWithInt8Func{}, int(0), int(8), "", nil}, 93 | 94 | {SomeStructWithInt8FuncPtr{}, int(0), int(8), "", nil}, 95 | {&SomeStructWithInt8FuncPtr{}, int(0), int(8), "", nil}, 96 | 97 | {SomeStructWithInt8WithErrFunc{}, int(0), int(8), "", nil}, 98 | {&SomeStructWithInt8WithErrFunc{}, int(0), int(8), "", nil}, 99 | 100 | {SomeStructWithInt8WithErrFuncPtr{}, int(0), int(8), "", nil}, 101 | {&SomeStructWithInt8WithErrFuncPtr{}, int(0), int(8), "", nil}, 102 | 103 | {SomeStructWithInt16Func{}, int(0), int(16), "", nil}, 104 | {&SomeStructWithInt16Func{}, int(0), int(16), "", nil}, 105 | 106 | {SomeStructWithInt16FuncPtr{}, int(0), int(16), "", nil}, 107 | {&SomeStructWithInt16FuncPtr{}, int(0), int(16), "", nil}, 108 | 109 | {SomeStructWithInt16WithErrFunc{}, int(0), int(16), "", nil}, 110 | {&SomeStructWithInt16WithErrFunc{}, int(0), int(16), "", nil}, 111 | 112 | {SomeStructWithInt16WithErrFuncPtr{}, int(0), int(16), "", nil}, 113 | {&SomeStructWithInt16WithErrFuncPtr{}, int(0), int(16), "", nil}, 114 | 115 | {SomeStructWithInt32Func{}, int(0), int(32), "", nil}, 116 | {&SomeStructWithInt32Func{}, int(0), int(32), "", nil}, 117 | 118 | {SomeStructWithInt32FuncPtr{}, int(0), int(32), "", nil}, 119 | {&SomeStructWithInt32FuncPtr{}, int(0), int(32), "", nil}, 120 | 121 | {SomeStructWithInt32WithErrFunc{}, int(0), int(32), "", nil}, 122 | {&SomeStructWithInt32WithErrFunc{}, int(0), int(32), "", nil}, 123 | 124 | {SomeStructWithInt32WithErrFuncPtr{}, int(0), int(32), "", nil}, 125 | {&SomeStructWithInt32WithErrFuncPtr{}, int(0), int(32), "", nil}, 126 | 127 | {SomeStructWithInt64Func{}, int(0), int(64), "", nil}, 128 | {&SomeStructWithInt64Func{}, int(0), int(64), "", nil}, 129 | 130 | {SomeStructWithInt64FuncPtr{}, int(0), int(64), "", nil}, 131 | {&SomeStructWithInt64FuncPtr{}, int(0), int(64), "", nil}, 132 | 133 | {SomeStructWithInt64WithErrFunc{}, int(0), int(64), "", nil}, 134 | {&SomeStructWithInt64WithErrFunc{}, int(0), int(64), "", nil}, 135 | 136 | {SomeStructWithInt64WithErrFuncPtr{}, int(0), int(64), "", nil}, 137 | {&SomeStructWithInt64WithErrFuncPtr{}, int(0), int(64), "", nil}, 138 | 139 | {SomeStructWithUintFunc{}, int(0), int(16), "", nil}, 140 | {&SomeStructWithUintFunc{}, int(0), int(16), "", nil}, 141 | 142 | {SomeStructWithUintFuncPtr{}, int(0), int(16), "", nil}, 143 | {&SomeStructWithUintFuncPtr{}, int(0), int(16), "", nil}, 144 | 145 | {SomeStructWithUintWithErrFunc{}, int(0), int(16), "", nil}, 146 | {&SomeStructWithUintWithErrFunc{}, int(0), int(16), "", nil}, 147 | 148 | {SomeStructWithUintWithErrFuncPtr{}, int(0), int(16), "", nil}, 149 | {&SomeStructWithUintWithErrFuncPtr{}, int(0), int(16), "", nil}, 150 | 151 | {SomeStructWithUint8Func{}, int(0), int(8), "", nil}, 152 | {&SomeStructWithUint8Func{}, int(0), int(8), "", nil}, 153 | 154 | {SomeStructWithUint8FuncPtr{}, int(0), int(8), "", nil}, 155 | {&SomeStructWithUint8FuncPtr{}, int(0), int(8), "", nil}, 156 | 157 | {SomeStructWithUint8WithErrFunc{}, int(0), int(8), "", nil}, 158 | {&SomeStructWithUint8WithErrFunc{}, int(0), int(8), "", nil}, 159 | 160 | {SomeStructWithUint8WithErrFuncPtr{}, int(0), int(8), "", nil}, 161 | {&SomeStructWithUint8WithErrFuncPtr{}, int(0), int(8), "", nil}, 162 | 163 | {SomeStructWithUint16Func{}, int(0), int(16), "", nil}, 164 | {&SomeStructWithUint16Func{}, int(0), int(16), "", nil}, 165 | 166 | {SomeStructWithUint16FuncPtr{}, int(0), int(16), "", nil}, 167 | {&SomeStructWithUint16FuncPtr{}, int(0), int(16), "", nil}, 168 | 169 | {SomeStructWithUint16WithErrFunc{}, int(0), int(16), "", nil}, 170 | {&SomeStructWithUint16WithErrFunc{}, int(0), int(16), "", nil}, 171 | 172 | {SomeStructWithUint16WithErrFuncPtr{}, int(0), int(16), "", nil}, 173 | {&SomeStructWithUint16WithErrFuncPtr{}, int(0), int(16), "", nil}, 174 | 175 | {SomeStructWithUint32Func{}, int(0), int(32), "", nil}, 176 | {&SomeStructWithUint32Func{}, int(0), int(32), "", nil}, 177 | 178 | {SomeStructWithUint32FuncPtr{}, int(0), int(32), "", nil}, 179 | {&SomeStructWithUint32FuncPtr{}, int(0), int(32), "", nil}, 180 | 181 | {SomeStructWithUint32WithErrFunc{}, int(0), int(32), "", nil}, 182 | {&SomeStructWithUint32WithErrFunc{}, int(0), int(32), "", nil}, 183 | 184 | {SomeStructWithUint32WithErrFuncPtr{}, int(0), int(32), "", nil}, 185 | {&SomeStructWithUint32WithErrFuncPtr{}, int(0), int(32), "", nil}, 186 | 187 | {SomeStructWithUint64Func{}, int(0), int(64), "", nil}, 188 | {&SomeStructWithUint64Func{}, int(0), int(64), "", nil}, 189 | 190 | {SomeStructWithUint64FuncPtr{}, int(0), int(64), "", nil}, 191 | {&SomeStructWithUint64FuncPtr{}, int(0), int(64), "", nil}, 192 | 193 | {SomeStructWithUint64WithErrFunc{}, int(0), int(64), "", nil}, 194 | {&SomeStructWithUint64WithErrFunc{}, int(0), int(64), "", nil}, 195 | 196 | {SomeStructWithUint64WithErrFuncPtr{}, int(0), int(64), "", nil}, 197 | {&SomeStructWithUint64WithErrFuncPtr{}, int(0), int(64), "", nil}, 198 | } 199 | 200 | for i, test := range tests { 201 | testhelpers.RunTest(t, test, i) 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /internal/testhelpers/helpers.go: -------------------------------------------------------------------------------- 1 | package testhelpers 2 | 3 | import ( 4 | "testing" 5 | 6 | "fmt" 7 | 8 | "strings" 9 | 10 | "reflect" 11 | 12 | convert "github.com/Eun/go-convert" 13 | "github.com/stretchr/testify/require" 14 | ) 15 | 16 | // TestCase is a testcase that can be run with RunTest() 17 | type TestCase struct { 18 | Src interface{} 19 | Dst interface{} 20 | Expected interface{} 21 | ErrorText string 22 | Options *convert.Options 23 | } 24 | 25 | func getTestName(test TestCase, index ...int) string { 26 | var sb strings.Builder 27 | if len(index) > 0 { 28 | fmt.Fprintf(&sb, "%d: ", index) 29 | } 30 | src := "nil" 31 | if test.Src != nil { 32 | src = reflect.TypeOf(test.Src).String() 33 | } 34 | dst := "nil" 35 | if test.Dst != nil { 36 | dst = reflect.TypeOf(test.Dst).String() 37 | } 38 | fmt.Fprintf(&sb, "%s to %s", src, dst) 39 | return sb.String() 40 | } 41 | 42 | // RunTest runs the specified testCase in t 43 | func RunTest(t *testing.T, test TestCase, index ...int) { 44 | t.Run(getTestName(test, index...), func(t *testing.T) { 45 | dst := reflect.ValueOf(test.Dst) 46 | ptrDst := reflect.New(dst.Type()) 47 | ptrDst.Elem().Set(dst) 48 | var opts []convert.Options 49 | if test.Options != nil { 50 | opts = []convert.Options{*test.Options} 51 | } 52 | err := convert.Convert(test.Src, ptrDst.Interface(), opts...) 53 | if test.ErrorText == "" { 54 | require.NoError(t, err) 55 | } else { 56 | require.EqualError(t, err, test.ErrorText) 57 | } 58 | require.Equal(t, test.Expected, ptrDst.Elem().Interface()) 59 | }) 60 | } 61 | 62 | // Ptr makes a pointer for the specified value 63 | func Ptr(v interface{}) interface{} { 64 | return &v 65 | } 66 | 67 | // PtrInt makes a pointer to int for the specified int 68 | func PtrInt(i int) *int { 69 | return &i 70 | } 71 | 72 | // PtrString makes a pointer to string for the specified string 73 | func PtrString(v string) *string { 74 | return &v 75 | } 76 | 77 | // PtrPtrString makes a pointer to pointer string for the specified string 78 | func PtrPtrString(v string) **string { 79 | p := PtrString(v) 80 | return &p 81 | } 82 | -------------------------------------------------------------------------------- /map.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func (stdRecipes) nilToMap(Converter, NilValue, MapValue) error { 8 | return nil 9 | } 10 | 11 | func (stdRecipes) mapToMap(c Converter, in MapValue, out MapValue) error { 12 | keyType := out.Elem().Type().Key() 13 | valueType := out.Elem().Type().Elem() 14 | 15 | m := reflect.MakeMapWithSize(reflect.MapOf(keyType, valueType), in.Len()) 16 | 17 | for _, key := range in.MapKeys() { 18 | keyValue := reflect.New(keyType) 19 | if err := c.ConvertReflectValue(key, keyValue); err != nil { 20 | return err 21 | } 22 | 23 | var valueValue reflect.Value 24 | // lookup key in dst 25 | existingValue := out.Elem().MapIndex(keyValue.Elem()) 26 | if existingValue.IsValid() { 27 | valueValue = reflect.New(existingValue.Type()) 28 | valueValue.Elem().Set(existingValue) 29 | } else { 30 | valueValue = reflect.New(valueType) 31 | } 32 | 33 | if err := c.ConvertReflectValue(in.MapIndex(key), valueValue); err != nil { 34 | return err 35 | } 36 | 37 | m.SetMapIndex(keyValue.Elem(), valueValue.Elem()) 38 | } 39 | out.Elem().Set(m) 40 | 41 | return nil 42 | } 43 | 44 | func (stdRecipes) structToMap(c Converter, in StructValue, out MapValue) error { 45 | keyType := out.Elem().Type().Key() 46 | valueType := out.Elem().Type().Elem() 47 | 48 | m := reflect.MakeMapWithSize(reflect.MapOf(keyType, valueType), in.NumField()) 49 | 50 | for i := in.NumField() - 1; i >= 0; i-- { 51 | field := reflect.ValueOf(in.Type().Field(i).Name) 52 | 53 | var valueValue reflect.Value 54 | // lookup key in dst 55 | existingValue := out.Elem().MapIndex(field) 56 | if existingValue.IsValid() { 57 | valueValue = reflect.New(existingValue.Type()) 58 | valueValue.Elem().Set(existingValue) 59 | } else { 60 | // if the source is nil and the destination map does not expect us to have the field 61 | // skip 62 | switch in.Field(i).Kind() { 63 | case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice: 64 | if in.Field(i).IsNil() { 65 | continue 66 | } 67 | } 68 | 69 | valueValue = reflect.New(valueType) 70 | } 71 | 72 | if err := c.ConvertReflectValue(in.Field(i), valueValue); err != nil { 73 | return err 74 | } 75 | 76 | m.SetMapIndex(field, valueValue.Elem()) 77 | } 78 | out.Elem().Set(m) 79 | 80 | return nil 81 | } 82 | -------------------------------------------------------------------------------- /map_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/Eun/go-convert/internal/testhelpers" 8 | ) 9 | 10 | func TestMap(t *testing.T) { 11 | type User struct { 12 | Name string 13 | } 14 | 15 | type Company struct { 16 | Name string 17 | } 18 | 19 | type UserAndCompany struct { 20 | Name string 21 | Company 22 | } 23 | 24 | type privateCompany struct { 25 | Name string 26 | } 27 | 28 | type UserAndPrivateCompany struct { 29 | Name string 30 | privateCompany 31 | } 32 | 33 | type TimeStruct struct { 34 | CreatedOn *time.Time 35 | } 36 | 37 | beginningOfTime := time.Unix(0, 0).UTC() 38 | 39 | tests := []testhelpers.TestCase{ 40 | // nil 41 | {nil, map[string]interface{}{}, map[string]interface{}{}, "", nil}, 42 | // string 43 | {"Hello World", map[string]interface{}{}, map[string]interface{}{}, "unable to convert string to map[string]interface {}: no recipe", nil}, 44 | // map 45 | {map[string]interface{}{"Foo": true}, map[string]string{}, map[string]string{"Foo": "true"}, "", nil}, 46 | {map[string]string{"Foo": "Bar"}, map[string]interface{}{}, map[string]interface{}{"Foo": "Bar"}, "", nil}, 47 | // 48 | // respect nested types 49 | { 50 | map[string]interface{}{"Int": "3", "Float": "4", "String": "5", "PtrInt": "6", "Slice": []interface{}{"1", "2", "3"}}, 51 | map[string]interface{}{"Int": 0, "Float": 0.0, "PtrInt": testhelpers.PtrInt(0), "Slice": []interface{}{"0", 0, 0.0}}, 52 | map[string]interface{}{"Int": 3, "Float": 4.0, "String": "5", "PtrInt": testhelpers.PtrInt(6), "Slice": []interface{}{"1", 2, 3.0}}, 53 | "", 54 | nil, 55 | }, 56 | 57 | // respect different key type 58 | { 59 | map[int]interface{}{1: 123}, 60 | map[string]interface{}{"1": "String"}, 61 | map[string]interface{}{"1": "123"}, 62 | "", 63 | nil, 64 | }, 65 | 66 | // respect nested slice 67 | { 68 | map[string][]interface{}{"Slice": {"1", "2", "3"}}, 69 | map[string][]interface{}{"Slice": {"0", 0, 0.0}}, 70 | map[string][]interface{}{"Slice": {"1", 2, 3.0}}, 71 | "", 72 | nil, 73 | }, 74 | 75 | // another key type than destination 76 | {map[string]string{"1": "3"}, map[int]interface{}{1: 0}, map[int]interface{}{1: 3}, "", nil}, 77 | // 78 | {map[string]string{"1": "3"}, map[interface{}]interface{}{1: 0}, map[interface{}]interface{}{"1": "3"}, "", nil}, 79 | // 80 | // null interface 81 | {map[string]interface{}{"Foo": nil}, map[string][]string{}, map[string][]string{"Foo": nil}, "", nil}, 82 | // 83 | // struct 84 | {User{"Joe"}, map[string]string{}, map[string]string{"Name": "Joe"}, "", nil}, 85 | {UserAndCompany{"Joe", Company{"Wood Inc"}}, map[string]interface{}{}, map[string]interface{}{"Name": "Joe", "Company": Company{"Wood Inc"}}, "", nil}, 86 | {UserAndCompany{"Joe", Company{"Wood Inc"}}, map[string]interface{}{"Company": map[string]interface{}{}}, map[string]interface{}{"Name": "Joe", "Company": map[string]interface{}{"Name": "Wood Inc"}}, "", nil}, 87 | {UserAndPrivateCompany{"Joe", privateCompany{"Wood Inc"}}, map[string]interface{}{"privateCompany": map[string]interface{}{}}, map[string]interface{}{"Name": "Joe", "privateCompany": map[string]interface{}{"Name": "Wood Inc"}}, "", nil}, 88 | 89 | {map[User]string{{"Joe"}: "Bar"}, map[string]interface{}{}, map[string]interface{}{}, "unable to convert map[convert_test.User]string to map[string]interface {}: unable to convert convert_test.User to string: convert_test.User has no String() function", nil}, 90 | {map[string]User{"Foo": {"Joe"}}, map[string]string{}, map[string]string{}, "unable to convert map[string]convert_test.User to map[string]string: unable to convert convert_test.User to string: convert_test.User has no String() function", nil}, 91 | {UserAndCompany{"Joe", Company{"Wood Inc"}}, map[string]string{}, map[string]string{}, "unable to convert convert_test.UserAndCompany to map[string]string: unable to convert convert_test.Company to string: convert_test.Company has no String() function", nil}, 92 | 93 | {TimeStruct{}, map[string]string{}, map[string]string{}, "", nil}, 94 | {TimeStruct{}, map[string]string{"CreatedOn": ""}, map[string]string{"CreatedOn": ""}, "", nil}, 95 | {TimeStruct{CreatedOn: &beginningOfTime}, map[string]string{}, map[string]string{"CreatedOn": "1970-01-01 00:00:00 +0000 UTC"}, "", nil}, 96 | } 97 | 98 | for i, test := range tests { 99 | testhelpers.RunTest(t, test, i) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /option.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | // Options can be used to alter the behavior of the converter 4 | type Options struct { 5 | // SkipUnknownFields can be used to ignore fields that are not existent in the destination type 6 | // 7 | // Example: 8 | // type User struct { 9 | // Name string 10 | // } 11 | // m := map[string]interface{}{ 12 | // "Name": "Joe", 13 | // "Surname": "Doe", 14 | // } 15 | // // convert a map into User type 16 | // var user User 17 | // // will fail because Surname is not in the User struct 18 | // MustConvert(m, &user) 19 | // // will pass 20 | // MustConvert(m, &user, Options{SkipUnknownFields: true}) 21 | SkipUnknownFields bool 22 | // Recipes can be used to define custom recipes for this converter 23 | Recipes []Recipe 24 | } 25 | -------------------------------------------------------------------------------- /ptr_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Eun/go-convert/internal/testhelpers" 7 | ) 8 | 9 | func TestPtr(t *testing.T) { 10 | type User struct { 11 | Name *string 12 | } 13 | 14 | var nilString *string 15 | 16 | tests := []testhelpers.TestCase{ 17 | // string 18 | {testhelpers.Ptr("Hello World"), "", "Hello World", "", nil}, 19 | {"Hello World", testhelpers.Ptr(""), testhelpers.Ptr("Hello World"), "", nil}, 20 | {"Hello World", testhelpers.PtrString(""), testhelpers.PtrString("Hello World"), "", nil}, 21 | {testhelpers.Ptr("Hello World"), testhelpers.Ptr(""), testhelpers.Ptr("Hello World"), "", nil}, 22 | {testhelpers.PtrString("Hello World"), "", "Hello World", "", nil}, 23 | {"Hello World", testhelpers.PtrString(""), testhelpers.PtrString("Hello World"), "", nil}, 24 | {testhelpers.PtrString("Hello World"), testhelpers.PtrString(""), testhelpers.PtrString("Hello World"), "", nil}, 25 | // map 26 | {testhelpers.Ptr(map[string]interface{}{"Foo": true}), testhelpers.Ptr(map[string]string{}), testhelpers.Ptr(map[string]string{"Foo": "true"}), "", nil}, 27 | {map[string]*string{"Foo": testhelpers.PtrString("Bar")}, map[string]string{}, map[string]string{"Foo": "Bar"}, "", nil}, 28 | 29 | // double ptr 30 | {testhelpers.Ptr(testhelpers.Ptr("Hello World")), testhelpers.Ptr(testhelpers.Ptr("")), testhelpers.Ptr(testhelpers.Ptr("Hello World")), "", nil}, 31 | {testhelpers.Ptr(testhelpers.PtrString("Hello World")), testhelpers.Ptr(testhelpers.PtrString("")), testhelpers.Ptr(testhelpers.PtrString("Hello World")), "", nil}, 32 | {testhelpers.PtrPtrString("Hello World"), testhelpers.PtrPtrString(""), testhelpers.PtrPtrString("Hello World"), "", nil}, 33 | 34 | {map[string]string{"Name": "Foo"}, User{}, User{Name: testhelpers.PtrString("Foo")}, "", nil}, 35 | {map[string]string{"Name": "Foo"}, User{Name: testhelpers.PtrString("Bar")}, User{Name: testhelpers.PtrString("Foo")}, "", nil}, 36 | 37 | {nilString, 0, 0, "", nil}, 38 | } 39 | 40 | for i, test := range tests { 41 | testhelpers.RunTest(t, test, i) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /recipe.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // Recipe represents a recipe that defines which type can be converted into which type 9 | // and which function should be called to convert this type 10 | type Recipe struct { 11 | From reflect.Type 12 | To reflect.Type 13 | Func func(c Converter, in reflect.Value, out reflect.Value) error 14 | } 15 | 16 | // MakeRecipe makes a recipe for the passed in function. 17 | // 18 | // Note that the functions must match this format: 19 | // func(Converter, INVALUE, *OUTVALUE) (error) 20 | // 21 | // Example: 22 | // // convert int to bool 23 | // MakeRecipe(func(c Converter, in int, out *bool) error { 24 | // if in == 0 { 25 | // *out = false 26 | // return nil 27 | // } 28 | // *out = true 29 | // return nil 30 | // }) 31 | func MakeRecipe(fn interface{}) (Recipe, error) { 32 | v := reflect.ValueOf(fn) 33 | 34 | if v.Kind() != reflect.Func { 35 | return Recipe{}, fmt.Errorf("cannot make an recipe from an %v", v.Kind()) 36 | } 37 | var r Recipe 38 | 39 | converterInterface := reflect.TypeOf((*Converter)(nil)).Elem() 40 | errorInterface := reflect.TypeOf((*error)(nil)).Elem() 41 | 42 | if v.Type().NumIn() != 3 { 43 | return Recipe{}, fmt.Errorf("%s has invalid pattern", v.Type().String()) 44 | } 45 | if !v.Type().In(0).Implements(converterInterface) { 46 | return Recipe{}, fmt.Errorf("%s has invalid pattern", v.Type().String()) 47 | } 48 | r.From = v.Type().In(1) 49 | r.To = v.Type().In(2) 50 | 51 | fromWrapper, _ := getGenericWrapper(r.From) 52 | toWrapper, hasToWrapper := getGenericWrapper(r.To) 53 | 54 | if !hasToWrapper && r.To.Kind() != reflect.Ptr { 55 | return Recipe{}, fmt.Errorf("%s has invalid pattern", v.Type().String()) 56 | } 57 | 58 | r.Func = wrapFunc(v, fromWrapper, toWrapper) 59 | 60 | if v.Type().NumOut() != 1 { 61 | return Recipe{}, fmt.Errorf("%s has invalid pattern", v.Type().String()) 62 | } 63 | if !v.Type().Out(0).Implements(errorInterface) { 64 | return Recipe{}, fmt.Errorf("%s has invalid pattern", v.Type().String()) 65 | } 66 | 67 | return r, nil 68 | } 69 | 70 | // MakeRecipes makes a recipe slice for the passed in functions. 71 | // see also MakeRecipe 72 | func MakeRecipes(f ...interface{}) ([]Recipe, error) { 73 | recipes := make([]Recipe, len(f)) 74 | for i, v := range f { 75 | r, err := MakeRecipe(v) 76 | if err != nil { 77 | return nil, err 78 | } 79 | recipes[i] = r 80 | } 81 | return recipes, nil 82 | } 83 | 84 | // MustMakeRecipe makes a recipe for the passed in functions, but panics on error. 85 | // see also MakeRecipe 86 | func MustMakeRecipe(f interface{}) Recipe { 87 | r, err := MakeRecipe(f) 88 | if err != nil { 89 | panic(err) 90 | } 91 | return r 92 | } 93 | 94 | // MustMakeRecipes makes a recipe slice for the passed in functions, but panics on error. 95 | // see also MakeRecipe 96 | func MustMakeRecipes(f ...interface{}) []Recipe { 97 | r, err := MakeRecipes(f...) 98 | if err != nil { 99 | panic(err) 100 | } 101 | return r 102 | } 103 | 104 | type wrapParam func(reflect.Value) reflect.Value 105 | 106 | func wrapFunc(f reflect.Value, wrapIn, wrapOut wrapParam) func(c Converter, in reflect.Value, out reflect.Value) error { 107 | return func(c Converter, in reflect.Value, out reflect.Value) error { 108 | result := f.Call([]reflect.Value{reflect.ValueOf(c), wrapIn(in), wrapOut(out)}) 109 | if !result[0].IsNil() { 110 | return result[0].Interface().(error) 111 | } 112 | return nil 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /recipe_test.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestMakeRecipe(t *testing.T) { 11 | tests := []struct { 12 | name string 13 | args interface{} 14 | want Recipe 15 | wantErr bool 16 | }{ 17 | { 18 | "not a func", 19 | "Hello World", 20 | Recipe{}, 21 | true, 22 | }, 23 | { 24 | "invalid func (no args)", 25 | func() {}, 26 | Recipe{}, 27 | true, 28 | }, 29 | { 30 | "invalid func (invalid first arg)", 31 | func(int, int, *int) {}, 32 | Recipe{}, 33 | true, 34 | }, 35 | { 36 | "invalid func (output not a pointer)", 37 | func(Converter, int, int) {}, 38 | Recipe{}, 39 | true, 40 | }, 41 | { 42 | "invalid func (return not error)", 43 | func(Converter, int, *int) int { return 0 }, 44 | Recipe{}, 45 | true, 46 | }, 47 | { 48 | "invalid func (multiple return)", 49 | func(Converter, int, *int) (int, int) { return 0, 0 }, 50 | Recipe{}, 51 | true, 52 | }, 53 | } 54 | for _, tt := range tests { 55 | t.Run(tt.name, func(t *testing.T) { 56 | got, err := MakeRecipe(tt.args) 57 | if (err != nil) != tt.wantErr { 58 | t.Errorf("MakeRecipe() error = %v, wantErr %v", err, tt.wantErr) 59 | return 60 | } 61 | if !reflect.DeepEqual(got, tt.want) { 62 | t.Errorf("MakeRecipe() got = %v, want %v", got, tt.want) 63 | } 64 | }) 65 | } 66 | } 67 | 68 | func TestMustMakeRecipe(t *testing.T) { 69 | require.Panics(t, func() { 70 | _ = MustMakeRecipe(0) 71 | }) 72 | } 73 | 74 | func TestJoinRecipes(t *testing.T) { 75 | tests := []struct { 76 | Recipes []Recipe 77 | CustomRecipes []Recipe 78 | Wanted []Recipe 79 | }{ 80 | { 81 | []Recipe{ 82 | { 83 | From: reflect.TypeOf(""), 84 | To: reflect.TypeOf(""), 85 | }, 86 | }, 87 | []Recipe{ 88 | { 89 | From: reflect.TypeOf(0), 90 | To: reflect.TypeOf(0), 91 | }, 92 | }, 93 | []Recipe{ 94 | { 95 | From: reflect.TypeOf(0), 96 | To: reflect.TypeOf(0), 97 | }, 98 | { 99 | From: reflect.TypeOf(""), 100 | To: reflect.TypeOf(""), 101 | }, 102 | }, 103 | }, 104 | 105 | { 106 | []Recipe{ 107 | { 108 | From: NilType, 109 | To: reflect.TypeOf(""), 110 | }, 111 | }, 112 | []Recipe{ 113 | { 114 | From: StructType, 115 | To: reflect.TypeOf(0), 116 | }, 117 | }, 118 | []Recipe{ 119 | { 120 | From: StructType, 121 | To: reflect.TypeOf(0), 122 | }, 123 | { 124 | From: NilType, 125 | To: reflect.TypeOf(""), 126 | }, 127 | }, 128 | }, 129 | 130 | { 131 | []Recipe{ 132 | { 133 | From: NilType, 134 | To: reflect.TypeOf(""), 135 | }, 136 | }, 137 | []Recipe{ 138 | { 139 | From: reflect.TypeOf(0), 140 | To: reflect.TypeOf(0), 141 | }, 142 | { 143 | From: StructType, 144 | To: reflect.TypeOf(""), 145 | }, 146 | }, 147 | []Recipe{ 148 | { 149 | From: reflect.TypeOf(0), 150 | To: reflect.TypeOf(0), 151 | }, 152 | { 153 | From: StructType, 154 | To: reflect.TypeOf(""), 155 | }, 156 | { 157 | From: NilType, 158 | To: reflect.TypeOf(""), 159 | }, 160 | }, 161 | }, 162 | 163 | { 164 | []Recipe{ 165 | { 166 | From: reflect.TypeOf(""), 167 | To: reflect.TypeOf(""), 168 | }, 169 | { 170 | From: NilType, 171 | To: reflect.TypeOf(""), 172 | }, 173 | }, 174 | []Recipe{ 175 | { 176 | From: reflect.TypeOf(0), 177 | To: reflect.TypeOf(0), 178 | }, 179 | { 180 | From: StructType, 181 | To: reflect.TypeOf(""), 182 | }, 183 | }, 184 | []Recipe{ 185 | { 186 | From: reflect.TypeOf(0), 187 | To: reflect.TypeOf(0), 188 | }, 189 | { 190 | From: reflect.TypeOf(""), 191 | To: reflect.TypeOf(""), 192 | }, 193 | { 194 | From: StructType, 195 | To: reflect.TypeOf(""), 196 | }, 197 | { 198 | From: NilType, 199 | To: reflect.TypeOf(""), 200 | }, 201 | }, 202 | }, 203 | 204 | // when this test fails it means that the standart recipes are not in order 205 | // make sure generic types are on the end 206 | { 207 | getStdRecipes(), 208 | nil, 209 | getStdRecipes(), 210 | }, 211 | } 212 | 213 | for _, test := range tests { 214 | t.Run("", func(t *testing.T) { 215 | recipes := joinRecipes(test.Recipes, test.CustomRecipes) 216 | require.Equal(t, len(test.Wanted), len(recipes)) 217 | for i := range recipes { 218 | require.Equal(t, test.Wanted[i].From, recipes[i].From) 219 | require.Equal(t, test.Wanted[i].To, recipes[i].To) 220 | } 221 | }) 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /slice.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "reflect" 5 | 6 | "errors" 7 | ) 8 | 9 | func (stdRecipes) nilToSlice(_ Converter, _ NilValue, out SliceValue) error { 10 | out.Elem().Set(reflect.MakeSlice(reflect.SliceOf(out.Type().Elem().Elem()), 0, 0)) 11 | return nil 12 | } 13 | 14 | func (stdRecipes) stringToSlice(c Converter, in string, out SliceValue) error { 15 | valueType := out.Type().Elem().Elem() 16 | switch valueType.Kind() { 17 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 18 | size := len(in) 19 | sl := reflect.MakeSlice(reflect.SliceOf(valueType), size, size) 20 | for i := size - 1; i >= 0; i-- { 21 | sl.Index(i).SetInt(int64(in[i])) 22 | } 23 | out.Elem().Set(sl) 24 | return nil 25 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 26 | size := len(in) 27 | sl := reflect.MakeSlice(reflect.SliceOf(valueType), size, size) 28 | for i := size - 1; i >= 0; i-- { 29 | sl.Index(i).SetUint(uint64(in[i])) 30 | } 31 | out.Elem().Set(sl) 32 | return nil 33 | } 34 | return errors.New("no recipe") 35 | } 36 | 37 | func (stdRecipes) sliceToSlice(c Converter, in, out SliceValue) error { 38 | o := out.Elem() 39 | valueType := o.Type().Elem() 40 | 41 | length := in.Len() 42 | 43 | sl := reflect.MakeSlice(reflect.SliceOf(valueType), length, in.Cap()) 44 | for i := length - 1; i >= 0; i-- { 45 | value := reflect.New(valueType) 46 | // lookup the original 47 | if i < o.Len() { 48 | orig := o.Index(i) 49 | if orig.IsValid() { 50 | value.Elem().Set(orig) 51 | } 52 | } 53 | 54 | if err := c.ConvertReflectValue(in.Index(i), value); err != nil { 55 | return err 56 | } 57 | sl.Index(i).Set(value.Elem()) 58 | } 59 | o.Set(sl) 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /slice_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Eun/go-convert/internal/testhelpers" 7 | ) 8 | 9 | func TestSlice(t *testing.T) { 10 | tests := []testhelpers.TestCase{ 11 | {nil, []int{}, []int{}, "", nil}, 12 | {6, []int{}, []int{}, "unable to convert int to []int: no recipe", nil}, 13 | {[]interface{}{[]int{}}, []int{}, []int{}, "unable to convert []interface {} to []int: unable to convert []int to int: no recipe", nil}, 14 | // string 15 | {"Hello World", []byte{}, []byte("Hello World"), "", nil}, 16 | {"Hello", []int{}, []int{'H', 'e', 'l', 'l', 'o'}, "", nil}, 17 | {"Hello", []string{}, []string{}, "unable to convert string to []string: no recipe", nil}, 18 | {"", []byte{}, []byte{}, "", nil}, 19 | // Slice to Slice 20 | {[]int{1, 2, 3}, []uint{}, []uint{1, 2, 3}, "", nil}, 21 | {[]int{1, 2, 3}, []string{}, []string{"1", "2", "3"}, "", nil}, 22 | {[]int{1, 2, 3}, []interface{}{"", 0.0, 0}, []interface{}{"1", 2.0, 3}, "", nil}, 23 | } 24 | 25 | for i, test := range tests { 26 | testhelpers.RunTest(t, test, i) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /string.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func (stdRecipes) nilToString(Converter, NilValue, *string) error { 13 | return nil 14 | } 15 | 16 | func (stdRecipes) intToString(c Converter, in int, out *string) error { 17 | *out = strconv.FormatInt(int64(in), 10) 18 | return nil 19 | } 20 | 21 | func (stdRecipes) int8ToString(c Converter, in int8, out *string) error { 22 | *out = strconv.FormatInt(int64(in), 10) 23 | return nil 24 | } 25 | 26 | func (stdRecipes) int16ToString(c Converter, in int16, out *string) error { 27 | *out = strconv.FormatInt(int64(in), 10) 28 | return nil 29 | } 30 | 31 | func (stdRecipes) int32ToString(c Converter, in int32, out *string) error { 32 | *out = strconv.FormatInt(int64(in), 10) 33 | return nil 34 | } 35 | 36 | func (stdRecipes) int64ToString(_ Converter, in int64, out *string) error { 37 | *out = strconv.FormatInt(in, 10) 38 | return nil 39 | } 40 | 41 | func (stdRecipes) uintToString(c Converter, in uint, out *string) error { 42 | *out = strconv.FormatUint(uint64(in), 10) 43 | return nil 44 | } 45 | 46 | func (stdRecipes) uint8ToString(c Converter, in uint8, out *string) error { 47 | *out = strconv.FormatUint(uint64(in), 10) 48 | return nil 49 | } 50 | 51 | func (stdRecipes) uint16ToString(c Converter, in uint16, out *string) error { 52 | *out = strconv.FormatUint(uint64(in), 10) 53 | return nil 54 | } 55 | 56 | func (stdRecipes) uint32ToString(c Converter, in uint32, out *string) error { 57 | *out = strconv.FormatUint(uint64(in), 10) 58 | return nil 59 | } 60 | 61 | func (stdRecipes) uint64ToString(_ Converter, in uint64, out *string) error { 62 | *out = strconv.FormatUint(in, 10) 63 | return nil 64 | } 65 | 66 | func (stdRecipes) boolToString(c Converter, in bool, out *string) error { 67 | *out = strconv.FormatBool(in) 68 | return nil 69 | } 70 | 71 | func (stdRecipes) float32ToString(_ Converter, in float32, out *string) error { 72 | if *out != "" && strings.ContainsRune(*out, '%') { 73 | *out = fmt.Sprintf(*out, in) 74 | return nil 75 | } 76 | *out = strconv.FormatFloat(float64(in), 'f', 6, 32) 77 | return nil 78 | } 79 | 80 | func (stdRecipes) float64ToString(_ Converter, in float64, out *string) error { 81 | if *out != "" && strings.ContainsRune(*out, '%') { 82 | *out = fmt.Sprintf(*out, in) 83 | return nil 84 | } 85 | *out = strconv.FormatFloat(in, 'f', 6, 64) 86 | return nil 87 | } 88 | 89 | func (stdRecipes) stringToString(_ Converter, in string, out *string) error { 90 | *out = in 91 | return nil 92 | } 93 | 94 | func (stdRecipes) intSliceToString(_ Converter, in []int, out *string) error { 95 | var sb strings.Builder 96 | for _, i := range in { 97 | sb.WriteRune(rune(i)) 98 | } 99 | *out = sb.String() 100 | return nil 101 | } 102 | 103 | func (stdRecipes) int8SliceToString(c Converter, in []int8, out *string) error { 104 | var sb strings.Builder 105 | for _, i := range in { 106 | sb.WriteRune(rune(i)) 107 | } 108 | *out = sb.String() 109 | return nil 110 | } 111 | 112 | func (stdRecipes) int16SliceToString(c Converter, in []int16, out *string) error { 113 | var sb strings.Builder 114 | for _, i := range in { 115 | sb.WriteRune(rune(i)) 116 | } 117 | *out = sb.String() 118 | return nil 119 | } 120 | 121 | func (stdRecipes) int32SliceToString(c Converter, in []int32, out *string) error { 122 | var sb strings.Builder 123 | for _, i := range in { 124 | sb.WriteRune(i) 125 | } 126 | *out = sb.String() 127 | return nil 128 | } 129 | 130 | func (stdRecipes) int64SliceToString(c Converter, in []int64, out *string) error { 131 | var sb strings.Builder 132 | for _, i := range in { 133 | sb.WriteRune(rune(i)) 134 | } 135 | *out = sb.String() 136 | return nil 137 | } 138 | 139 | func (stdRecipes) uintSliceToString(c Converter, in []uint, out *string) error { 140 | var sb strings.Builder 141 | for _, i := range in { 142 | sb.WriteRune(rune(i)) 143 | } 144 | *out = sb.String() 145 | return nil 146 | } 147 | 148 | func (stdRecipes) uint8SliceToString(c Converter, in []uint8, out *string) error { 149 | var sb strings.Builder 150 | for _, i := range in { 151 | sb.WriteRune(rune(i)) 152 | } 153 | *out = sb.String() 154 | return nil 155 | } 156 | 157 | func (stdRecipes) uint16SliceToString(c Converter, in []uint16, out *string) error { 158 | var sb strings.Builder 159 | for _, i := range in { 160 | sb.WriteRune(rune(i)) 161 | } 162 | *out = sb.String() 163 | return nil 164 | } 165 | 166 | func (stdRecipes) uint32SliceToString(c Converter, in []uint32, out *string) error { 167 | var sb strings.Builder 168 | for _, i := range in { 169 | sb.WriteRune(rune(i)) 170 | } 171 | *out = sb.String() 172 | return nil 173 | } 174 | 175 | func (stdRecipes) uint64SliceToString(c Converter, in []uint64, out *string) error { 176 | var sb strings.Builder 177 | for _, i := range in { 178 | sb.WriteRune(rune(i)) 179 | } 180 | *out = sb.String() 181 | return nil 182 | } 183 | 184 | func (stdRecipes) timeToString(c Converter, in time.Time, out *string) error { 185 | *out = in.String() 186 | return nil 187 | } 188 | 189 | func (s stdRecipes) structToString(c Converter, in StructValue, out *string) error { 190 | err := s.baseStructToString(c, in.Value, out) 191 | if err == nil { 192 | return err 193 | } 194 | 195 | // test for *struct.String() 196 | v := reflect.New(in.Type()) 197 | v.Elem().Set(in.Value) 198 | if s.baseStructToString(c, v, out) == nil { 199 | return nil 200 | } 201 | return err 202 | } 203 | 204 | func (s stdRecipes) baseStructToString(_ Converter, in reflect.Value, out *string) error { 205 | if !in.CanInterface() { 206 | return errors.New("unable to make interface") 207 | } 208 | type toString interface { 209 | String() string 210 | } 211 | type toStringWithErr interface { 212 | String() (string, error) 213 | } 214 | 215 | // check for struct.String() 216 | if i, ok := in.Interface().(toString); ok { 217 | *out = i.String() 218 | return nil 219 | } 220 | if i, ok := in.Interface().(toStringWithErr); ok { 221 | var err error 222 | *out, err = i.String() 223 | return err 224 | } 225 | 226 | return fmt.Errorf("%s has no String() function", in.Type().String()) 227 | } 228 | -------------------------------------------------------------------------------- /string_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "time" 7 | 8 | "github.com/Eun/go-convert/internal/testhelpers" 9 | ) 10 | 11 | type SomeStructWithStringFunc struct{} 12 | 13 | func (SomeStructWithStringFunc) String() string { 14 | return "Hello World" 15 | } 16 | 17 | type SomeStructWithStringFuncPtr struct{} 18 | 19 | func (*SomeStructWithStringErrFuncPtr) String() string { 20 | return "Hello World" 21 | } 22 | 23 | type SomeStructWithStringErrFunc struct{} 24 | 25 | func (SomeStructWithStringErrFunc) String() (string, error) { 26 | return "Hello World", nil 27 | } 28 | 29 | type SomeStructWithStringErrFuncPtr struct{} 30 | 31 | func (*SomeStructWithStringFuncPtr) String() (string, error) { 32 | return "Hello World", nil 33 | } 34 | 35 | func TestString(t *testing.T) { 36 | beginningOfTime := time.Unix(0, 0).UTC() 37 | tests := []testhelpers.TestCase{ 38 | // nil 39 | {nil, "", "", "", nil}, 40 | // string 41 | {"Hello World", "", "Hello World", "", nil}, 42 | // bool 43 | {true, "", "true", "", nil}, 44 | // int 45 | {6, "", "6", "", nil}, 46 | // int8 47 | {int8(6), "", "6", "", nil}, 48 | // int16 49 | {int16(6), "", "6", "", nil}, 50 | // int32 51 | {int32(6), "", "6", "", nil}, 52 | // int64 53 | {int64(6), "", "6", "", nil}, 54 | // uint 55 | {uint(6), "", "6", "", nil}, 56 | // uint8 57 | {uint8(6), "", "6", "", nil}, 58 | // uint16 59 | {uint16(6), "", "6", "", nil}, 60 | // uint32 61 | {uint32(6), "", "6", "", nil}, 62 | // uint64 63 | {uint64(6), "", "6", "", nil}, 64 | // float32 65 | {float32(6), "", "6.000000", "", nil}, 66 | // float32 with format 67 | {float32(6), "%06.2f", "006.00", "", nil}, 68 | // float32 with invalid format 69 | {float32(6), "06.2f", "6.000000", "", nil}, 70 | // float64 71 | {float64(6), "", "6.000000", "", nil}, 72 | // float64 with format 73 | {float64(6), "%06.2f", "006.00", "", nil}, 74 | // float64 with invalid format 75 | {float64(6), "06.2f", "6.000000", "", nil}, 76 | // slice 77 | {[]int{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 78 | {[]int8{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 79 | {[]int16{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 80 | {[]int32{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 81 | {[]int64{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 82 | {[]uint{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 83 | {[]uint8{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 84 | {[]uint16{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 85 | {[]uint32{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 86 | {[]uint64{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 87 | {[]byte{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 88 | {[]rune{'H', 'e', 'l', 'l', 'o'}, "", "Hello", "", nil}, 89 | {[]string{"H", "e", "l", "l", "o"}, "", "", "unable to convert []string to string: no recipe", nil}, 90 | // struct 91 | {struct{}{}, "", "", "unable to convert struct {} to string: struct {} has no String() function", nil}, 92 | 93 | {SomeStructWithStringFunc{}, "Hello World", "Hello World", "", nil}, 94 | {&SomeStructWithStringFunc{}, "Hello World", "Hello World", "", nil}, 95 | 96 | {SomeStructWithStringFuncPtr{}, "Hello World", "Hello World", "", nil}, 97 | {&SomeStructWithStringFuncPtr{}, "Hello World", "Hello World", "", nil}, 98 | 99 | {SomeStructWithStringErrFunc{}, "Hello World", "Hello World", "", nil}, 100 | {&SomeStructWithStringErrFunc{}, "Hello World", "Hello World", "", nil}, 101 | 102 | {SomeStructWithStringErrFuncPtr{}, "Hello World", "Hello World", "", nil}, 103 | {&SomeStructWithStringErrFuncPtr{}, "Hello World", "Hello World", "", nil}, 104 | 105 | {beginningOfTime, "", "1970-01-01 00:00:00 +0000 UTC", "", nil}, 106 | {&beginningOfTime, "", "1970-01-01 00:00:00 +0000 UTC", "", nil}, 107 | } 108 | 109 | for i, test := range tests { 110 | testhelpers.RunTest(t, test, i) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /struct.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "reflect" 5 | 6 | "fmt" 7 | "strings" 8 | ) 9 | 10 | func (stdRecipes) nilToStruct(Converter, NilValue, StructValue) error { 11 | return nil 12 | } 13 | 14 | func (stdRecipes) mapToStruct(c Converter, in MapValue, out StructValue) error { 15 | fieldNameValue := reflect.New(reflect.TypeOf("")) 16 | for _, key := range in.MapKeys() { 17 | // convert key 18 | if err := c.ConvertReflectValue(key, fieldNameValue); err != nil { 19 | return err 20 | } 21 | fieldName := fieldNameValue.Elem().String() 22 | 23 | // find the destination field with the converted value 24 | field := out.Elem().FieldByNameFunc(func(s string) bool { 25 | return strings.EqualFold(fieldName, s) 26 | }) 27 | if !field.IsValid() || !field.CanSet() { 28 | if c.Options().SkipUnknownFields { 29 | continue 30 | } 31 | return fmt.Errorf("unable to find %s in %s", fieldName, out.Elem().Type().String()) 32 | } 33 | 34 | // convert value 35 | value := reflect.New(field.Type()) 36 | if err := c.ConvertReflectValue(in.MapIndex(key), value); err != nil { 37 | return err 38 | } 39 | 40 | field.Set(value.Elem()) 41 | } 42 | return nil 43 | } 44 | 45 | func (stdRecipes) structToStruct(c Converter, in, out StructValue) error { 46 | for i := in.NumField() - 1; i >= 0; i-- { 47 | fieldName := in.Type().Field(i).Name 48 | // find the destination field 49 | 50 | // find the destination field with the converted value 51 | field := out.Elem().FieldByNameFunc(func(s string) bool { 52 | return strings.EqualFold(fieldName, s) 53 | }) 54 | if !field.IsValid() || !field.CanSet() { 55 | if c.Options().SkipUnknownFields { 56 | continue 57 | } 58 | return fmt.Errorf("unable to find %s in %s", fieldName, out.Elem().Type().String()) 59 | } 60 | 61 | // convert value 62 | value := reflect.New(field.Type()) 63 | err := c.ConvertReflectValue(in.Field(i), value) 64 | if err != nil { 65 | return err 66 | } 67 | 68 | field.Set(value.Elem()) 69 | } 70 | 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /struct_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Eun/go-convert" 7 | "github.com/Eun/go-convert/internal/testhelpers" 8 | ) 9 | 10 | func TestStruct(t *testing.T) { 11 | type Foo struct { 12 | Ok bool 13 | } 14 | 15 | type Bool struct { 16 | True string 17 | } 18 | 19 | type User struct { 20 | Name string 21 | } 22 | 23 | type AnotherUser struct { 24 | Name string 25 | } 26 | 27 | type AnotherByteUser struct { 28 | Name []byte 29 | } 30 | 31 | type Company struct { 32 | Name string 33 | } 34 | 35 | type UserAndCompany struct { 36 | Name string 37 | Company 38 | } 39 | 40 | type AnotherUserAndCompany struct { 41 | Name string 42 | Company 43 | } 44 | 45 | type AnotherCompany struct { 46 | Name string 47 | } 48 | 49 | type AnotherUserAndAnotherCompany struct { 50 | Name string 51 | Company AnotherCompany 52 | } 53 | 54 | type AnotherUserAndCompanyString struct { 55 | Name string 56 | Company string 57 | } 58 | 59 | type NilField struct { 60 | OptionalField *string 61 | } 62 | 63 | tests := []testhelpers.TestCase{ 64 | // nil 65 | {nil, struct{}{}, struct{}{}, "", nil}, 66 | 67 | // string 68 | {"Hello World", struct{}{}, struct{}{}, "unable to convert string to struct {}: no recipe", nil}, 69 | 70 | // map 71 | {map[string]interface{}{"Ok": true}, Foo{}, Foo{true}, "", nil}, 72 | {map[string]string{"Name": "Joe"}, User{}, User{"Joe"}, "", nil}, 73 | {map[string]interface{}{"Name": "Joe", "Company": map[string]interface{}{"Name": "Wood Inc"}}, UserAndCompany{}, UserAndCompany{"Joe", Company{"Wood Inc"}}, "", nil}, 74 | {map[bool]string{true: "Bar"}, Bool{}, Bool{"Bar"}, "", nil}, 75 | {map[string]interface{}{}, NilField{}, NilField{}, "", nil}, 76 | {map[string]interface{}{"OptionalField": "Hello World"}, NilField{}, NilField{testhelpers.PtrString("Hello World")}, "", nil}, 77 | 78 | {map[string]interface{}{"Foo": "Bar"}, User{}, User{}, `unable to convert map[string]interface {} to convert_test.User: unable to find Foo in convert_test.User`, nil}, 79 | {map[string]interface{}{"Foo": "Bar"}, User{}, User{}, "", &convert.Options{SkipUnknownFields: true}}, 80 | 81 | // should be unable to convert key 82 | {map[User]string{{}: ""}, struct{}{}, struct{}{}, `unable to convert map[convert_test.User]string to struct {}: unable to convert convert_test.User to string: convert_test.User has no String() function`, nil}, 83 | // should be unable to convert value 84 | {map[string]User{"Foo": {}}, struct{ Foo Foo }{}, struct{ Foo Foo }{}, `unable to convert map[string]convert_test.User to struct { Foo convert_test.Foo }: unable to convert convert_test.User to convert_test.Foo: unable to find Name in convert_test.Foo`, nil}, 85 | // 86 | // struct 87 | {User{"Joe"}, User{}, User{"Joe"}, "", nil}, 88 | {User{"Joe"}, AnotherUser{}, AnotherUser{"Joe"}, "", nil}, 89 | {User{"Joe"}, AnotherByteUser{}, AnotherByteUser{[]byte("Joe")}, "", nil}, 90 | {UserAndCompany{"Joe", Company{"Wood Inc"}}, AnotherUserAndCompany{}, AnotherUserAndCompany{"Joe", Company{"Wood Inc"}}, "", nil}, 91 | {UserAndCompany{"Joe", Company{"Wood Inc"}}, AnotherUserAndAnotherCompany{}, AnotherUserAndAnotherCompany{"Joe", AnotherCompany{"Wood Inc"}}, "", nil}, 92 | 93 | {UserAndCompany{"Joe", Company{"Wood Inc"}}, User{}, User{}, "unable to convert convert_test.UserAndCompany to convert_test.User: unable to find Company in convert_test.User", nil}, 94 | {UserAndCompany{"Joe", Company{"Wood Inc"}}, User{}, User{"Joe"}, "", &convert.Options{SkipUnknownFields: true}}, 95 | 96 | {UserAndCompany{"Joe", Company{"Wood Inc"}}, AnotherUserAndCompanyString{}, AnotherUserAndCompanyString{}, "unable to convert convert_test.UserAndCompany to convert_test.AnotherUserAndCompanyString: unable to convert convert_test.Company to string: convert_test.Company has no String() function", nil}, 97 | 98 | // struct with nil field should stay nil 99 | {NilField{}, NilField{}, NilField{}, "", nil}, 100 | } 101 | 102 | for i, test := range tests { 103 | testhelpers.RunTest(t, test, i) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /time.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/araddon/dateparse" 7 | ) 8 | 9 | func (stdRecipes) nilToTime(Converter, NilValue, *time.Time) error { 10 | return nil 11 | } 12 | 13 | func (stdRecipes) intToTime(c Converter, in int, out *time.Time) error { 14 | *out = time.Unix(int64(in), 0) 15 | return nil 16 | } 17 | 18 | func (stdRecipes) int8ToTime(c Converter, in int8, out *time.Time) error { 19 | *out = time.Unix(int64(in), 0) 20 | return nil 21 | } 22 | 23 | func (stdRecipes) int16ToTime(c Converter, in int16, out *time.Time) error { 24 | *out = time.Unix(int64(in), 0) 25 | return nil 26 | } 27 | 28 | func (stdRecipes) int32ToTime(c Converter, in int32, out *time.Time) error { 29 | *out = time.Unix(int64(in), 0) 30 | return nil 31 | } 32 | 33 | func (stdRecipes) int64ToTime(_ Converter, in int64, out *time.Time) error { 34 | *out = time.Unix(in, 0) 35 | return nil 36 | } 37 | 38 | func (stdRecipes) uintToTime(c Converter, in uint, out *time.Time) error { 39 | *out = time.Unix(int64(in), 0) 40 | return nil 41 | } 42 | 43 | func (stdRecipes) uint8ToTime(c Converter, in uint8, out *time.Time) error { 44 | *out = time.Unix(int64(in), 0) 45 | return nil 46 | } 47 | 48 | func (stdRecipes) uint16ToTime(c Converter, in uint16, out *time.Time) error { 49 | *out = time.Unix(int64(in), 0) 50 | return nil 51 | } 52 | 53 | func (stdRecipes) uint32ToTime(c Converter, in uint32, out *time.Time) error { 54 | *out = time.Unix(int64(in), 0) 55 | return nil 56 | } 57 | 58 | func (stdRecipes) uint64ToTime(_ Converter, in uint64, out *time.Time) error { 59 | *out = time.Unix(int64(in), 0) 60 | return nil 61 | } 62 | 63 | func (stdRecipes) float32ToTime(_ Converter, in float32, out *time.Time) error { 64 | *out = time.Unix(int64(in), 0) 65 | return nil 66 | } 67 | 68 | func (stdRecipes) float64ToTime(_ Converter, in float64, out *time.Time) error { 69 | *out = time.Unix(int64(in), 0) 70 | return nil 71 | } 72 | func (stdRecipes) stringToTime(_ Converter, in string, out *time.Time) error { 73 | if in == "" { 74 | *out = time.Time{} 75 | return nil 76 | } 77 | var err error 78 | *out, err = dateparse.ParseAny(in) 79 | return err 80 | } 81 | -------------------------------------------------------------------------------- /time_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/Eun/go-convert/internal/testhelpers" 8 | ) 9 | 10 | func TestTime(t *testing.T) { 11 | someTime := func() time.Time { 12 | return time.Time{}.AddDate(2005, 1, 0) 13 | } 14 | 15 | tests := []testhelpers.TestCase{ 16 | // nil 17 | {nil, time.Time{}, time.Time{}, "", nil}, 18 | // string 19 | {"2/1/2006", time.Time{}, someTime(), "", nil}, 20 | {"", time.Time{}, time.Time{}, "", nil}, 21 | // int 22 | {100, time.Time{}, time.Unix(100, 0), "", nil}, 23 | // int8 24 | {int8(100), time.Time{}, time.Unix(100, 0), "", nil}, 25 | // int16 26 | {int16(100), time.Time{}, time.Unix(100, 0), "", nil}, 27 | // int32 28 | {int32(100), time.Time{}, time.Unix(100, 0), "", nil}, 29 | // int64 30 | {int64(100), time.Time{}, time.Unix(100, 0), "", nil}, 31 | // uint 32 | {uint(100), time.Time{}, time.Unix(100, 0), "", nil}, 33 | // uint8 34 | {uint8(100), time.Time{}, time.Unix(100, 0), "", nil}, 35 | // uint16 36 | {uint16(100), time.Time{}, time.Unix(100, 0), "", nil}, 37 | // uint32 38 | {uint32(100), time.Time{}, time.Unix(100, 0), "", nil}, 39 | // uint64 40 | {uint64(100), time.Time{}, time.Unix(100, 0), "", nil}, 41 | // float32 42 | {float32(100), time.Time{}, time.Unix(100, 0), "", nil}, 43 | // float64 44 | {float64(100), time.Time{}, time.Unix(100, 0), "", nil}, 45 | } 46 | 47 | for i, test := range tests { 48 | testhelpers.RunTest(t, test, i) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /uint.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToUint(Converter, NilValue, *uint) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToUint(c Converter, in int, out *uint) error { 15 | *out = uint(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToUint(c Converter, in int8, out *uint) error { 19 | *out = uint(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToUint(c Converter, in int16, out *uint) error { 23 | *out = uint(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToUint(c Converter, in int32, out *uint) error { 27 | *out = uint(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToUint(c Converter, in int64, out *uint) error { 31 | *out = uint(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToUint(c Converter, in uint, out *uint) error { 35 | *out = in 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToUint(c Converter, in uint8, out *uint) error { 39 | *out = uint(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToUint(c Converter, in uint16, out *uint) error { 43 | *out = uint(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToUint(c Converter, in uint32, out *uint) error { 47 | *out = uint(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToUint(c Converter, in uint64, out *uint) error { 51 | *out = uint(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToUint(c Converter, in bool, out *uint) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToUint(c Converter, in float32, out *uint) error { 65 | *out = uint(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToUint(c Converter, in float64, out *uint) error { 69 | *out = uint(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToUint(c Converter, in string, out *uint) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseUint(in, 0, 32) 78 | if err != nil { 79 | return err 80 | } 81 | *out = uint(i) 82 | return nil 83 | } 84 | func (stdRecipes) timeToUint(c Converter, in time.Time, out *uint) error { 85 | *out = uint(in.Unix()) 86 | return nil 87 | } 88 | 89 | func (s stdRecipes) structToUint(c Converter, in StructValue, out *uint) error { 90 | err := s.baseStructToUint(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Uint() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToUint(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | type toUint interface { 105 | Uint() uint 106 | } 107 | type toUintWithErr interface { 108 | Uint() (uint, error) 109 | } 110 | 111 | func (s stdRecipes) baseStructToUint(_ Converter, in reflect.Value, out *uint) error { 112 | if !in.CanInterface() { 113 | return errors.New("unable to make interface") 114 | } 115 | 116 | // check for struct.Uint() 117 | if i, ok := in.Interface().(toUint); ok { 118 | *out = i.Uint() 119 | return nil 120 | } 121 | if i, ok := in.Interface().(toUintWithErr); ok { 122 | var err error 123 | *out, err = i.Uint() 124 | return err 125 | } 126 | 127 | if ok, i, err := genericIntConvert(in); ok { 128 | if err != nil { 129 | return err 130 | } 131 | *out = uint(i) 132 | return nil 133 | } 134 | 135 | return fmt.Errorf("%s has no Uint() function", in.Type().String()) 136 | } 137 | -------------------------------------------------------------------------------- /uint16.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToUint16(Converter, NilValue, *uint16) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToUint16(c Converter, in int, out *uint16) error { 15 | *out = uint16(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToUint16(c Converter, in int8, out *uint16) error { 19 | *out = uint16(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToUint16(c Converter, in int16, out *uint16) error { 23 | *out = uint16(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToUint16(c Converter, in int32, out *uint16) error { 27 | *out = uint16(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToUint16(c Converter, in int64, out *uint16) error { 31 | *out = uint16(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToUint16(c Converter, in uint, out *uint16) error { 35 | *out = uint16(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToUint16(c Converter, in uint8, out *uint16) error { 39 | *out = uint16(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToUint16(c Converter, in uint16, out *uint16) error { 43 | *out = in 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToUint16(c Converter, in uint32, out *uint16) error { 47 | *out = uint16(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToUint16(c Converter, in uint64, out *uint16) error { 51 | *out = uint16(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToUint16(c Converter, in bool, out *uint16) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToUint16(c Converter, in float32, out *uint16) error { 65 | *out = uint16(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToUint16(c Converter, in float64, out *uint16) error { 69 | *out = uint16(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToUint16(c Converter, in string, out *uint16) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseUint(in, 0, 16) 78 | if err != nil { 79 | return err 80 | } 81 | *out = uint16(i) 82 | return nil 83 | } 84 | func (stdRecipes) timeToUint16(c Converter, in time.Time, out *uint16) error { 85 | *out = uint16(in.Unix()) 86 | return nil 87 | } 88 | 89 | func (s stdRecipes) structToUint16(c Converter, in StructValue, out *uint16) error { 90 | err := s.baseStructToUint16(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Uint16() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToUint16(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | type toUint16 interface { 105 | Uint16() uint16 106 | } 107 | type toUint16WithErr interface { 108 | Uint16() (uint16, error) 109 | } 110 | 111 | func (s stdRecipes) baseStructToUint16(_ Converter, in reflect.Value, out *uint16) error { 112 | if !in.CanInterface() { 113 | return errors.New("unable to make interface") 114 | } 115 | 116 | // check for struct.Uint16() 117 | if i, ok := in.Interface().(toUint16); ok { 118 | *out = i.Uint16() 119 | return nil 120 | } 121 | if i, ok := in.Interface().(toUint16WithErr); ok { 122 | var err error 123 | *out, err = i.Uint16() 124 | return err 125 | } 126 | 127 | if ok, i, err := genericIntConvert(in); ok { 128 | if err != nil { 129 | return err 130 | } 131 | *out = uint16(i) 132 | return nil 133 | } 134 | 135 | return fmt.Errorf("%s has no Uint16() function", in.Type().String()) 136 | } 137 | -------------------------------------------------------------------------------- /uint32.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToUint32(Converter, NilValue, *uint32) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToUint32(c Converter, in int, out *uint32) error { 15 | *out = uint32(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToUint32(c Converter, in int8, out *uint32) error { 19 | *out = uint32(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToUint32(c Converter, in int16, out *uint32) error { 23 | *out = uint32(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToUint32(c Converter, in int32, out *uint32) error { 27 | *out = uint32(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToUint32(c Converter, in int64, out *uint32) error { 31 | *out = uint32(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToUint32(c Converter, in uint, out *uint32) error { 35 | *out = uint32(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToUint32(c Converter, in uint8, out *uint32) error { 39 | *out = uint32(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToUint32(c Converter, in uint16, out *uint32) error { 43 | *out = uint32(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToUint32(c Converter, in uint32, out *uint32) error { 47 | *out = in 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToUint32(c Converter, in uint64, out *uint32) error { 51 | *out = uint32(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToUint32(c Converter, in bool, out *uint32) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToUint32(c Converter, in float32, out *uint32) error { 65 | *out = uint32(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToUint32(c Converter, in float64, out *uint32) error { 69 | *out = uint32(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToUint32(c Converter, in string, out *uint32) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseUint(in, 0, 32) 78 | if err != nil { 79 | return err 80 | } 81 | *out = uint32(i) 82 | return nil 83 | } 84 | func (stdRecipes) timeToUint32(c Converter, in time.Time, out *uint32) error { 85 | *out = uint32(in.Unix()) 86 | return nil 87 | } 88 | 89 | func (s stdRecipes) structToUint32(c Converter, in StructValue, out *uint32) error { 90 | err := s.baseStructToUint32(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Uint32() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToUint32(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | type toUint32 interface { 105 | Uint32() uint32 106 | } 107 | type toUint32WithErr interface { 108 | Uint32() (uint32, error) 109 | } 110 | 111 | func (s stdRecipes) baseStructToUint32(_ Converter, in reflect.Value, out *uint32) error { 112 | if !in.CanInterface() { 113 | return errors.New("unable to make interface") 114 | } 115 | 116 | // check for struct.Uint32() 117 | if i, ok := in.Interface().(toUint32); ok { 118 | *out = i.Uint32() 119 | return nil 120 | } 121 | if i, ok := in.Interface().(toUint32WithErr); ok { 122 | var err error 123 | *out, err = i.Uint32() 124 | return err 125 | } 126 | 127 | if ok, i, err := genericIntConvert(in); ok { 128 | if err != nil { 129 | return err 130 | } 131 | *out = uint32(i) 132 | return nil 133 | } 134 | 135 | return fmt.Errorf("%s has no Uint32() function", in.Type().String()) 136 | } 137 | -------------------------------------------------------------------------------- /uint64.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToUint64(Converter, NilValue, *uint64) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToUint64(c Converter, in int, out *uint64) error { 15 | *out = uint64(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToUint64(c Converter, in int8, out *uint64) error { 19 | *out = uint64(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToUint64(c Converter, in int16, out *uint64) error { 23 | *out = uint64(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToUint64(c Converter, in int32, out *uint64) error { 27 | *out = uint64(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToUint64(c Converter, in int64, out *uint64) error { 31 | *out = uint64(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToUint64(c Converter, in uint, out *uint64) error { 35 | *out = uint64(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToUint64(c Converter, in uint8, out *uint64) error { 39 | *out = uint64(in) 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToUint64(c Converter, in uint16, out *uint64) error { 43 | *out = uint64(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToUint64(c Converter, in uint32, out *uint64) error { 47 | *out = uint64(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToUint64(c Converter, in uint64, out *uint64) error { 51 | *out = in 52 | return nil 53 | } 54 | func (stdRecipes) boolToUint64(c Converter, in bool, out *uint64) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToUint64(c Converter, in float32, out *uint64) error { 65 | *out = uint64(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToUint64(c Converter, in float64, out *uint64) error { 69 | *out = uint64(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToUint64(c Converter, in string, out *uint64) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseUint(in, 0, 64) 78 | if err != nil { 79 | return err 80 | } 81 | *out = i 82 | return nil 83 | } 84 | func (stdRecipes) timeToUint64(c Converter, in time.Time, out *uint64) error { 85 | *out = uint64(in.Unix()) 86 | return nil 87 | } 88 | 89 | func (s stdRecipes) structToUint64(c Converter, in StructValue, out *uint64) error { 90 | err := s.baseStructToUint64(c, in.Value, out) 91 | if err == nil { 92 | return err 93 | } 94 | 95 | // test for *struct.Uint64() 96 | v := reflect.New(in.Type()) 97 | v.Elem().Set(in.Value) 98 | if s.baseStructToUint64(c, v, out) == nil { 99 | return nil 100 | } 101 | return err 102 | } 103 | 104 | type toUint64 interface { 105 | Uint64() uint64 106 | } 107 | type toUint64WithErr interface { 108 | Uint64() (uint64, error) 109 | } 110 | 111 | func (s stdRecipes) baseStructToUint64(_ Converter, in reflect.Value, out *uint64) error { 112 | if !in.CanInterface() { 113 | return errors.New("unable to make interface") 114 | } 115 | 116 | // check for struct.Uint64() 117 | if i, ok := in.Interface().(toUint64); ok { 118 | *out = i.Uint64() 119 | return nil 120 | } 121 | if i, ok := in.Interface().(toUint64WithErr); ok { 122 | var err error 123 | *out, err = i.Uint64() 124 | return err 125 | } 126 | 127 | if ok, i, err := genericIntConvert(in); ok { 128 | if err != nil { 129 | return err 130 | } 131 | *out = uint64(i) 132 | return nil 133 | } 134 | 135 | return fmt.Errorf("%s has no Uint64() function", in.Type().String()) 136 | } 137 | -------------------------------------------------------------------------------- /uint8.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func (stdRecipes) nilToUint8(Converter, NilValue, *uint8) error { 12 | return nil 13 | } 14 | func (stdRecipes) intToUint8(c Converter, in int, out *uint8) error { 15 | *out = uint8(in) 16 | return nil 17 | } 18 | func (stdRecipes) int8ToUint8(c Converter, in int8, out *uint8) error { 19 | *out = uint8(in) 20 | return nil 21 | } 22 | func (stdRecipes) int16ToUint8(c Converter, in int16, out *uint8) error { 23 | *out = uint8(in) 24 | return nil 25 | } 26 | func (stdRecipes) int32ToUint8(c Converter, in int32, out *uint8) error { 27 | *out = uint8(in) 28 | return nil 29 | } 30 | func (stdRecipes) int64ToUint8(c Converter, in int64, out *uint8) error { 31 | *out = uint8(in) 32 | return nil 33 | } 34 | func (stdRecipes) uintToUint8(c Converter, in uint, out *uint8) error { 35 | *out = uint8(in) 36 | return nil 37 | } 38 | func (stdRecipes) uint8ToUint8(c Converter, in uint8, out *uint8) error { 39 | *out = in 40 | return nil 41 | } 42 | func (stdRecipes) uint16ToUint8(c Converter, in uint16, out *uint8) error { 43 | *out = uint8(in) 44 | return nil 45 | } 46 | func (stdRecipes) uint32ToUint8(c Converter, in uint32, out *uint8) error { 47 | *out = uint8(in) 48 | return nil 49 | } 50 | func (stdRecipes) uint64ToUint8(c Converter, in uint64, out *uint8) error { 51 | *out = uint8(in) 52 | return nil 53 | } 54 | func (stdRecipes) boolToUint8(c Converter, in bool, out *uint8) error { 55 | switch in { 56 | case true: 57 | *out = 1 58 | default: 59 | *out = 0 60 | } 61 | return nil 62 | } 63 | 64 | func (stdRecipes) float32ToUint8(c Converter, in float32, out *uint8) error { 65 | *out = uint8(in) 66 | return nil 67 | } 68 | func (stdRecipes) float64ToUint8(c Converter, in float64, out *uint8) error { 69 | *out = uint8(in) 70 | return nil 71 | } 72 | func (stdRecipes) stringToUint8(c Converter, in string, out *uint8) error { 73 | if in == "" { 74 | *out = 0 75 | return nil 76 | } 77 | i, err := strconv.ParseUint(in, 0, 8) 78 | if err != nil { 79 | return err 80 | } 81 | *out = uint8(i) 82 | return nil 83 | } 84 | 85 | func (stdRecipes) timeToUint8(c Converter, in time.Time, out *uint8) error { 86 | *out = uint8(in.Unix()) 87 | return nil 88 | } 89 | 90 | func (s stdRecipes) structToUint8(c Converter, in StructValue, out *uint8) error { 91 | err := s.baseStructToUint8(c, in.Value, out) 92 | if err == nil { 93 | return err 94 | } 95 | 96 | // test for *struct.Uint8() 97 | v := reflect.New(in.Type()) 98 | v.Elem().Set(in.Value) 99 | if s.baseStructToUint8(c, v, out) == nil { 100 | return nil 101 | } 102 | return err 103 | } 104 | 105 | type toUint8 interface { 106 | Uint8() uint8 107 | } 108 | type toUint8WithErr interface { 109 | Uint8() (uint8, error) 110 | } 111 | 112 | func (s stdRecipes) baseStructToUint8(_ Converter, in reflect.Value, out *uint8) error { 113 | if !in.CanInterface() { 114 | return errors.New("unable to make interface") 115 | } 116 | 117 | // check for struct.Uint8() 118 | if i, ok := in.Interface().(toUint8); ok { 119 | *out = i.Uint8() 120 | return nil 121 | } 122 | if i, ok := in.Interface().(toUint8WithErr); ok { 123 | var err error 124 | *out, err = i.Uint8() 125 | return err 126 | } 127 | 128 | if ok, i, err := genericIntConvert(in); ok { 129 | if err != nil { 130 | return err 131 | } 132 | *out = uint8(i) 133 | return nil 134 | } 135 | 136 | return fmt.Errorf("%s has no Uint8() function", in.Type().String()) 137 | } 138 | -------------------------------------------------------------------------------- /uint8_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "time" 7 | 8 | "github.com/Eun/go-convert/internal/testhelpers" 9 | ) 10 | 11 | type SomeStructWithUint8Func struct{} 12 | 13 | func (SomeStructWithUint8Func) Uint8() uint8 { 14 | return 8 15 | } 16 | 17 | type SomeStructWithUint8FuncPtr struct{} 18 | 19 | func (*SomeStructWithUint8FuncPtr) Uint8() uint8 { 20 | return 8 21 | } 22 | 23 | type SomeStructWithUint8WithErrFunc struct{} 24 | 25 | func (SomeStructWithUint8WithErrFunc) Uint8() (uint8, error) { 26 | return 8, nil 27 | } 28 | 29 | type SomeStructWithUint8WithErrFuncPtr struct{} 30 | 31 | func (*SomeStructWithUint8WithErrFuncPtr) Uint8() (uint8, error) { 32 | return 8, nil 33 | } 34 | 35 | func TestUint8(t *testing.T) { 36 | tests := []testhelpers.TestCase{ 37 | // nil 38 | {nil, uint8(0), uint8(0), "", nil}, 39 | // string 40 | {"6", uint8(0), uint8(6), "", nil}, 41 | {"", uint8(0), uint8(0), "", nil}, 42 | {"Hello World", uint8(0), uint8(0), `unable to convert string to uint8: strconv.ParseUint: parsing "Hello World": invalid syntax`, nil}, 43 | // bool 44 | {true, uint8(0), uint8(1), "", nil}, 45 | {false, uint8(0), uint8(0), "", nil}, 46 | // int 47 | {6, uint8(0), uint8(6), "", nil}, 48 | // int8 49 | {int8(6), uint8(0), uint8(6), "", nil}, 50 | // int16 51 | {int16(6), uint8(0), uint8(6), "", nil}, 52 | // int32 53 | {int32(6), uint8(0), uint8(6), "", nil}, 54 | // int64 55 | {int64(6), uint8(0), uint8(6), "", nil}, 56 | // uint 57 | {uint(6), uint8(0), uint8(6), "", nil}, 58 | // int8 59 | {uint8(6), uint8(0), uint8(6), "", nil}, 60 | // uint16 61 | {uint16(6), uint8(0), uint8(6), "", nil}, 62 | // uint32 63 | {uint32(6), uint8(0), uint8(6), "", nil}, 64 | // uint64 65 | {uint64(6), uint8(0), uint8(6), "", nil}, 66 | // float32 67 | {float32(6), uint8(0), uint8(6), "", nil}, 68 | // float64 69 | {float64(6), uint8(0), uint8(6), "", nil}, 70 | // slice 71 | {[]int{'H', 'e', 'l', 'l', 'o'}, uint8(0), uint8(0), "unable to convert []int to uint8: no recipe", nil}, 72 | {[]byte{'H', 'e', 'l', 'l', 'o'}, uint8(0), uint8(0), "unable to convert []uint8 to uint8: no recipe", nil}, 73 | {[]rune{'H', 'e', 'l', 'l', 'o'}, uint8(0), uint8(0), "unable to convert []int32 to uint8: no recipe", nil}, 74 | {[]string{"H", "e", "l", "l", "o"}, uint8(0), uint8(0), "unable to convert []string to uint8: no recipe", nil}, 75 | // struct 76 | {struct{}{}, uint8(0), uint8(0), "unable to convert struct {} to uint8: struct {} has no Uint8() function", nil}, 77 | // time 78 | {time.Unix(10, 10), uint8(10), uint8(10), "", nil}, 79 | 80 | {SomeStructWithIntFunc{}, uint8(0), uint8(8), "", nil}, 81 | {&SomeStructWithIntFunc{}, uint8(0), uint8(8), "", nil}, 82 | 83 | {SomeStructWithIntFuncPtr{}, uint8(0), uint8(8), "", nil}, 84 | {&SomeStructWithIntFuncPtr{}, uint8(0), uint8(8), "", nil}, 85 | 86 | {SomeStructWithIntWithErrFunc{}, uint8(0), uint8(8), "", nil}, 87 | {&SomeStructWithIntWithErrFunc{}, uint8(0), uint8(8), "", nil}, 88 | 89 | {SomeStructWithIntWithErrFuncPtr{}, uint8(0), uint8(8), "", nil}, 90 | {&SomeStructWithIntWithErrFuncPtr{}, uint8(0), uint8(8), "", nil}, 91 | 92 | {SomeStructWithInt8Func{}, uint8(0), uint8(8), "", nil}, 93 | {&SomeStructWithInt8Func{}, uint8(0), uint8(8), "", nil}, 94 | 95 | {SomeStructWithInt8FuncPtr{}, uint8(0), uint8(8), "", nil}, 96 | {&SomeStructWithInt8FuncPtr{}, uint8(0), uint8(8), "", nil}, 97 | 98 | {SomeStructWithInt8WithErrFunc{}, uint8(0), uint8(8), "", nil}, 99 | {&SomeStructWithInt8WithErrFunc{}, uint8(0), uint8(8), "", nil}, 100 | 101 | {SomeStructWithInt8WithErrFuncPtr{}, uint8(0), uint8(8), "", nil}, 102 | {&SomeStructWithInt8WithErrFuncPtr{}, uint8(0), uint8(8), "", nil}, 103 | 104 | {SomeStructWithInt16Func{}, uint8(0), uint8(16), "", nil}, 105 | {&SomeStructWithInt16Func{}, uint8(0), uint8(16), "", nil}, 106 | 107 | {SomeStructWithInt16FuncPtr{}, uint8(0), uint8(16), "", nil}, 108 | {&SomeStructWithInt16FuncPtr{}, uint8(0), uint8(16), "", nil}, 109 | 110 | {SomeStructWithInt16WithErrFunc{}, uint8(0), uint8(16), "", nil}, 111 | {&SomeStructWithInt16WithErrFunc{}, uint8(0), uint8(16), "", nil}, 112 | 113 | {SomeStructWithInt16WithErrFuncPtr{}, uint8(0), uint8(16), "", nil}, 114 | {&SomeStructWithInt16WithErrFuncPtr{}, uint8(0), uint8(16), "", nil}, 115 | 116 | {SomeStructWithInt32Func{}, uint8(0), uint8(32), "", nil}, 117 | {&SomeStructWithInt32Func{}, uint8(0), uint8(32), "", nil}, 118 | 119 | {SomeStructWithInt32FuncPtr{}, uint8(0), uint8(32), "", nil}, 120 | {&SomeStructWithInt32FuncPtr{}, uint8(0), uint8(32), "", nil}, 121 | 122 | {SomeStructWithInt32WithErrFunc{}, uint8(0), uint8(32), "", nil}, 123 | {&SomeStructWithInt32WithErrFunc{}, uint8(0), uint8(32), "", nil}, 124 | 125 | {SomeStructWithInt32WithErrFuncPtr{}, uint8(0), uint8(32), "", nil}, 126 | {&SomeStructWithInt32WithErrFuncPtr{}, uint8(0), uint8(32), "", nil}, 127 | 128 | {SomeStructWithInt64Func{}, uint8(0), uint8(64), "", nil}, 129 | {&SomeStructWithInt64Func{}, uint8(0), uint8(64), "", nil}, 130 | 131 | {SomeStructWithInt64FuncPtr{}, uint8(0), uint8(64), "", nil}, 132 | {&SomeStructWithInt64FuncPtr{}, uint8(0), uint8(64), "", nil}, 133 | 134 | {SomeStructWithInt64WithErrFunc{}, uint8(0), uint8(64), "", nil}, 135 | {&SomeStructWithInt64WithErrFunc{}, uint8(0), uint8(64), "", nil}, 136 | 137 | {SomeStructWithInt64WithErrFuncPtr{}, uint8(0), uint8(64), "", nil}, 138 | {&SomeStructWithInt64WithErrFuncPtr{}, uint8(0), uint8(64), "", nil}, 139 | 140 | {SomeStructWithUintFunc{}, uint8(0), uint8(16), "", nil}, 141 | {&SomeStructWithUintFunc{}, uint8(0), uint8(16), "", nil}, 142 | 143 | {SomeStructWithUintFuncPtr{}, uint8(0), uint8(16), "", nil}, 144 | {&SomeStructWithUintFuncPtr{}, uint8(0), uint8(16), "", nil}, 145 | 146 | {SomeStructWithUintWithErrFunc{}, uint8(0), uint8(16), "", nil}, 147 | {&SomeStructWithUintWithErrFunc{}, uint8(0), uint8(16), "", nil}, 148 | 149 | {SomeStructWithUintWithErrFuncPtr{}, uint8(0), uint8(16), "", nil}, 150 | {&SomeStructWithUintWithErrFuncPtr{}, uint8(0), uint8(16), "", nil}, 151 | 152 | {SomeStructWithUint8Func{}, uint8(0), uint8(8), "", nil}, 153 | {&SomeStructWithUint8Func{}, uint8(0), uint8(8), "", nil}, 154 | 155 | {SomeStructWithUint8FuncPtr{}, uint8(0), uint8(8), "", nil}, 156 | {&SomeStructWithUint8FuncPtr{}, uint8(0), uint8(8), "", nil}, 157 | 158 | {SomeStructWithUint8WithErrFunc{}, uint8(0), uint8(8), "", nil}, 159 | {&SomeStructWithUint8WithErrFunc{}, uint8(0), uint8(8), "", nil}, 160 | 161 | {SomeStructWithUint8WithErrFuncPtr{}, uint8(0), uint8(8), "", nil}, 162 | {&SomeStructWithUint8WithErrFuncPtr{}, uint8(0), uint8(8), "", nil}, 163 | 164 | {SomeStructWithUint16Func{}, uint8(0), uint8(16), "", nil}, 165 | {&SomeStructWithUint16Func{}, uint8(0), uint8(16), "", nil}, 166 | 167 | {SomeStructWithUint16FuncPtr{}, uint8(0), uint8(16), "", nil}, 168 | {&SomeStructWithUint16FuncPtr{}, uint8(0), uint8(16), "", nil}, 169 | 170 | {SomeStructWithUint16WithErrFunc{}, uint8(0), uint8(16), "", nil}, 171 | {&SomeStructWithUint16WithErrFunc{}, uint8(0), uint8(16), "", nil}, 172 | 173 | {SomeStructWithUint16WithErrFuncPtr{}, uint8(0), uint8(16), "", nil}, 174 | {&SomeStructWithUint16WithErrFuncPtr{}, uint8(0), uint8(16), "", nil}, 175 | 176 | {SomeStructWithUint32Func{}, uint8(0), uint8(32), "", nil}, 177 | {&SomeStructWithUint32Func{}, uint8(0), uint8(32), "", nil}, 178 | 179 | {SomeStructWithUint32FuncPtr{}, uint8(0), uint8(32), "", nil}, 180 | {&SomeStructWithUint32FuncPtr{}, uint8(0), uint8(32), "", nil}, 181 | 182 | {SomeStructWithUint32WithErrFunc{}, uint8(0), uint8(32), "", nil}, 183 | {&SomeStructWithUint32WithErrFunc{}, uint8(0), uint8(32), "", nil}, 184 | 185 | {SomeStructWithUint32WithErrFuncPtr{}, uint8(0), uint8(32), "", nil}, 186 | {&SomeStructWithUint32WithErrFuncPtr{}, uint8(0), uint8(32), "", nil}, 187 | 188 | {SomeStructWithUint64Func{}, uint8(0), uint8(64), "", nil}, 189 | {&SomeStructWithUint64Func{}, uint8(0), uint8(64), "", nil}, 190 | 191 | {SomeStructWithUint64FuncPtr{}, uint8(0), uint8(64), "", nil}, 192 | {&SomeStructWithUint64FuncPtr{}, uint8(0), uint8(64), "", nil}, 193 | 194 | {SomeStructWithUint64WithErrFunc{}, uint8(0), uint8(64), "", nil}, 195 | {&SomeStructWithUint64WithErrFunc{}, uint8(0), uint8(64), "", nil}, 196 | 197 | {SomeStructWithUint64WithErrFuncPtr{}, uint8(0), uint8(64), "", nil}, 198 | {&SomeStructWithUint64WithErrFuncPtr{}, uint8(0), uint8(64), "", nil}, 199 | } 200 | 201 | for i, test := range tests { 202 | testhelpers.RunTest(t, test, i) 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /uint_test.go: -------------------------------------------------------------------------------- 1 | package convert_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "time" 7 | 8 | "github.com/Eun/go-convert/internal/testhelpers" 9 | ) 10 | 11 | type SomeStructWithUintFunc struct{} 12 | 13 | func (SomeStructWithUintFunc) Uint() uint { 14 | return 16 15 | } 16 | 17 | type SomeStructWithUintFuncPtr struct{} 18 | 19 | func (*SomeStructWithUintFuncPtr) Uint() uint { 20 | return 16 21 | } 22 | 23 | type SomeStructWithUintWithErrFunc struct{} 24 | 25 | func (SomeStructWithUintWithErrFunc) Uint() (uint, error) { 26 | return 16, nil 27 | } 28 | 29 | type SomeStructWithUintWithErrFuncPtr struct{} 30 | 31 | func (*SomeStructWithUintWithErrFuncPtr) Uint() (uint, error) { 32 | return 16, nil 33 | } 34 | 35 | func TestUint(t *testing.T) { 36 | tests := []testhelpers.TestCase{ 37 | // nil 38 | {nil, uint(0), uint(0), "", nil}, 39 | // string 40 | {"6", uint(0), uint(6), "", nil}, 41 | {"Hello World", uint(0), uint(0), `unable to convert string to uint: strconv.ParseUint: parsing "Hello World": invalid syntax`, nil}, 42 | // bool 43 | {true, uint(0), uint(1), "", nil}, 44 | {false, uint(0), uint(0), "", nil}, 45 | // int 46 | {6, uint(0), uint(6), "", nil}, 47 | // int8 48 | {int8(6), uint(0), uint(6), "", nil}, 49 | // int16 50 | {int16(6), uint(0), uint(6), "", nil}, 51 | // int32 52 | {int32(6), uint(0), uint(6), "", nil}, 53 | // int64 54 | {int64(6), uint(0), uint(6), "", nil}, 55 | // uint 56 | {uint(6), uint(0), uint(6), "", nil}, 57 | // uint8 58 | {uint8(6), uint(0), uint(6), "", nil}, 59 | // uint16 60 | {uint16(6), uint(0), uint(6), "", nil}, 61 | // uint32 62 | {uint32(6), uint(0), uint(6), "", nil}, 63 | // uint64 64 | {uint64(6), uint(0), uint(6), "", nil}, 65 | // float32 66 | {float32(6), uint(0), uint(6), "", nil}, 67 | // float64 68 | {float64(6), uint(0), uint(6), "", nil}, 69 | // slice 70 | {[]int{'H', 'e', 'l', 'l', 'o'}, uint(0), uint(0), "unable to convert []int to uint: no recipe", nil}, 71 | {[]byte{'H', 'e', 'l', 'l', 'o'}, uint(0), uint(0), "unable to convert []uint8 to uint: no recipe", nil}, 72 | {[]rune{'H', 'e', 'l', 'l', 'o'}, uint(0), uint(0), "unable to convert []int32 to uint: no recipe", nil}, 73 | {[]string{"H", "e", "l", "l", "o"}, uint(0), uint(0), "unable to convert []string to uint: no recipe", nil}, 74 | // struct 75 | {struct{}{}, uint(0), uint(0), "unable to convert struct {} to uint: struct {} has no Uint() function", nil}, 76 | // time 77 | {time.Unix(10, 10), uint(10), uint(10), "", nil}, 78 | 79 | {SomeStructWithIntFunc{}, uint(0), uint(8), "", nil}, 80 | {&SomeStructWithIntFunc{}, uint(0), uint(8), "", nil}, 81 | 82 | {SomeStructWithIntFuncPtr{}, uint(0), uint(8), "", nil}, 83 | {&SomeStructWithIntFuncPtr{}, uint(0), uint(8), "", nil}, 84 | 85 | {SomeStructWithIntWithErrFunc{}, uint(0), uint(8), "", nil}, 86 | {&SomeStructWithIntWithErrFunc{}, uint(0), uint(8), "", nil}, 87 | 88 | {SomeStructWithIntWithErrFuncPtr{}, uint(0), uint(8), "", nil}, 89 | {&SomeStructWithIntWithErrFuncPtr{}, uint(0), uint(8), "", nil}, 90 | 91 | {SomeStructWithInt8Func{}, uint(0), uint(8), "", nil}, 92 | {&SomeStructWithInt8Func{}, uint(0), uint(8), "", nil}, 93 | 94 | {SomeStructWithInt8FuncPtr{}, uint(0), uint(8), "", nil}, 95 | {&SomeStructWithInt8FuncPtr{}, uint(0), uint(8), "", nil}, 96 | 97 | {SomeStructWithInt8WithErrFunc{}, uint(0), uint(8), "", nil}, 98 | {&SomeStructWithInt8WithErrFunc{}, uint(0), uint(8), "", nil}, 99 | 100 | {SomeStructWithInt8WithErrFuncPtr{}, uint(0), uint(8), "", nil}, 101 | {&SomeStructWithInt8WithErrFuncPtr{}, uint(0), uint(8), "", nil}, 102 | 103 | {SomeStructWithInt16Func{}, uint(0), uint(16), "", nil}, 104 | {&SomeStructWithInt16Func{}, uint(0), uint(16), "", nil}, 105 | 106 | {SomeStructWithInt16FuncPtr{}, uint(0), uint(16), "", nil}, 107 | {&SomeStructWithInt16FuncPtr{}, uint(0), uint(16), "", nil}, 108 | 109 | {SomeStructWithInt16WithErrFunc{}, uint(0), uint(16), "", nil}, 110 | {&SomeStructWithInt16WithErrFunc{}, uint(0), uint(16), "", nil}, 111 | 112 | {SomeStructWithInt16WithErrFuncPtr{}, uint(0), uint(16), "", nil}, 113 | {&SomeStructWithInt16WithErrFuncPtr{}, uint(0), uint(16), "", nil}, 114 | 115 | {SomeStructWithInt32Func{}, uint(0), uint(32), "", nil}, 116 | {&SomeStructWithInt32Func{}, uint(0), uint(32), "", nil}, 117 | 118 | {SomeStructWithInt32FuncPtr{}, uint(0), uint(32), "", nil}, 119 | {&SomeStructWithInt32FuncPtr{}, uint(0), uint(32), "", nil}, 120 | 121 | {SomeStructWithInt32WithErrFunc{}, uint(0), uint(32), "", nil}, 122 | {&SomeStructWithInt32WithErrFunc{}, uint(0), uint(32), "", nil}, 123 | 124 | {SomeStructWithInt32WithErrFuncPtr{}, uint(0), uint(32), "", nil}, 125 | {&SomeStructWithInt32WithErrFuncPtr{}, uint(0), uint(32), "", nil}, 126 | 127 | {SomeStructWithInt64Func{}, uint(0), uint(64), "", nil}, 128 | {&SomeStructWithInt64Func{}, uint(0), uint(64), "", nil}, 129 | 130 | {SomeStructWithInt64FuncPtr{}, uint(0), uint(64), "", nil}, 131 | {&SomeStructWithInt64FuncPtr{}, uint(0), uint(64), "", nil}, 132 | 133 | {SomeStructWithInt64WithErrFunc{}, uint(0), uint(64), "", nil}, 134 | {&SomeStructWithInt64WithErrFunc{}, uint(0), uint(64), "", nil}, 135 | 136 | {SomeStructWithInt64WithErrFuncPtr{}, uint(0), uint(64), "", nil}, 137 | {&SomeStructWithInt64WithErrFuncPtr{}, uint(0), uint(64), "", nil}, 138 | 139 | {SomeStructWithUintFunc{}, uint(0), uint(16), "", nil}, 140 | {&SomeStructWithUintFunc{}, uint(0), uint(16), "", nil}, 141 | 142 | {SomeStructWithUintFuncPtr{}, uint(0), uint(16), "", nil}, 143 | {&SomeStructWithUintFuncPtr{}, uint(0), uint(16), "", nil}, 144 | 145 | {SomeStructWithUintWithErrFunc{}, uint(0), uint(16), "", nil}, 146 | {&SomeStructWithUintWithErrFunc{}, uint(0), uint(16), "", nil}, 147 | 148 | {SomeStructWithUintWithErrFuncPtr{}, uint(0), uint(16), "", nil}, 149 | {&SomeStructWithUintWithErrFuncPtr{}, uint(0), uint(16), "", nil}, 150 | 151 | {SomeStructWithUint8Func{}, uint(0), uint(8), "", nil}, 152 | {&SomeStructWithUint8Func{}, uint(0), uint(8), "", nil}, 153 | 154 | {SomeStructWithUint8FuncPtr{}, uint(0), uint(8), "", nil}, 155 | {&SomeStructWithUint8FuncPtr{}, uint(0), uint(8), "", nil}, 156 | 157 | {SomeStructWithUint8WithErrFunc{}, uint(0), uint(8), "", nil}, 158 | {&SomeStructWithUint8WithErrFunc{}, uint(0), uint(8), "", nil}, 159 | 160 | {SomeStructWithUint8WithErrFuncPtr{}, uint(0), uint(8), "", nil}, 161 | {&SomeStructWithUint8WithErrFuncPtr{}, uint(0), uint(8), "", nil}, 162 | 163 | {SomeStructWithUint16Func{}, uint(0), uint(16), "", nil}, 164 | {&SomeStructWithUint16Func{}, uint(0), uint(16), "", nil}, 165 | 166 | {SomeStructWithUint16FuncPtr{}, uint(0), uint(16), "", nil}, 167 | {&SomeStructWithUint16FuncPtr{}, uint(0), uint(16), "", nil}, 168 | 169 | {SomeStructWithUint16WithErrFunc{}, uint(0), uint(16), "", nil}, 170 | {&SomeStructWithUint16WithErrFunc{}, uint(0), uint(16), "", nil}, 171 | 172 | {SomeStructWithUint16WithErrFuncPtr{}, uint(0), uint(16), "", nil}, 173 | {&SomeStructWithUint16WithErrFuncPtr{}, uint(0), uint(16), "", nil}, 174 | 175 | {SomeStructWithUint32Func{}, uint(0), uint(32), "", nil}, 176 | {&SomeStructWithUint32Func{}, uint(0), uint(32), "", nil}, 177 | 178 | {SomeStructWithUint32FuncPtr{}, uint(0), uint(32), "", nil}, 179 | {&SomeStructWithUint32FuncPtr{}, uint(0), uint(32), "", nil}, 180 | 181 | {SomeStructWithUint32WithErrFunc{}, uint(0), uint(32), "", nil}, 182 | {&SomeStructWithUint32WithErrFunc{}, uint(0), uint(32), "", nil}, 183 | 184 | {SomeStructWithUint32WithErrFuncPtr{}, uint(0), uint(32), "", nil}, 185 | {&SomeStructWithUint32WithErrFuncPtr{}, uint(0), uint(32), "", nil}, 186 | 187 | {SomeStructWithUint64Func{}, uint(0), uint(64), "", nil}, 188 | {&SomeStructWithUint64Func{}, uint(0), uint(64), "", nil}, 189 | 190 | {SomeStructWithUint64FuncPtr{}, uint(0), uint(64), "", nil}, 191 | {&SomeStructWithUint64FuncPtr{}, uint(0), uint(64), "", nil}, 192 | 193 | {SomeStructWithUint64WithErrFunc{}, uint(0), uint(64), "", nil}, 194 | {&SomeStructWithUint64WithErrFunc{}, uint(0), uint(64), "", nil}, 195 | 196 | {SomeStructWithUint64WithErrFuncPtr{}, uint(0), uint(64), "", nil}, 197 | {&SomeStructWithUint64WithErrFuncPtr{}, uint(0), uint(64), "", nil}, 198 | } 199 | 200 | for i, test := range tests { 201 | testhelpers.RunTest(t, test, i) 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /vendor/github.com/araddon/dateparse/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.10.x 5 | - 1.11.x 6 | 7 | before_install: 8 | - go get -t -v ./... 9 | 10 | script: 11 | - go test -race -coverprofile=coverage.txt -covermode=atomic 12 | 13 | after_success: 14 | - bash <(curl -s https://codecov.io/bash) 15 | -------------------------------------------------------------------------------- /vendor/github.com/araddon/dateparse/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 Aaron Raddon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2016 Dave Collins 4 | 5 | Permission to use, copy, modify, and distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypass.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is not running on Google App Engine, compiled by GopherJS, and 17 | // "-tags safe" is not added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build !js,!appengine,!safe,!disableunsafe 20 | 21 | package spew 22 | 23 | import ( 24 | "reflect" 25 | "unsafe" 26 | ) 27 | 28 | const ( 29 | // UnsafeDisabled is a build-time constant which specifies whether or 30 | // not access to the unsafe package is available. 31 | UnsafeDisabled = false 32 | 33 | // ptrSize is the size of a pointer on the current arch. 34 | ptrSize = unsafe.Sizeof((*byte)(nil)) 35 | ) 36 | 37 | var ( 38 | // offsetPtr, offsetScalar, and offsetFlag are the offsets for the 39 | // internal reflect.Value fields. These values are valid before golang 40 | // commit ecccf07e7f9d which changed the format. The are also valid 41 | // after commit 82f48826c6c7 which changed the format again to mirror 42 | // the original format. Code in the init function updates these offsets 43 | // as necessary. 44 | offsetPtr = uintptr(ptrSize) 45 | offsetScalar = uintptr(0) 46 | offsetFlag = uintptr(ptrSize * 2) 47 | 48 | // flagKindWidth and flagKindShift indicate various bits that the 49 | // reflect package uses internally to track kind information. 50 | // 51 | // flagRO indicates whether or not the value field of a reflect.Value is 52 | // read-only. 53 | // 54 | // flagIndir indicates whether the value field of a reflect.Value is 55 | // the actual data or a pointer to the data. 56 | // 57 | // These values are valid before golang commit 90a7c3c86944 which 58 | // changed their positions. Code in the init function updates these 59 | // flags as necessary. 60 | flagKindWidth = uintptr(5) 61 | flagKindShift = uintptr(flagKindWidth - 1) 62 | flagRO = uintptr(1 << 0) 63 | flagIndir = uintptr(1 << 1) 64 | ) 65 | 66 | func init() { 67 | // Older versions of reflect.Value stored small integers directly in the 68 | // ptr field (which is named val in the older versions). Versions 69 | // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named 70 | // scalar for this purpose which unfortunately came before the flag 71 | // field, so the offset of the flag field is different for those 72 | // versions. 73 | // 74 | // This code constructs a new reflect.Value from a known small integer 75 | // and checks if the size of the reflect.Value struct indicates it has 76 | // the scalar field. When it does, the offsets are updated accordingly. 77 | vv := reflect.ValueOf(0xf00) 78 | if unsafe.Sizeof(vv) == (ptrSize * 4) { 79 | offsetScalar = ptrSize * 2 80 | offsetFlag = ptrSize * 3 81 | } 82 | 83 | // Commit 90a7c3c86944 changed the flag positions such that the low 84 | // order bits are the kind. This code extracts the kind from the flags 85 | // field and ensures it's the correct type. When it's not, the flag 86 | // order has been changed to the newer format, so the flags are updated 87 | // accordingly. 88 | upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) 89 | upfv := *(*uintptr)(upf) 90 | flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { 92 | flagKindShift = 0 93 | flagRO = 1 << 5 94 | flagIndir = 1 << 6 95 | 96 | // Commit adf9b30e5594 modified the flags to separate the 97 | // flagRO flag into two bits which specifies whether or not the 98 | // field is embedded. This causes flagIndir to move over a bit 99 | // and means that flagRO is the combination of either of the 100 | // original flagRO bit and the new bit. 101 | // 102 | // This code detects the change by extracting what used to be 103 | // the indirect bit to ensure it's set. When it's not, the flag 104 | // order has been changed to the newer format, so the flags are 105 | // updated accordingly. 106 | if upfv&flagIndir == 0 { 107 | flagRO = 3 << 5 108 | flagIndir = 1 << 7 109 | } 110 | } 111 | } 112 | 113 | // unsafeReflectValue converts the passed reflect.Value into a one that bypasses 114 | // the typical safety restrictions preventing access to unaddressable and 115 | // unexported data. It works by digging the raw pointer to the underlying 116 | // value out of the protected value and generating a new unprotected (unsafe) 117 | // reflect.Value to it. 118 | // 119 | // This allows us to check for implementations of the Stringer and error 120 | // interfaces to be used for pretty printing ordinarily unaddressable and 121 | // inaccessible values such as unexported struct fields. 122 | func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { 123 | indirects := 1 124 | vt := v.Type() 125 | upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) 126 | rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) 127 | if rvf&flagIndir != 0 { 128 | vt = reflect.PtrTo(v.Type()) 129 | indirects++ 130 | } else if offsetScalar != 0 { 131 | // The value is in the scalar field when it's not one of the 132 | // reference types. 133 | switch vt.Kind() { 134 | case reflect.Uintptr: 135 | case reflect.Chan: 136 | case reflect.Func: 137 | case reflect.Map: 138 | case reflect.Ptr: 139 | case reflect.UnsafePointer: 140 | default: 141 | upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + 142 | offsetScalar) 143 | } 144 | } 145 | 146 | pv := reflect.NewAt(vt, upv) 147 | rv = pv 148 | for i := 0; i < indirects; i++ { 149 | rv = rv.Elem() 150 | } 151 | return rv 152 | } 153 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypasssafe.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is running on Google App Engine, compiled by GopherJS, or 17 | // "-tags safe" is added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build js appengine safe disableunsafe 20 | 21 | package spew 22 | 23 | import "reflect" 24 | 25 | const ( 26 | // UnsafeDisabled is a build-time constant which specifies whether or 27 | // not access to the unsafe package is available. 28 | UnsafeDisabled = true 29 | ) 30 | 31 | // unsafeReflectValue typically converts the passed reflect.Value into a one 32 | // that bypasses the typical safety restrictions preventing access to 33 | // unaddressable and unexported data. However, doing this relies on access to 34 | // the unsafe package. This is a stub version which simply returns the passed 35 | // reflect.Value when the unsafe package is not available. 36 | func unsafeReflectValue(v reflect.Value) reflect.Value { 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/spew.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | ) 23 | 24 | // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were 25 | // passed with a default Formatter interface returned by NewFormatter. It 26 | // returns the formatted string as a value that satisfies error. See 27 | // NewFormatter for formatting details. 28 | // 29 | // This function is shorthand for the following syntax: 30 | // 31 | // fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 32 | func Errorf(format string, a ...interface{}) (err error) { 33 | return fmt.Errorf(format, convertArgs(a)...) 34 | } 35 | 36 | // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were 37 | // passed with a default Formatter interface returned by NewFormatter. It 38 | // returns the number of bytes written and any write error encountered. See 39 | // NewFormatter for formatting details. 40 | // 41 | // This function is shorthand for the following syntax: 42 | // 43 | // fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) 44 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) { 45 | return fmt.Fprint(w, convertArgs(a)...) 46 | } 47 | 48 | // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were 49 | // passed with a default Formatter interface returned by NewFormatter. It 50 | // returns the number of bytes written and any write error encountered. See 51 | // NewFormatter for formatting details. 52 | // 53 | // This function is shorthand for the following syntax: 54 | // 55 | // fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) 56 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 57 | return fmt.Fprintf(w, format, convertArgs(a)...) 58 | } 59 | 60 | // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it 61 | // passed with a default Formatter interface returned by NewFormatter. See 62 | // NewFormatter for formatting details. 63 | // 64 | // This function is shorthand for the following syntax: 65 | // 66 | // fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) 67 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 68 | return fmt.Fprintln(w, convertArgs(a)...) 69 | } 70 | 71 | // Print is a wrapper for fmt.Print that treats each argument as if it were 72 | // passed with a default Formatter interface returned by NewFormatter. It 73 | // returns the number of bytes written and any write error encountered. See 74 | // NewFormatter for formatting details. 75 | // 76 | // This function is shorthand for the following syntax: 77 | // 78 | // fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) 79 | func Print(a ...interface{}) (n int, err error) { 80 | return fmt.Print(convertArgs(a)...) 81 | } 82 | 83 | // Printf is a wrapper for fmt.Printf that treats each argument as if it were 84 | // passed with a default Formatter interface returned by NewFormatter. It 85 | // returns the number of bytes written and any write error encountered. See 86 | // NewFormatter for formatting details. 87 | // 88 | // This function is shorthand for the following syntax: 89 | // 90 | // fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 91 | func Printf(format string, a ...interface{}) (n int, err error) { 92 | return fmt.Printf(format, convertArgs(a)...) 93 | } 94 | 95 | // Println is a wrapper for fmt.Println that treats each argument as if it were 96 | // passed with a default Formatter interface returned by NewFormatter. It 97 | // returns the number of bytes written and any write error encountered. See 98 | // NewFormatter for formatting details. 99 | // 100 | // This function is shorthand for the following syntax: 101 | // 102 | // fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) 103 | func Println(a ...interface{}) (n int, err error) { 104 | return fmt.Println(convertArgs(a)...) 105 | } 106 | 107 | // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were 108 | // passed with a default Formatter interface returned by NewFormatter. It 109 | // returns the resulting string. See NewFormatter for formatting details. 110 | // 111 | // This function is shorthand for the following syntax: 112 | // 113 | // fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) 114 | func Sprint(a ...interface{}) string { 115 | return fmt.Sprint(convertArgs(a)...) 116 | } 117 | 118 | // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were 119 | // passed with a default Formatter interface returned by NewFormatter. It 120 | // returns the resulting string. See NewFormatter for formatting details. 121 | // 122 | // This function is shorthand for the following syntax: 123 | // 124 | // fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 125 | func Sprintf(format string, a ...interface{}) string { 126 | return fmt.Sprintf(format, convertArgs(a)...) 127 | } 128 | 129 | // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it 130 | // were passed with a default Formatter interface returned by NewFormatter. It 131 | // returns the resulting string. See NewFormatter for formatting details. 132 | // 133 | // This function is shorthand for the following syntax: 134 | // 135 | // fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) 136 | func Sprintln(a ...interface{}) string { 137 | return fmt.Sprintln(convertArgs(a)...) 138 | } 139 | 140 | // convertArgs accepts a slice of arguments and returns a slice of the same 141 | // length with each argument converted to a default spew Formatter interface. 142 | func convertArgs(args []interface{}) (formatters []interface{}) { 143 | formatters = make([]interface{}, len(args)) 144 | for index, arg := range args { 145 | formatters[index] = NewFormatter(arg) 146 | } 147 | return formatters 148 | } 149 | -------------------------------------------------------------------------------- /vendor/github.com/pmezard/go-difflib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Patrick Mezard 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | The names of its contributors may not be used to endorse or promote 14 | products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentFormat}} 2 | func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_order.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // isOrdered checks that collection contains orderable elements. 9 | func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { 10 | objKind := reflect.TypeOf(object).Kind() 11 | if objKind != reflect.Slice && objKind != reflect.Array { 12 | return false 13 | } 14 | 15 | objValue := reflect.ValueOf(object) 16 | objLen := objValue.Len() 17 | 18 | if objLen <= 1 { 19 | return true 20 | } 21 | 22 | value := objValue.Index(0) 23 | valueInterface := value.Interface() 24 | firstValueKind := value.Kind() 25 | 26 | for i := 1; i < objLen; i++ { 27 | prevValue := value 28 | prevValueInterface := valueInterface 29 | 30 | value = objValue.Index(i) 31 | valueInterface = value.Interface() 32 | 33 | compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind) 34 | 35 | if !isComparable { 36 | return Fail(t, fmt.Sprintf("Can not compare type \"%s\" and \"%s\"", reflect.TypeOf(value), reflect.TypeOf(prevValue)), msgAndArgs...) 37 | } 38 | 39 | if !containsValue(allowedComparesResults, compareResult) { 40 | return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...) 41 | } 42 | } 43 | 44 | return true 45 | } 46 | 47 | // IsIncreasing asserts that the collection is increasing 48 | // 49 | // assert.IsIncreasing(t, []int{1, 2, 3}) 50 | // assert.IsIncreasing(t, []float{1, 2}) 51 | // assert.IsIncreasing(t, []string{"a", "b"}) 52 | func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 53 | return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) 54 | } 55 | 56 | // IsNonIncreasing asserts that the collection is not increasing 57 | // 58 | // assert.IsNonIncreasing(t, []int{2, 1, 1}) 59 | // assert.IsNonIncreasing(t, []float{2, 1}) 60 | // assert.IsNonIncreasing(t, []string{"b", "a"}) 61 | func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 62 | return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) 63 | } 64 | 65 | // IsDecreasing asserts that the collection is decreasing 66 | // 67 | // assert.IsDecreasing(t, []int{2, 1, 0}) 68 | // assert.IsDecreasing(t, []float{2, 1}) 69 | // assert.IsDecreasing(t, []string{"b", "a"}) 70 | func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 71 | return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) 72 | } 73 | 74 | // IsNonDecreasing asserts that the collection is not decreasing 75 | // 76 | // assert.IsNonDecreasing(t, []int{1, 1, 2}) 77 | // assert.IsNonDecreasing(t, []float{1, 2}) 78 | // assert.IsNonDecreasing(t, []string{"a", "b"}) 79 | func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 80 | return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) 81 | } 82 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // Example Usage 4 | // 5 | // The following is a complete example using assert in a standard test function: 6 | // import ( 7 | // "testing" 8 | // "github.com/stretchr/testify/assert" 9 | // ) 10 | // 11 | // func TestSomething(t *testing.T) { 12 | // 13 | // var a string = "Hello" 14 | // var b string = "Hello" 15 | // 16 | // assert.Equal(t, a, b, "The two words should be the same.") 17 | // 18 | // } 19 | // 20 | // if you assert many times, use the format below: 21 | // 22 | // import ( 23 | // "testing" 24 | // "github.com/stretchr/testify/assert" 25 | // ) 26 | // 27 | // func TestSomething(t *testing.T) { 28 | // assert := assert.New(t) 29 | // 30 | // var a string = "Hello" 31 | // var b string = "Hello" 32 | // 33 | // assert.Equal(a, b, "The two words should be the same.") 34 | // } 35 | // 36 | // Assertions 37 | // 38 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 39 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 40 | // testing framework. This allows the assertion funcs to write the failings and other details to 41 | // the correct place. 42 | // 43 | // Every assertion function also takes an optional string message as the final argument, 44 | // allowing custom error messages to be appended to the message the assertion method outputs. 45 | package assert 46 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/forward_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs" 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/http_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/http/httptest" 7 | "net/url" 8 | "strings" 9 | ) 10 | 11 | // httpCode is a helper that returns HTTP code of the response. It returns -1 and 12 | // an error if building a new request fails. 13 | func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { 14 | w := httptest.NewRecorder() 15 | req, err := http.NewRequest(method, url, nil) 16 | if err != nil { 17 | return -1, err 18 | } 19 | req.URL.RawQuery = values.Encode() 20 | handler(w, req) 21 | return w.Code, nil 22 | } 23 | 24 | // HTTPSuccess asserts that a specified handler returns a success status code. 25 | // 26 | // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) 27 | // 28 | // Returns whether the assertion was successful (true) or not (false). 29 | func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 30 | if h, ok := t.(tHelper); ok { 31 | h.Helper() 32 | } 33 | code, err := httpCode(handler, method, url, values) 34 | if err != nil { 35 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 36 | } 37 | 38 | isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent 39 | if !isSuccessCode { 40 | Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code)) 41 | } 42 | 43 | return isSuccessCode 44 | } 45 | 46 | // HTTPRedirect asserts that a specified handler returns a redirect status code. 47 | // 48 | // assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 49 | // 50 | // Returns whether the assertion was successful (true) or not (false). 51 | func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 52 | if h, ok := t.(tHelper); ok { 53 | h.Helper() 54 | } 55 | code, err := httpCode(handler, method, url, values) 56 | if err != nil { 57 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 58 | } 59 | 60 | isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect 61 | if !isRedirectCode { 62 | Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code)) 63 | } 64 | 65 | return isRedirectCode 66 | } 67 | 68 | // HTTPError asserts that a specified handler returns an error status code. 69 | // 70 | // assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 71 | // 72 | // Returns whether the assertion was successful (true) or not (false). 73 | func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 74 | if h, ok := t.(tHelper); ok { 75 | h.Helper() 76 | } 77 | code, err := httpCode(handler, method, url, values) 78 | if err != nil { 79 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 80 | } 81 | 82 | isErrorCode := code >= http.StatusBadRequest 83 | if !isErrorCode { 84 | Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code)) 85 | } 86 | 87 | return isErrorCode 88 | } 89 | 90 | // HTTPStatusCode asserts that a specified handler returns a specified status code. 91 | // 92 | // assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) 93 | // 94 | // Returns whether the assertion was successful (true) or not (false). 95 | func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { 96 | if h, ok := t.(tHelper); ok { 97 | h.Helper() 98 | } 99 | code, err := httpCode(handler, method, url, values) 100 | if err != nil { 101 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 102 | } 103 | 104 | successful := code == statuscode 105 | if !successful { 106 | Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code)) 107 | } 108 | 109 | return successful 110 | } 111 | 112 | // HTTPBody is a helper that returns HTTP body of the response. It returns 113 | // empty string if building a new request fails. 114 | func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { 115 | w := httptest.NewRecorder() 116 | req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) 117 | if err != nil { 118 | return "" 119 | } 120 | handler(w, req) 121 | return w.Body.String() 122 | } 123 | 124 | // HTTPBodyContains asserts that a specified handler returns a 125 | // body that contains a string. 126 | // 127 | // assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 128 | // 129 | // Returns whether the assertion was successful (true) or not (false). 130 | func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 131 | if h, ok := t.(tHelper); ok { 132 | h.Helper() 133 | } 134 | body := HTTPBody(handler, method, url, values) 135 | 136 | contains := strings.Contains(body, fmt.Sprint(str)) 137 | if !contains { 138 | Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) 139 | } 140 | 141 | return contains 142 | } 143 | 144 | // HTTPBodyNotContains asserts that a specified handler returns a 145 | // body that does not contain a string. 146 | // 147 | // assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 148 | // 149 | // Returns whether the assertion was successful (true) or not (false). 150 | func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 151 | if h, ok := t.(tHelper); ok { 152 | h.Helper() 153 | } 154 | body := HTTPBody(handler, method, url, values) 155 | 156 | contains := strings.Contains(body, fmt.Sprint(str)) 157 | if contains { 158 | Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) 159 | } 160 | 161 | return !contains 162 | } 163 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/doc.go: -------------------------------------------------------------------------------- 1 | // Package require implements the same assertions as the `assert` package but 2 | // stops test execution when a test fails. 3 | // 4 | // Example Usage 5 | // 6 | // The following is a complete example using require in a standard test function: 7 | // import ( 8 | // "testing" 9 | // "github.com/stretchr/testify/require" 10 | // ) 11 | // 12 | // func TestSomething(t *testing.T) { 13 | // 14 | // var a string = "Hello" 15 | // var b string = "Hello" 16 | // 17 | // require.Equal(t, a, b, "The two words should be the same.") 18 | // 19 | // } 20 | // 21 | // Assertions 22 | // 23 | // The `require` package have same global functions as in the `assert` package, 24 | // but instead of returning a boolean result they call `t.FailNow()`. 25 | // 26 | // Every assertion function also takes an optional string message as the final argument, 27 | // allowing custom error messages to be appended to the message the assertion method outputs. 28 | package require 29 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/forward_requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs" 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.Comment}} 2 | func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } 5 | t.FailNow() 6 | } 7 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // TestingT is an interface wrapper around *testing.T 4 | type TestingT interface { 5 | Errorf(format string, args ...interface{}) 6 | FailNow() 7 | } 8 | 9 | type tHelper interface { 10 | Helper() 11 | } 12 | 13 | // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful 14 | // for table driven tests. 15 | type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) 16 | 17 | // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful 18 | // for table driven tests. 19 | type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) 20 | 21 | // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful 22 | // for table driven tests. 23 | type BoolAssertionFunc func(TestingT, bool, ...interface{}) 24 | 25 | // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful 26 | // for table driven tests. 27 | type ErrorAssertionFunc func(TestingT, error, ...interface{}) 28 | 29 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" 30 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.4.x" 5 | - "1.5.x" 6 | - "1.6.x" 7 | - "1.7.x" 8 | - "1.8.x" 9 | - "1.9.x" 10 | - "1.10.x" 11 | - "1.11.x" 12 | - "1.12.x" 13 | - "1.13.x" 14 | - "tip" 15 | 16 | go_import_path: gopkg.in/yaml.v3 17 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | This project is covered by two different licenses: MIT and Apache. 3 | 4 | #### MIT License #### 5 | 6 | The following files were ported to Go from C files of libyaml, and thus 7 | are still covered by their original MIT license, with the additional 8 | copyright staring in 2011 when the project was ported over: 9 | 10 | apic.go emitterc.go parserc.go readerc.go scannerc.go 11 | writerc.go yamlh.go yamlprivateh.go 12 | 13 | Copyright (c) 2006-2010 Kirill Simonov 14 | Copyright (c) 2006-2011 Kirill Simonov 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy of 17 | this software and associated documentation files (the "Software"), to deal in 18 | the Software without restriction, including without limitation the rights to 19 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 20 | of the Software, and to permit persons to whom the Software is furnished to do 21 | so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in all 24 | copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | SOFTWARE. 33 | 34 | ### Apache License ### 35 | 36 | All the remaining project files are covered by the Apache license: 37 | 38 | Copyright (c) 2011-2019 Canonical Ltd 39 | 40 | Licensed under the Apache License, Version 2.0 (the "License"); 41 | you may not use this file except in compliance with the License. 42 | You may obtain a copy of the License at 43 | 44 | http://www.apache.org/licenses/LICENSE-2.0 45 | 46 | Unless required by applicable law or agreed to in writing, software 47 | distributed under the License is distributed on an "AS IS" BASIS, 48 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 49 | See the License for the specific language governing permissions and 50 | limitations under the License. 51 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2016 Canonical Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/README.md: -------------------------------------------------------------------------------- 1 | # YAML support for the Go language 2 | 3 | Introduction 4 | ------------ 5 | 6 | The yaml package enables Go programs to comfortably encode and decode YAML 7 | values. It was developed within [Canonical](https://www.canonical.com) as 8 | part of the [juju](https://juju.ubuntu.com) project, and is based on a 9 | pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) 10 | C library to parse and generate YAML data quickly and reliably. 11 | 12 | Compatibility 13 | ------------- 14 | 15 | The yaml package supports most of YAML 1.2, but preserves some behavior 16 | from 1.1 for backwards compatibility. 17 | 18 | Specifically, as of v3 of the yaml package: 19 | 20 | - YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being 21 | decoded into a typed bool value. Otherwise they behave as a string. Booleans 22 | in YAML 1.2 are _true/false_ only. 23 | - Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_ 24 | as specified in YAML 1.2, because most parsers still use the old format. 25 | Octals in the _0o777_ format are supported though, so new files work. 26 | - Does not support base-60 floats. These are gone from YAML 1.2, and were 27 | actually never supported by this package as it's clearly a poor choice. 28 | 29 | and offers backwards 30 | compatibility with YAML 1.1 in some cases. 31 | 1.2, including support for 32 | anchors, tags, map merging, etc. Multi-document unmarshalling is not yet 33 | implemented, and base-60 floats from YAML 1.1 are purposefully not 34 | supported since they're a poor design and are gone in YAML 1.2. 35 | 36 | Installation and usage 37 | ---------------------- 38 | 39 | The import path for the package is *gopkg.in/yaml.v3*. 40 | 41 | To install it, run: 42 | 43 | go get gopkg.in/yaml.v3 44 | 45 | API documentation 46 | ----------------- 47 | 48 | If opened in a browser, the import path itself leads to the API documentation: 49 | 50 | - [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3) 51 | 52 | API stability 53 | ------------- 54 | 55 | The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in). 56 | 57 | 58 | License 59 | ------- 60 | 61 | The yaml package is licensed under the MIT and Apache License 2.0 licenses. 62 | Please see the LICENSE file for details. 63 | 64 | 65 | Example 66 | ------- 67 | 68 | ```Go 69 | package main 70 | 71 | import ( 72 | "fmt" 73 | "log" 74 | 75 | "gopkg.in/yaml.v3" 76 | ) 77 | 78 | var data = ` 79 | a: Easy! 80 | b: 81 | c: 2 82 | d: [3, 4] 83 | ` 84 | 85 | // Note: struct fields must be public in order for unmarshal to 86 | // correctly populate the data. 87 | type T struct { 88 | A string 89 | B struct { 90 | RenamedC int `yaml:"c"` 91 | D []int `yaml:",flow"` 92 | } 93 | } 94 | 95 | func main() { 96 | t := T{} 97 | 98 | err := yaml.Unmarshal([]byte(data), &t) 99 | if err != nil { 100 | log.Fatalf("error: %v", err) 101 | } 102 | fmt.Printf("--- t:\n%v\n\n", t) 103 | 104 | d, err := yaml.Marshal(&t) 105 | if err != nil { 106 | log.Fatalf("error: %v", err) 107 | } 108 | fmt.Printf("--- t dump:\n%s\n\n", string(d)) 109 | 110 | m := make(map[interface{}]interface{}) 111 | 112 | err = yaml.Unmarshal([]byte(data), &m) 113 | if err != nil { 114 | log.Fatalf("error: %v", err) 115 | } 116 | fmt.Printf("--- m:\n%v\n\n", m) 117 | 118 | d, err = yaml.Marshal(&m) 119 | if err != nil { 120 | log.Fatalf("error: %v", err) 121 | } 122 | fmt.Printf("--- m dump:\n%s\n\n", string(d)) 123 | } 124 | ``` 125 | 126 | This example will generate the following output: 127 | 128 | ``` 129 | --- t: 130 | {Easy! {2 [3 4]}} 131 | 132 | --- t dump: 133 | a: Easy! 134 | b: 135 | c: 2 136 | d: [3, 4] 137 | 138 | 139 | --- m: 140 | map[a:Easy! b:map[c:2 d:[3 4]]] 141 | 142 | --- m dump: 143 | a: Easy! 144 | b: 145 | c: 2 146 | d: 147 | - 3 148 | - 4 149 | ``` 150 | 151 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/go.mod: -------------------------------------------------------------------------------- 1 | module "gopkg.in/yaml.v3" 2 | 3 | require ( 4 | "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 5 | ) 6 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/sorter.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2011-2019 Canonical Ltd 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package yaml 17 | 18 | import ( 19 | "reflect" 20 | "unicode" 21 | ) 22 | 23 | type keyList []reflect.Value 24 | 25 | func (l keyList) Len() int { return len(l) } 26 | func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 27 | func (l keyList) Less(i, j int) bool { 28 | a := l[i] 29 | b := l[j] 30 | ak := a.Kind() 31 | bk := b.Kind() 32 | for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 33 | a = a.Elem() 34 | ak = a.Kind() 35 | } 36 | for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 37 | b = b.Elem() 38 | bk = b.Kind() 39 | } 40 | af, aok := keyFloat(a) 41 | bf, bok := keyFloat(b) 42 | if aok && bok { 43 | if af != bf { 44 | return af < bf 45 | } 46 | if ak != bk { 47 | return ak < bk 48 | } 49 | return numLess(a, b) 50 | } 51 | if ak != reflect.String || bk != reflect.String { 52 | return ak < bk 53 | } 54 | ar, br := []rune(a.String()), []rune(b.String()) 55 | digits := false 56 | for i := 0; i < len(ar) && i < len(br); i++ { 57 | if ar[i] == br[i] { 58 | digits = unicode.IsDigit(ar[i]) 59 | continue 60 | } 61 | al := unicode.IsLetter(ar[i]) 62 | bl := unicode.IsLetter(br[i]) 63 | if al && bl { 64 | return ar[i] < br[i] 65 | } 66 | if al || bl { 67 | if digits { 68 | return al 69 | } else { 70 | return bl 71 | } 72 | } 73 | var ai, bi int 74 | var an, bn int64 75 | if ar[i] == '0' || br[i] == '0' { 76 | for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- { 77 | if ar[j] != '0' { 78 | an = 1 79 | bn = 1 80 | break 81 | } 82 | } 83 | } 84 | for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 85 | an = an*10 + int64(ar[ai]-'0') 86 | } 87 | for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 88 | bn = bn*10 + int64(br[bi]-'0') 89 | } 90 | if an != bn { 91 | return an < bn 92 | } 93 | if ai != bi { 94 | return ai < bi 95 | } 96 | return ar[i] < br[i] 97 | } 98 | return len(ar) < len(br) 99 | } 100 | 101 | // keyFloat returns a float value for v if it is a number/bool 102 | // and whether it is a number/bool or not. 103 | func keyFloat(v reflect.Value) (f float64, ok bool) { 104 | switch v.Kind() { 105 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 106 | return float64(v.Int()), true 107 | case reflect.Float32, reflect.Float64: 108 | return v.Float(), true 109 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 110 | return float64(v.Uint()), true 111 | case reflect.Bool: 112 | if v.Bool() { 113 | return 1, true 114 | } 115 | return 0, true 116 | } 117 | return 0, false 118 | } 119 | 120 | // numLess returns whether a < b. 121 | // a and b must necessarily have the same kind. 122 | func numLess(a, b reflect.Value) bool { 123 | switch a.Kind() { 124 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 125 | return a.Int() < b.Int() 126 | case reflect.Float32, reflect.Float64: 127 | return a.Float() < b.Float() 128 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 129 | return a.Uint() < b.Uint() 130 | case reflect.Bool: 131 | return !a.Bool() && b.Bool() 132 | } 133 | panic("not a number") 134 | } 135 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/writerc.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2011-2019 Canonical Ltd 3 | // Copyright (c) 2006-2010 Kirill Simonov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | // this software and associated documentation files (the "Software"), to deal in 7 | // the Software without restriction, including without limitation the rights to 8 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | // of the Software, and to permit persons to whom the Software is furnished to do 10 | // so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package yaml 24 | 25 | // Set the writer error and return false. 26 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 27 | emitter.error = yaml_WRITER_ERROR 28 | emitter.problem = problem 29 | return false 30 | } 31 | 32 | // Flush the output buffer. 33 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 34 | if emitter.write_handler == nil { 35 | panic("write handler not set") 36 | } 37 | 38 | // Check if the buffer is empty. 39 | if emitter.buffer_pos == 0 { 40 | return true 41 | } 42 | 43 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 44 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 45 | } 46 | emitter.buffer_pos = 0 47 | return true 48 | } 49 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/yamlprivateh.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2011-2019 Canonical Ltd 3 | // Copyright (c) 2006-2010 Kirill Simonov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | // this software and associated documentation files (the "Software"), to deal in 7 | // the Software without restriction, including without limitation the rights to 8 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | // of the Software, and to permit persons to whom the Software is furnished to do 10 | // so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package yaml 24 | 25 | const ( 26 | // The size of the input raw buffer. 27 | input_raw_buffer_size = 512 28 | 29 | // The size of the input buffer. 30 | // It should be possible to decode the whole raw buffer. 31 | input_buffer_size = input_raw_buffer_size * 3 32 | 33 | // The size of the output buffer. 34 | output_buffer_size = 128 35 | 36 | // The size of the output raw buffer. 37 | // It should be possible to encode the whole output buffer. 38 | output_raw_buffer_size = (output_buffer_size*2 + 2) 39 | 40 | // The size of other stacks and queues. 41 | initial_stack_size = 16 42 | initial_queue_size = 16 43 | initial_string_size = 16 44 | ) 45 | 46 | // Check if the character at the specified position is an alphabetical 47 | // character, a digit, '_', or '-'. 48 | func is_alpha(b []byte, i int) bool { 49 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' 50 | } 51 | 52 | // Check if the character at the specified position is a digit. 53 | func is_digit(b []byte, i int) bool { 54 | return b[i] >= '0' && b[i] <= '9' 55 | } 56 | 57 | // Get the value of a digit. 58 | func as_digit(b []byte, i int) int { 59 | return int(b[i]) - '0' 60 | } 61 | 62 | // Check if the character at the specified position is a hex-digit. 63 | func is_hex(b []byte, i int) bool { 64 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' 65 | } 66 | 67 | // Get the value of a hex-digit. 68 | func as_hex(b []byte, i int) int { 69 | bi := b[i] 70 | if bi >= 'A' && bi <= 'F' { 71 | return int(bi) - 'A' + 10 72 | } 73 | if bi >= 'a' && bi <= 'f' { 74 | return int(bi) - 'a' + 10 75 | } 76 | return int(bi) - '0' 77 | } 78 | 79 | // Check if the character is ASCII. 80 | func is_ascii(b []byte, i int) bool { 81 | return b[i] <= 0x7F 82 | } 83 | 84 | // Check if the character at the start of the buffer can be printed unescaped. 85 | func is_printable(b []byte, i int) bool { 86 | return ((b[i] == 0x0A) || // . == #x0A 87 | (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E 88 | (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF 89 | (b[i] > 0xC2 && b[i] < 0xED) || 90 | (b[i] == 0xED && b[i+1] < 0xA0) || 91 | (b[i] == 0xEE) || 92 | (b[i] == 0xEF && // #xE000 <= . <= #xFFFD 93 | !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF 94 | !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) 95 | } 96 | 97 | // Check if the character at the specified position is NUL. 98 | func is_z(b []byte, i int) bool { 99 | return b[i] == 0x00 100 | } 101 | 102 | // Check if the beginning of the buffer is a BOM. 103 | func is_bom(b []byte, i int) bool { 104 | return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF 105 | } 106 | 107 | // Check if the character at the specified position is space. 108 | func is_space(b []byte, i int) bool { 109 | return b[i] == ' ' 110 | } 111 | 112 | // Check if the character at the specified position is tab. 113 | func is_tab(b []byte, i int) bool { 114 | return b[i] == '\t' 115 | } 116 | 117 | // Check if the character at the specified position is blank (space or tab). 118 | func is_blank(b []byte, i int) bool { 119 | //return is_space(b, i) || is_tab(b, i) 120 | return b[i] == ' ' || b[i] == '\t' 121 | } 122 | 123 | // Check if the character at the specified position is a line break. 124 | func is_break(b []byte, i int) bool { 125 | return (b[i] == '\r' || // CR (#xD) 126 | b[i] == '\n' || // LF (#xA) 127 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 128 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 129 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) 130 | } 131 | 132 | func is_crlf(b []byte, i int) bool { 133 | return b[i] == '\r' && b[i+1] == '\n' 134 | } 135 | 136 | // Check if the character is a line break or NUL. 137 | func is_breakz(b []byte, i int) bool { 138 | //return is_break(b, i) || is_z(b, i) 139 | return ( 140 | // is_break: 141 | b[i] == '\r' || // CR (#xD) 142 | b[i] == '\n' || // LF (#xA) 143 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 144 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 145 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 146 | // is_z: 147 | b[i] == 0) 148 | } 149 | 150 | // Check if the character is a line break, space, or NUL. 151 | func is_spacez(b []byte, i int) bool { 152 | //return is_space(b, i) || is_breakz(b, i) 153 | return ( 154 | // is_space: 155 | b[i] == ' ' || 156 | // is_breakz: 157 | b[i] == '\r' || // CR (#xD) 158 | b[i] == '\n' || // LF (#xA) 159 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 160 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 161 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 162 | b[i] == 0) 163 | } 164 | 165 | // Check if the character is a line break, space, tab, or NUL. 166 | func is_blankz(b []byte, i int) bool { 167 | //return is_blank(b, i) || is_breakz(b, i) 168 | return ( 169 | // is_blank: 170 | b[i] == ' ' || b[i] == '\t' || 171 | // is_breakz: 172 | b[i] == '\r' || // CR (#xD) 173 | b[i] == '\n' || // LF (#xA) 174 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 175 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 176 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 177 | b[i] == 0) 178 | } 179 | 180 | // Determine the width of the character. 181 | func width(b byte) int { 182 | // Don't replace these by a switch without first 183 | // confirming that it is being inlined. 184 | if b&0x80 == 0x00 { 185 | return 1 186 | } 187 | if b&0xE0 == 0xC0 { 188 | return 2 189 | } 190 | if b&0xF0 == 0xE0 { 191 | return 3 192 | } 193 | if b&0xF8 == 0xF0 { 194 | return 4 195 | } 196 | return 0 197 | 198 | } 199 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195 2 | ## explicit 3 | github.com/araddon/dateparse 4 | # github.com/davecgh/go-spew v1.1.0 5 | github.com/davecgh/go-spew/spew 6 | # github.com/pmezard/go-difflib v1.0.0 7 | github.com/pmezard/go-difflib/difflib 8 | # github.com/stretchr/testify v1.7.0 9 | ## explicit 10 | github.com/stretchr/testify/assert 11 | github.com/stretchr/testify/require 12 | # gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c 13 | gopkg.in/yaml.v3 14 | --------------------------------------------------------------------------------