github.com/sacloud/iaas-api-go@v1.12.0/internal/dsl/meta/type.go (about) 1 // Copyright 2022-2023 The sacloud/iaas-api-go Authors 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 15 package meta 16 17 import ( 18 "fmt" 19 "log" 20 "reflect" 21 "strings" 22 ) 23 24 // Type 型情報 25 type Type interface { 26 // GoType 型名 27 GoType() string 28 // GoPkg パッケージ名 29 GoPkg() string 30 // GoImportPath インポートパス 31 GoImportPath() string 32 // GoTypeSourceCode ソースコードでの型表現 33 GoTypeSourceCode() string 34 // ZeroInitializeSourceCode 型に応じたzero値での初期化コード 35 ZeroInitializeSourceCode() string 36 // ZeroValueSourceCode 型に応じたzero値コード 37 ZeroValueSourceCode() string 38 // ToPtrType ポインタ型への変換 39 ToPtrType() Type 40 } 41 42 // StaticType あらかじめ静的参照できる型 43 type StaticType struct { 44 goType string 45 goPkg string 46 goImportPath string 47 reflectKind reflect.Kind 48 } 49 50 // GoType 型名 51 func (t *StaticType) GoType() string { return t.goType } 52 53 // GoPkg パッケージ名 54 func (t *StaticType) GoPkg() string { return t.goPkg } 55 56 // GoImportPath インポートパス 57 func (t *StaticType) GoImportPath() string { return t.goImportPath } 58 59 // GoTypeSourceCode ソースコードでの型表現 60 func (t *StaticType) GoTypeSourceCode() string { 61 if t.goPkg != "" && t.reflectKind == reflect.Struct && t.goType != "time.Time" { 62 return fmt.Sprintf("*%s", t.goType) 63 } 64 return t.goType 65 } 66 67 // ZeroInitializeSourceCode 型に応じたzero値での初期化コード 68 func (t *StaticType) ZeroInitializeSourceCode() string { 69 format := "%s" 70 if t.goPkg != "" { 71 switch t.reflectKind { 72 case reflect.Bool, reflect.Int, reflect.Int64, 73 reflect.Float32, reflect.Float64, reflect.String: 74 format = t.goType + "(%s)" 75 } 76 } 77 switch t.reflectKind { 78 case reflect.Bool: 79 return fmt.Sprintf(format, "false") 80 case reflect.Int: 81 return fmt.Sprintf(format, "0") 82 case reflect.Int64: 83 return fmt.Sprintf(format, "int64(0)") 84 case reflect.Float32: 85 return fmt.Sprintf(format, "float32(0)") 86 case reflect.Float64: 87 return fmt.Sprintf(format, "float64(0)") 88 case reflect.Interface, reflect.Map, reflect.Slice: 89 return fmt.Sprintf(format, t.goType+"{}") 90 case reflect.Struct: 91 if t.goType == "time.Time" { 92 return fmt.Sprintf(format, t.goType+"{}") 93 } 94 return fmt.Sprintf(format, "&"+t.goType+"{}") 95 case reflect.String: 96 return fmt.Sprintf(format, `""`) 97 case reflect.Ptr: 98 return fmt.Sprintf(format, `nil`) 99 default: 100 log.Panicf("unsupported Kind: %s", t.reflectKind) 101 return "" 102 } 103 } 104 105 // ZeroValueSourceCode 型に応じたzero値コード 106 func (t *StaticType) ZeroValueSourceCode() string { 107 format := "%s" 108 if t.goPkg != "" { 109 switch t.reflectKind { 110 case reflect.Bool, reflect.Int, reflect.Int64, 111 reflect.Float32, reflect.Float64, reflect.String: 112 format = t.goType + "(%s)" 113 } 114 } 115 switch t.reflectKind { 116 case reflect.Bool: 117 return fmt.Sprintf(format, "false") 118 case reflect.Int: 119 return fmt.Sprintf(format, "0") 120 case reflect.Int64: 121 return fmt.Sprintf(format, "int64(0)") 122 case reflect.Float32: 123 return fmt.Sprintf(format, "float32(0)") 124 case reflect.Float64: 125 return fmt.Sprintf(format, "float64(0)") 126 case reflect.Interface, reflect.Map, reflect.Slice, reflect.Struct, reflect.Ptr: 127 if t.goType == "time.Time" { 128 return fmt.Sprintf(format, t.goType+"{}") 129 } 130 return fmt.Sprintf(format, "nil") 131 case reflect.String: 132 return fmt.Sprintf(format, `""`) 133 default: 134 log.Panicf("unsupported Kind: %s", t.reflectKind) 135 return "" 136 } 137 } 138 139 func (t *StaticType) ToPtrType() Type { 140 return &StaticType{ 141 goType: "*" + t.goType, 142 goPkg: t.goPkg, 143 goImportPath: t.goImportPath, 144 reflectKind: reflect.Ptr, 145 } 146 } 147 148 // Static 型情報を受け取りTypeを返す 149 func Static(v interface{}) *StaticType { 150 t := reflect.TypeOf(v) 151 pkgName := "" 152 pkgPath := t.PkgPath() 153 if len(pkgPath) > 0 { 154 pathes := strings.Split(t.PkgPath(), "/") 155 pkgName = pathes[len(pathes)-1] 156 } 157 switch t.Kind() { 158 case reflect.Bool, reflect.Int, reflect.Int64, 159 reflect.Float32, reflect.Float64, reflect.Interface, 160 reflect.Map, reflect.Slice, reflect.Struct, reflect.String: 161 // noop 162 case reflect.Ptr: 163 // TODO どう実装する? 164 // return Static(reflect.ValueOf(v).Elem().Interface()) 165 default: 166 log.Panicf("unsupported Kind: %s", t.Kind()) 167 return nil 168 } 169 return &StaticType{ 170 goType: t.String(), 171 goPkg: pkgName, 172 goImportPath: t.PkgPath(), 173 reflectKind: t.Kind(), 174 } 175 } 176 177 // 178 // func ToPtr(t Type) *StaticType { 179 // st, ok := t.(*StaticType) 180 // if !ok { 181 // log.Fatal("unsupported Type", t) 182 // } 183 // return &StaticType{ 184 // goType: "*" + st.goType, 185 // goPkg: st.goPkg, 186 // goImportPath: st.goImportPath, 187 // reflectKind: reflect.Ptr, 188 // } 189 //}