Skip to content

Commit a6d26bd

Browse files
committed
feat: add alias resolution function
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
1 parent 633e5d0 commit a6d26bd

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

alias.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright © 2014 Steve Francia <spf@spf13.com>.
2+
//
3+
// Use of this source code is governed by an MIT-style
4+
// license that can be found in the LICENSE file.
5+
package cast
6+
7+
import (
8+
"reflect"
9+
"slices"
10+
)
11+
12+
var kindNames = []string{
13+
reflect.String: "string",
14+
reflect.Bool: "bool",
15+
reflect.Int: "int",
16+
reflect.Int8: "int8",
17+
reflect.Int16: "int16",
18+
reflect.Int32: "int32",
19+
reflect.Int64: "int64",
20+
reflect.Uint: "uint",
21+
reflect.Uint8: "uint8",
22+
reflect.Uint16: "uint16",
23+
reflect.Uint32: "uint32",
24+
reflect.Uint64: "uint64",
25+
reflect.Float32: "float32",
26+
reflect.Float64: "float64",
27+
}
28+
29+
var kinds = map[reflect.Kind]func(reflect.Value) any{
30+
reflect.String: func(v reflect.Value) any { return v.String() },
31+
reflect.Bool: func(v reflect.Value) any { return v.Bool() },
32+
reflect.Int: func(v reflect.Value) any { return int(v.Int()) },
33+
reflect.Int8: func(v reflect.Value) any { return int8(v.Int()) },
34+
reflect.Int16: func(v reflect.Value) any { return int16(v.Int()) },
35+
reflect.Int32: func(v reflect.Value) any { return int32(v.Int()) },
36+
reflect.Int64: func(v reflect.Value) any { return v.Int() },
37+
reflect.Uint: func(v reflect.Value) any { return uint(v.Uint()) },
38+
reflect.Uint8: func(v reflect.Value) any { return uint8(v.Uint()) },
39+
reflect.Uint16: func(v reflect.Value) any { return uint16(v.Uint()) },
40+
reflect.Uint32: func(v reflect.Value) any { return uint32(v.Uint()) },
41+
reflect.Uint64: func(v reflect.Value) any { return v.Uint() },
42+
reflect.Float32: func(v reflect.Value) any { return float32(v.Float()) },
43+
reflect.Float64: func(v reflect.Value) any { return v.Float() },
44+
}
45+
46+
// resolveAlias attempts to resolve a named type to its underlying basic type (if possible).
47+
//
48+
// Pointers are expected to be indirected by this point.
49+
func resolveAlias(i any) (any, bool) {
50+
if i == nil {
51+
return nil, false
52+
}
53+
54+
t := reflect.TypeOf(i)
55+
56+
// Not a named type
57+
if t.Name() == "" || slices.Contains(kindNames, t.Name()) {
58+
return i, false
59+
}
60+
61+
resolve, ok := kinds[t.Kind()]
62+
if !ok { // Not a supported kind
63+
return i, false
64+
}
65+
66+
v := reflect.ValueOf(i)
67+
68+
return resolve(v), true
69+
}

alias_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright © 2014 Steve Francia <spf@spf13.com>.
2+
//
3+
// Use of this source code is governed by an MIT-style
4+
// license that can be found in the LICENSE file.
5+
package cast
6+
7+
import (
8+
"testing"
9+
10+
qt "github.com/frankban/quicktest"
11+
)
12+
13+
func TestAlias(t *testing.T) {
14+
type MyStruct struct{}
15+
16+
type MyString string
17+
type MyOtherString MyString
18+
type MyAliasString = MyOtherString
19+
20+
type MyBool bool
21+
type MyOtherBool MyBool
22+
type MyAliasBool = MyOtherBool
23+
24+
type MyInt int
25+
type MyInt8 int8
26+
type MyInt16 int16
27+
type MyInt32 int32
28+
type MyInt64 int64
29+
type MyUint uint
30+
type MyUint8 uint8
31+
type MyUint16 uint16
32+
type MyUint32 uint32
33+
type MyUint64 uint64
34+
type MyFloat32 float32
35+
type MyFloat64 float64
36+
37+
testCases := []struct {
38+
input any
39+
expectedValue any
40+
expectedOk bool
41+
}{
42+
{"string", "string", false}, // Already resolved
43+
{MyStruct{}, MyStruct{}, false}, // Non-resolvable
44+
45+
{MyString("string"), "string", true},
46+
{MyOtherString("string"), "string", true},
47+
{MyAliasString("string"), "string", true},
48+
49+
{MyBool(true), true, true},
50+
{MyOtherBool(true), true, true},
51+
{MyAliasBool(true), true, true},
52+
53+
{MyInt(1234), int(1234), true},
54+
{MyInt8(123), int8(123), true},
55+
{MyInt16(1234), int16(1234), true},
56+
{MyInt32(1234), int32(1234), true},
57+
{MyInt64(1234), int64(1234), true},
58+
59+
{MyUint(1234), uint(1234), true},
60+
{MyUint8(123), uint8(123), true},
61+
{MyUint16(1234), uint16(1234), true},
62+
{MyUint32(1234), uint32(1234), true},
63+
{MyUint64(1234), uint64(1234), true},
64+
65+
{MyFloat32(1.0), float32(1.0), true},
66+
{MyFloat64(1.0), float64(1.0), true},
67+
}
68+
69+
for _, testCase := range testCases {
70+
// TODO: remove after minimum Go version is >=1.22
71+
testCase := testCase
72+
73+
t.Run("", func(t *testing.T) {
74+
c := qt.New(t)
75+
76+
actualValue, ok := resolveAlias(testCase.input)
77+
78+
c.Assert(actualValue, qt.Equals, testCase.expectedValue)
79+
c.Assert(ok, qt.Equals, testCase.expectedOk)
80+
})
81+
}
82+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy