pax_global_header00006660000000000000000000000064146425220600014513gustar00rootroot0000000000000052 comment=e408c5b16701c966632b03ff65772287693fbc9c golang-github-lestrrat-go-blackmagic-1.0.2/000077500000000000000000000000001464252206000205565ustar00rootroot00000000000000golang-github-lestrrat-go-blackmagic-1.0.2/.github/000077500000000000000000000000001464252206000221165ustar00rootroot00000000000000golang-github-lestrrat-go-blackmagic-1.0.2/.github/workflows/000077500000000000000000000000001464252206000241535ustar00rootroot00000000000000golang-github-lestrrat-go-blackmagic-1.0.2/.github/workflows/ci.yml000066400000000000000000000017521464252206000252760ustar00rootroot00000000000000name: CI on: [push, pull_request] jobs: build: runs-on: ubuntu-latest strategy: matrix: go: [ '1.19', '1.18' ] name: Go ${{ matrix.go }} test steps: - name: Checkout repository uses: actions/checkout@v3 - name: Install Go stable version if: matrix.go != 'tip' uses: actions/setup-go@v3 with: go-version: ${{ matrix.go }} check-latest: true - name: Install Go tip if: matrix.go == 'tip' run: | git clone --depth=1 https://go.googlesource.com/go $HOME/gotip cd $HOME/gotip/src ./make.bash echo "::set-env name=GOROOT::$HOME/gotip" echo "::add-path::$HOME/gotip/bin" echo "::add-path::$(go env GOPATH)/bin" - name: Test run: go test -v -race ./... - name: Upload code coverage to codecov if: matrix.go == '1.19' uses: codecov/codecov-action@v1 with: file: ./coverage.out golang-github-lestrrat-go-blackmagic-1.0.2/.github/workflows/lint.yml000066400000000000000000000005151464252206000256450ustar00rootroot00000000000000name: lint on: [push, pull_request] jobs: golangci: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: go-version: 1.19 check-latest: true - uses: golangci/golangci-lint-action@v3 with: version: v1.49.0 golang-github-lestrrat-go-blackmagic-1.0.2/.gitignore000066400000000000000000000004151464252206000225460ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ golang-github-lestrrat-go-blackmagic-1.0.2/LICENSE000066400000000000000000000020541464252206000215640ustar00rootroot00000000000000MIT License Copyright (c) 2021 lestrrat-go Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-github-lestrrat-go-blackmagic-1.0.2/README.md000066400000000000000000000001041464252206000220300ustar00rootroot00000000000000# blackmagic Reflect-based black magic. YMMV, and use with caution golang-github-lestrrat-go-blackmagic-1.0.2/blackmagic.go000066400000000000000000000050421464252206000231630ustar00rootroot00000000000000package blackmagic import ( "fmt" "reflect" ) // AssignField is a convenience function to assign a value to // an optional struct field. In Go, an optional struct field is // usually denoted by a pointer to T instead of T: // // type Object struct { // Optional *T // } // // This gets a bit cumbersome when you want to assign literals // or you do not want to worry about taking the address of a // variable. // // Object.Optional = &"foo" // doesn't compile! // // Instead you can use this function to do it in one line: // // blackmagic.AssignOptionalField(&Object.Optionl, "foo") func AssignOptionalField(dst, src interface{}) error { dstRV := reflect.ValueOf(dst) srcRV := reflect.ValueOf(src) if dstRV.Kind() != reflect.Pointer || dstRV.Elem().Kind() != reflect.Pointer { return fmt.Errorf(`dst must be a pointer to a field that is turn a pointer of src (%T)`, src) } if !dstRV.Elem().CanSet() { return fmt.Errorf(`dst (%T) is not assignable`, dstRV.Elem().Interface()) } if !reflect.PtrTo(srcRV.Type()).AssignableTo(dstRV.Elem().Type()) { return fmt.Errorf(`cannot assign src (%T) to dst (%T)`, src, dst) } ptr := reflect.New(srcRV.Type()) ptr.Elem().Set(srcRV) dstRV.Elem().Set(ptr) return nil } // AssignIfCompatible is a convenience function to safely // assign arbitrary values. dst must be a pointer to an // empty interface, or it must be a pointer to a compatible // variable type that can hold src. func AssignIfCompatible(dst, src interface{}) error { orv := reflect.ValueOf(src) // save this value for error reporting result := orv // t can be a pointer or a slice, and the code will slightly change // depending on this var isPtr bool var isSlice bool switch result.Kind() { case reflect.Ptr: isPtr = true case reflect.Slice: isSlice = true } rv := reflect.ValueOf(dst) if rv.Kind() != reflect.Ptr { return fmt.Errorf(`destination argument to AssignIfCompatible() must be a pointer: %T`, dst) } actualDst := rv.Elem() switch actualDst.Kind() { case reflect.Interface: // If it's an interface, we can just assign the pointer to the interface{} default: // If it's a pointer to the struct we're looking for, we need to set // the de-referenced struct if !isSlice && isPtr { result = result.Elem() } } if !result.Type().AssignableTo(actualDst.Type()) { return fmt.Errorf(`argument to AssignIfCompatible() must be compatible with %T (was %T)`, orv.Interface(), dst) } if !actualDst.CanSet() { return fmt.Errorf(`argument to AssignIfCompatible() must be settable`) } actualDst.Set(result) return nil } golang-github-lestrrat-go-blackmagic-1.0.2/blackmagic_test.go000066400000000000000000000030661464252206000242260ustar00rootroot00000000000000package blackmagic_test import ( "testing" "github.com/lestrrat-go/blackmagic" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestAssignment(t *testing.T) { testcases := []struct { Name string Error bool Value interface{} Destination func() interface{} }{ { Name: `empty struct`, Error: false, Value: struct{}{}, Destination: func() interface{} { var v interface{} return &v }, }, { Name: `non pointer destination`, Error: true, Value: &struct{}{}, }, { Name: `assign empty struct to int`, Error: true, Value: &struct{}{}, Destination: func() interface{} { var v int return &v }, }, } for _, tc := range testcases { tc := tc t.Run(tc.Name, func(t *testing.T) { var dst interface{} if dstFunc := tc.Destination; dstFunc != nil { dst = dstFunc() } err := blackmagic.AssignIfCompatible(dst, tc.Value) if tc.Error { if !assert.Error(t, err, `blackmagic.AssignIfCompatible should fail`) { return } } else { if !assert.NoError(t, err, `blackmagic.AssignIfCompatible should succeed`) { return } } }) } } func TestAssignOptionalField(t *testing.T) { var f struct { Foo *string Bar *int } require.NoError(t, blackmagic.AssignOptionalField(&f.Foo, "Hello"), `blackmagic.AssignOptionalField should succeed`) require.Equal(t, *(f.Foo), "Hello") require.NoError(t, blackmagic.AssignOptionalField(&f.Bar, 1), `blackmagic.AssignOptionalField should succeed`) require.Equal(t, *(f.Bar), 1) } golang-github-lestrrat-go-blackmagic-1.0.2/go.mod000066400000000000000000000001361464252206000216640ustar00rootroot00000000000000module github.com/lestrrat-go/blackmagic go 1.16 require github.com/stretchr/testify v1.7.1 golang-github-lestrrat-go-blackmagic-1.0.2/go.sum000066400000000000000000000020001464252206000217010ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=