github.com/urso/go-structform@v0.0.2/gotype/unfold.go (about)

     1  package gotype
     2  
     3  import (
     4  	"reflect"
     5  	"sync"
     6  	"unsafe"
     7  
     8  	structform "github.com/urso/go-structform"
     9  )
    10  
    11  type Unfolder struct {
    12  	unfoldCtx
    13  }
    14  
    15  type unfoldCtx struct {
    16  	opts options
    17  
    18  	buf buffer
    19  
    20  	unfolder unfolderStack
    21  	value    reflectValueStack
    22  	baseType structformTypeStack
    23  	ptr      ptrStack
    24  	key      keyStack
    25  	idx      idxStack
    26  
    27  	keyCache symbolCache
    28  }
    29  
    30  type ptrUnfolder interface {
    31  	initState(*unfoldCtx, unsafe.Pointer)
    32  }
    33  
    34  type reflUnfolder interface {
    35  	initState(*unfoldCtx, reflect.Value)
    36  }
    37  
    38  type unfolder interface {
    39  	// primitives
    40  	OnNil(*unfoldCtx) error
    41  	OnBool(*unfoldCtx, bool) error
    42  	OnString(*unfoldCtx, string) error
    43  	OnStringRef(*unfoldCtx, []byte) error
    44  	OnInt8(*unfoldCtx, int8) error
    45  	OnInt16(*unfoldCtx, int16) error
    46  	OnInt32(*unfoldCtx, int32) error
    47  	OnInt64(*unfoldCtx, int64) error
    48  	OnInt(*unfoldCtx, int) error
    49  	OnByte(*unfoldCtx, byte) error
    50  	OnUint8(*unfoldCtx, uint8) error
    51  	OnUint16(*unfoldCtx, uint16) error
    52  	OnUint32(*unfoldCtx, uint32) error
    53  	OnUint64(*unfoldCtx, uint64) error
    54  	OnUint(*unfoldCtx, uint) error
    55  	OnFloat32(*unfoldCtx, float32) error
    56  	OnFloat64(*unfoldCtx, float64) error
    57  
    58  	// array types
    59  	OnArrayStart(*unfoldCtx, int, structform.BaseType) error
    60  	OnArrayFinished(*unfoldCtx) error
    61  	OnChildArrayDone(*unfoldCtx) error
    62  
    63  	// object types
    64  	OnObjectStart(*unfoldCtx, int, structform.BaseType) error
    65  	OnObjectFinished(*unfoldCtx) error
    66  	OnKey(*unfoldCtx, string) error
    67  	OnKeyRef(*unfoldCtx, []byte) error
    68  	OnChildObjectDone(*unfoldCtx) error
    69  }
    70  
    71  type typeUnfoldRegistry struct {
    72  	mu sync.RWMutex
    73  	m  map[reflect.Type]reflUnfolder
    74  }
    75  
    76  var unfoldRegistry = newTypeUnfoldRegistry()
    77  
    78  func NewUnfolder(to interface{}) (*Unfolder, error) {
    79  	u := &Unfolder{}
    80  	u.opts = options{tag: "struct"}
    81  
    82  	u.unfolder.init(&unfolderNoTarget{})
    83  	u.value.init(reflect.Value{})
    84  	u.ptr.init()
    85  	u.key.init()
    86  	u.idx.init()
    87  	u.baseType.init()
    88  
    89  	// TODO: make allocation buffer size configurable
    90  	u.buf.init(1024)
    91  
    92  	if to != nil {
    93  		err := u.SetTarget(to)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  	}
    98  
    99  	return u, nil
   100  }
   101  
   102  func (u *Unfolder) EnableKeyCache(max int) {
   103  	u.keyCache.init(max)
   104  }
   105  
   106  func (u *Unfolder) SetTarget(to interface{}) error {
   107  	ctx := &u.unfoldCtx
   108  
   109  	if ptr, u := lookupGoTypeUnfolder(to); u != nil {
   110  		u.initState(ctx, ptr)
   111  		return nil
   112  	}
   113  
   114  	t := reflect.TypeOf(to)
   115  	if t.Kind() != reflect.Ptr {
   116  		return errRequiresPointer
   117  	}
   118  
   119  	ru, err := lookupReflUnfolder(&u.unfoldCtx, t)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	if ru != nil {
   124  		ru.initState(ctx, reflect.ValueOf(to))
   125  		return nil
   126  	}
   127  
   128  	return errUnsupported
   129  }
   130  
   131  func (u *unfoldCtx) OnObjectStart(len int, baseType structform.BaseType) error {
   132  	return u.unfolder.current.OnObjectStart(u, len, baseType)
   133  }
   134  
   135  func (u *unfoldCtx) OnObjectFinished() error {
   136  	lBefore := len(u.unfolder.stack) + 1
   137  
   138  	if err := u.unfolder.current.OnObjectFinished(u); err != nil {
   139  		return err
   140  	}
   141  
   142  	lAfter := len(u.unfolder.stack) + 1
   143  	if old := u.unfolder.current; lAfter > 1 && lBefore != lAfter {
   144  		return old.OnChildObjectDone(u)
   145  	}
   146  
   147  	return nil
   148  }
   149  
   150  func (u *unfoldCtx) OnKey(s string) error {
   151  	return u.unfolder.current.OnKey(u, s)
   152  }
   153  
   154  func (u *unfoldCtx) OnKeyRef(s []byte) error {
   155  	return u.unfolder.current.OnKeyRef(u, s)
   156  }
   157  
   158  func (u *unfoldCtx) OnArrayStart(len int, baseType structform.BaseType) error {
   159  	return u.unfolder.current.OnArrayStart(u, len, baseType)
   160  }
   161  
   162  func (u *unfoldCtx) OnArrayFinished() error {
   163  	lBefore := len(u.unfolder.stack) + 1
   164  
   165  	if err := u.unfolder.current.OnArrayFinished(u); err != nil {
   166  		return err
   167  	}
   168  
   169  	lAfter := len(u.unfolder.stack) + 1
   170  	if old := u.unfolder.current; lAfter > 1 && lBefore != lAfter {
   171  		return old.OnChildArrayDone(u)
   172  	}
   173  
   174  	return nil
   175  }
   176  
   177  func (u *unfoldCtx) OnNil() error {
   178  	return u.unfolder.current.OnNil(u)
   179  }
   180  
   181  func (u *unfoldCtx) OnBool(b bool) error {
   182  	return u.unfolder.current.OnBool(u, b)
   183  }
   184  
   185  func (u *unfoldCtx) OnString(s string) error {
   186  	return u.unfolder.current.OnString(u, s)
   187  }
   188  
   189  func (u *unfoldCtx) OnStringRef(s []byte) error {
   190  	return u.unfolder.current.OnStringRef(u, s)
   191  }
   192  
   193  func (u *unfoldCtx) OnInt8(i int8) error {
   194  	return u.unfolder.current.OnInt8(u, i)
   195  }
   196  
   197  func (u *unfoldCtx) OnInt16(i int16) error {
   198  	return u.unfolder.current.OnInt16(u, i)
   199  }
   200  
   201  func (u *unfoldCtx) OnInt32(i int32) error {
   202  	return u.unfolder.current.OnInt32(u, i)
   203  }
   204  
   205  func (u *unfoldCtx) OnInt64(i int64) error {
   206  	return u.unfolder.current.OnInt64(u, i)
   207  }
   208  
   209  func (u *unfoldCtx) OnInt(i int) error {
   210  	return u.unfolder.current.OnInt(u, i)
   211  }
   212  
   213  func (u *unfoldCtx) OnByte(b byte) error {
   214  	return u.unfolder.current.OnByte(u, b)
   215  }
   216  
   217  func (u *unfoldCtx) OnUint8(v uint8) error {
   218  	return u.unfolder.current.OnUint8(u, v)
   219  }
   220  
   221  func (u *unfoldCtx) OnUint16(v uint16) error {
   222  	return u.unfolder.current.OnUint16(u, v)
   223  }
   224  
   225  func (u *unfoldCtx) OnUint32(v uint32) error {
   226  	return u.unfolder.current.OnUint32(u, v)
   227  }
   228  
   229  func (u *unfoldCtx) OnUint64(v uint64) error {
   230  	return u.unfolder.current.OnUint64(u, v)
   231  }
   232  
   233  func (u *unfoldCtx) OnUint(v uint) error {
   234  	return u.unfolder.current.OnUint(u, v)
   235  }
   236  
   237  func (u *unfoldCtx) OnFloat32(f float32) error {
   238  	return u.unfolder.current.OnFloat32(u, f)
   239  }
   240  
   241  func (u *unfoldCtx) OnFloat64(f float64) error {
   242  	return u.unfolder.current.OnFloat64(u, f)
   243  }
   244  
   245  func newTypeUnfoldRegistry() *typeUnfoldRegistry {
   246  	return &typeUnfoldRegistry{m: map[reflect.Type]reflUnfolder{}}
   247  }
   248  
   249  func (r *typeUnfoldRegistry) find(t reflect.Type) reflUnfolder {
   250  	r.mu.RLock()
   251  	defer r.mu.RUnlock()
   252  	return r.m[t]
   253  }
   254  
   255  func (r *typeUnfoldRegistry) set(t reflect.Type, f reflUnfolder) {
   256  	r.mu.Lock()
   257  	defer r.mu.Unlock()
   258  	r.m[t] = f
   259  }