github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/ztype/struct.go (about)

     1  package ztype
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  
     7  	"github.com/sohaha/zlsgo/zreflect"
     8  )
     9  
    10  type (
    11  	StruBuilder struct {
    12  		key       reflect.Type
    13  		fields    map[string]*StruField
    14  		fieldKeys []string
    15  		typ       int
    16  	}
    17  	StruField struct {
    18  		typ interface{}
    19  		tag string
    20  	}
    21  )
    22  
    23  const (
    24  	typeStruct = iota
    25  	typeMapStruct
    26  	typeSliceStruct
    27  )
    28  
    29  func NewStruct() *StruBuilder {
    30  	return &StruBuilder{
    31  		typ:    typeStruct,
    32  		fields: map[string]*StruField{},
    33  	}
    34  }
    35  
    36  func NewMapStruct(key interface{}) *StruBuilder {
    37  	var k reflect.Type
    38  	if v, ok := key.(reflect.Type); ok {
    39  		k = v
    40  	} else {
    41  		k = reflect.TypeOf(key)
    42  	}
    43  	return &StruBuilder{
    44  		typ:    typeMapStruct,
    45  		key:    k,
    46  		fields: map[string]*StruField{},
    47  	}
    48  }
    49  
    50  func NewSliceStruct() *StruBuilder {
    51  	return &StruBuilder{
    52  		typ:    typeSliceStruct,
    53  		fields: map[string]*StruField{},
    54  	}
    55  }
    56  
    57  func (b *StruBuilder) Copy(v *StruBuilder) *StruBuilder {
    58  	typ := b.typ
    59  	val := *v
    60  	*b = val
    61  	b.typ = typ
    62  	return b
    63  }
    64  
    65  func (b *StruBuilder) Merge(values ...interface{}) *StruBuilder {
    66  	for _, value := range values {
    67  		valueOf := reflect.Indirect(zreflect.ValueOf(value))
    68  		typeOf := valueOf.Type()
    69  		for i := 0; i < valueOf.NumField(); i++ {
    70  			fval := valueOf.Field(i)
    71  			ftyp := typeOf.Field(i)
    72  			b.AddField(ftyp.Name, fval.Interface(), string(ftyp.Tag))
    73  		}
    74  	}
    75  
    76  	return b
    77  }
    78  
    79  // func (b *StruBuilder) AddFunc(name string, fieldType interface{}, tag ...string) *StruBuilder {
    80  // 	reflect.MakeFunc()
    81  // 	return b
    82  // }
    83  
    84  func (b *StruBuilder) AddField(name string, fieldType interface{}, tag ...string) *StruBuilder {
    85  	var t string
    86  	if len(tag) > 0 {
    87  		t = strings.Join(tag, " ")
    88  	}
    89  	if b.typ == typeStruct {
    90  		nkey := make([]string, 0, len(b.fieldKeys))
    91  		for i := range b.fieldKeys {
    92  			if b.fieldKeys[i] != name {
    93  				nkey = append(nkey, b.fieldKeys[i])
    94  			}
    95  		}
    96  		b.fieldKeys = append(nkey, name)
    97  	}
    98  	b.fields[name] = &StruField{
    99  		typ: fieldType,
   100  		tag: t,
   101  	}
   102  	return b
   103  }
   104  
   105  func (b *StruBuilder) RemoveField(name string) *StruBuilder {
   106  	delete(b.fields, name)
   107  	if b.typ == typeStruct {
   108  		nkey := make([]string, 0, len(b.fieldKeys))
   109  		for i := range b.fieldKeys {
   110  			if b.fieldKeys[i] != name {
   111  				nkey = append(nkey, b.fieldKeys[i])
   112  			}
   113  		}
   114  		b.fieldKeys = nkey
   115  	}
   116  	return b
   117  }
   118  
   119  func (b *StruBuilder) HasField(name string) bool {
   120  	_, ok := b.fields[name]
   121  	return ok
   122  }
   123  
   124  func (b *StruBuilder) GetField(name string) *StruField {
   125  	if !b.HasField(name) {
   126  		return nil
   127  	}
   128  	return b.fields[name]
   129  }
   130  
   131  func (b *StruBuilder) Interface() interface{} {
   132  	return b.Value().Interface()
   133  }
   134  
   135  func (b *StruBuilder) Type() reflect.Type {
   136  	var fields []reflect.StructField
   137  	fn := func(name string, field *StruField) {
   138  		var t reflect.Type
   139  		switch v := field.typ.(type) {
   140  		case *StruBuilder:
   141  			t = v.Type()
   142  		case reflect.Type:
   143  			t = v
   144  		default:
   145  			t = reflect.TypeOf(field.typ)
   146  		}
   147  
   148  		fields = append(fields, reflect.StructField{
   149  			Name: name,
   150  			Type: t,
   151  			Tag:  reflect.StructTag(field.tag),
   152  		})
   153  	}
   154  	if b.typ == typeStruct {
   155  		for i := range b.fieldKeys {
   156  			name := b.fieldKeys[i]
   157  			if field, ok := b.fields[name]; ok {
   158  				fn(name, field)
   159  			}
   160  		}
   161  	} else {
   162  		for name := range b.fields {
   163  			field := b.fields[name]
   164  			fn(name, field)
   165  		}
   166  	}
   167  
   168  	typ := reflect.StructOf(fields)
   169  
   170  	switch b.typ {
   171  	case typeSliceStruct:
   172  		return reflect.SliceOf(typ)
   173  	case typeMapStruct:
   174  		return reflect.MapOf(b.key, typ)
   175  	default:
   176  		return typ
   177  	}
   178  }
   179  
   180  func (b *StruBuilder) Value() reflect.Value {
   181  	return reflect.New(b.Type())
   182  }
   183  
   184  func (f *StruField) SetType(typ interface{}) *StruField {
   185  	f.typ = typ
   186  	return f
   187  }
   188  
   189  func (f *StruField) SetTag(tag string) *StruField {
   190  	f.tag = tag
   191  	return f
   192  }