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  //}