github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/rlp/typecache.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:45</date>
    10  //</624342663629377536>
    11  
    12  
    13  package rlp
    14  
    15  import (
    16  	"fmt"
    17  	"reflect"
    18  	"strings"
    19  	"sync"
    20  )
    21  
    22  var (
    23  	typeCacheMutex sync.RWMutex
    24  	typeCache      = make(map[typekey]*typeinfo)
    25  )
    26  
    27  type typeinfo struct {
    28  	decoder
    29  	writer
    30  }
    31  
    32  //表示结构标记
    33  type tags struct {
    34  //rlp:“nil”控制空输入是否导致nil指针。
    35  	nilOK bool
    36  //rlp:“tail”控制此字段是否吞咽附加列表
    37  //元素。只能为最后一个字段设置,必须
    38  //薄片型。
    39  	tail bool
    40  //RLP:“-”忽略字段。
    41  	ignored bool
    42  }
    43  
    44  type typekey struct {
    45  	reflect.Type
    46  //键必须包含结构标记,因为它们
    47  //可能会生成不同的解码器。
    48  	tags
    49  }
    50  
    51  type decoder func(*Stream, reflect.Value) error
    52  
    53  type writer func(reflect.Value, *encbuf) error
    54  
    55  func cachedTypeInfo(typ reflect.Type, tags tags) (*typeinfo, error) {
    56  	typeCacheMutex.RLock()
    57  	info := typeCache[typekey{typ, tags}]
    58  	typeCacheMutex.RUnlock()
    59  	if info != nil {
    60  		return info, nil
    61  	}
    62  //不在缓存中,需要为此类型生成信息。
    63  	typeCacheMutex.Lock()
    64  	defer typeCacheMutex.Unlock()
    65  	return cachedTypeInfo1(typ, tags)
    66  }
    67  
    68  func cachedTypeInfo1(typ reflect.Type, tags tags) (*typeinfo, error) {
    69  	key := typekey{typ, tags}
    70  	info := typeCache[key]
    71  	if info != nil {
    72  //另一个goroutine先得到了写锁
    73  		return info, nil
    74  	}
    75  //在生成之前将一个dummy值放入缓存。
    76  //如果生成器试图查找自身,它将
    77  //虚拟值,不会递归调用自己。
    78  	typeCache[key] = new(typeinfo)
    79  	info, err := genTypeInfo(typ, tags)
    80  	if err != nil {
    81  //如果发电机发生故障,移除虚拟值
    82  		delete(typeCache, key)
    83  		return nil, err
    84  	}
    85  	*typeCache[key] = *info
    86  	return typeCache[key], err
    87  }
    88  
    89  type field struct {
    90  	index int
    91  	info  *typeinfo
    92  }
    93  
    94  func structFields(typ reflect.Type) (fields []field, err error) {
    95  	for i := 0; i < typ.NumField(); i++ {
    96  if f := typ.Field(i); f.PkgPath == "" { //出口
    97  			tags, err := parseStructTag(typ, i)
    98  			if err != nil {
    99  				return nil, err
   100  			}
   101  			if tags.ignored {
   102  				continue
   103  			}
   104  			info, err := cachedTypeInfo1(f.Type, tags)
   105  			if err != nil {
   106  				return nil, err
   107  			}
   108  			fields = append(fields, field{i, info})
   109  		}
   110  	}
   111  	return fields, nil
   112  }
   113  
   114  func parseStructTag(typ reflect.Type, fi int) (tags, error) {
   115  	f := typ.Field(fi)
   116  	var ts tags
   117  	for _, t := range strings.Split(f.Tag.Get("rlp"), ",") {
   118  		switch t = strings.TrimSpace(t); t {
   119  		case "":
   120  		case "-":
   121  			ts.ignored = true
   122  		case "nil":
   123  			ts.nilOK = true
   124  		case "tail":
   125  			ts.tail = true
   126  			if fi != typ.NumField()-1 {
   127  				return ts, fmt.Errorf(`rlp: invalid struct tag "tail" for %v.%s (must be on last field)`, typ, f.Name)
   128  			}
   129  			if f.Type.Kind() != reflect.Slice {
   130  				return ts, fmt.Errorf(`rlp: invalid struct tag "tail" for %v.%s (field type is not slice)`, typ, f.Name)
   131  			}
   132  		default:
   133  			return ts, fmt.Errorf("rlp: unknown struct tag %q on %v.%s", t, typ, f.Name)
   134  		}
   135  	}
   136  	return ts, nil
   137  }
   138  
   139  func genTypeInfo(typ reflect.Type, tags tags) (info *typeinfo, err error) {
   140  	info = new(typeinfo)
   141  	if info.decoder, err = makeDecoder(typ, tags); err != nil {
   142  		return nil, err
   143  	}
   144  	if info.writer, err = makeWriter(typ, tags); err != nil {
   145  		return nil, err
   146  	}
   147  	return info, nil
   148  }
   149  
   150  func isUint(k reflect.Kind) bool {
   151  	return k >= reflect.Uint && k <= reflect.Uintptr
   152  }
   153