github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/internal/runtime/struct_field.go (about)

     1  package runtime
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"unicode"
     7  )
     8  
     9  func getTag(field reflect.StructField) string {
    10  	return field.Tag.Get("php")
    11  }
    12  
    13  func IsIgnoredStructField(field reflect.StructField) bool {
    14  	if field.PkgPath != "" {
    15  		if field.Anonymous {
    16  			t := field.Type
    17  			if t.Kind() == reflect.Ptr {
    18  				t = t.Elem()
    19  			}
    20  			if t.Kind() != reflect.Struct {
    21  				return true
    22  			}
    23  		} else {
    24  			// private field
    25  			return true
    26  		}
    27  	}
    28  	tag := getTag(field)
    29  	return tag == "-"
    30  }
    31  
    32  type StructTag struct {
    33  	Key         string
    34  	IsTaggedKey bool
    35  	IsOmitEmpty bool
    36  	IsString    bool
    37  	Field       reflect.StructField
    38  }
    39  
    40  func (s StructTag) Name() string {
    41  	if s.Key != "" {
    42  		return s.Key
    43  	}
    44  	return s.Field.Name
    45  }
    46  
    47  type StructTags []*StructTag
    48  
    49  func (t StructTags) ExistsKey(key string) bool {
    50  	for _, tt := range t {
    51  		if tt.Key == key {
    52  			return true
    53  		}
    54  	}
    55  	return false
    56  }
    57  
    58  func isValidTag(s string) bool {
    59  	if s == "" {
    60  		return false
    61  	}
    62  	for _, c := range s {
    63  		switch {
    64  		case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
    65  			// Backslash and quote chars are reserved, but
    66  			// otherwise any punctuation chars are allowed
    67  			// in a tag name.
    68  		case !unicode.IsLetter(c) && !unicode.IsDigit(c):
    69  			return false
    70  		}
    71  	}
    72  	return true
    73  }
    74  
    75  func StructTagFromField(field reflect.StructField) *StructTag {
    76  	keyName := field.Name
    77  	tag := getTag(field)
    78  	st := &StructTag{Field: field}
    79  	opts := strings.Split(tag, ",")
    80  	if len(opts) > 0 {
    81  		if opts[0] != "" && isValidTag(opts[0]) {
    82  			keyName = opts[0]
    83  			st.IsTaggedKey = true
    84  		}
    85  	}
    86  	st.Key = keyName
    87  	if len(opts) > 1 {
    88  		for _, opt := range opts[1:] {
    89  			switch opt {
    90  			case "omitempty":
    91  				st.IsOmitEmpty = true
    92  			case "string":
    93  				st.IsString = true
    94  			}
    95  		}
    96  	}
    97  	return st
    98  }