github.com/brownsys/tracing-framework-go@v0.0.0-20161210174012-0542a62412fe/other/trace/baggage/baggage.go (about)

     1  package baggage
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sync"
     7  
     8  	"github.com/golang/protobuf/proto"
     9  
    10  	lproto "github.com/brownsys/tracing-framework-go/trace/baggage/internal/proto"
    11  )
    12  
    13  // ContextKey should be used as the key for baggage
    14  // propagated using a context.Context object (from
    15  // the golang.org/x/net/context (pre-go1.7) or context
    16  // (go1.7) packages).
    17  var ContextKey struct{ private struct{} }
    18  
    19  // ByteNamespaces is a set of named namespaces
    20  // in which all values are represented by byte
    21  // slices. Since byte slices are not legal map
    22  // keys in Go, strings with the same contents
    23  // are used instead. These strings are not
    24  // necessarily human-readable, and should be
    25  // treated simply as byte slices which are stored
    26  // temporarily as strings.
    27  type ByteNamespaces map[string]ByteBaggage
    28  
    29  // ByteBaggage is a set of named bags
    30  // in which all values are represented by byte
    31  // slices. Since byte slices are not legal map
    32  // keys in Go, strings with the same contents
    33  // are used instead. These strings are not
    34  // necessarily human-readable, and should be
    35  // treated simply as byte slices which are stored
    36  // temporarily as strings.
    37  type ByteBaggage map[string][][]byte
    38  
    39  type Marshaler interface {
    40  	MarshalBaggage() ([]byte, error)
    41  }
    42  
    43  type Unmarshaler interface {
    44  	UnmarshalBaggage(b []byte) error
    45  }
    46  
    47  func Marshal(v interface{}) ([]byte, error) {
    48  	if bv, ok := v.(ByteNamespaces); ok {
    49  		var message lproto.BaggageMessage
    50  		message.Namespace = make([]*lproto.BaggageMessage_NamespaceData, len(bv))
    51  
    52  		i := -1
    53  		for k, ns := range bv {
    54  			i++
    55  			var pns lproto.BaggageMessage_NamespaceData
    56  			pns.Key = []byte(k)
    57  			pns.Bag = make([]*lproto.BaggageMessage_BagData, len(ns))
    58  			j := -1
    59  			for k, bag := range ns {
    60  				j++
    61  				var pbag lproto.BaggageMessage_BagData
    62  				pbag.Key = []byte(k)
    63  				pbag.Value = bag
    64  				pns.Bag[j] = &pbag
    65  			}
    66  			message.Namespace[i] = &pns
    67  		}
    68  
    69  		bytes, err := proto.Marshal(&message)
    70  		if err != nil {
    71  			return nil, fmt.Errorf("baggage: Marshal: %v", err)
    72  		}
    73  		return bytes, nil
    74  	}
    75  
    76  	rv := reflect.ValueOf(v)
    77  	typ := rv.Type()
    78  
    79  	marshalSettingsCache.RLock()
    80  	settings, ok := marshalSettingsCache.m[typ]
    81  	marshalSettingsCache.RUnlock()
    82  	if !ok {
    83  		var err error
    84  		settings, err = makeMarshalSettings(typ)
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  
    89  		marshalSettingsCache.Lock()
    90  		marshalSettingsCache.m[typ] = settings
    91  		marshalSettingsCache.Unlock()
    92  	}
    93  
    94  	panic("unimplemented")
    95  }
    96  
    97  func Unmarshal(data []byte, v interface{}) error {
    98  	bv, ok1 := v.(ByteNamespaces)
    99  	bvp, ok2 := v.(*ByteNamespaces)
   100  	if ok1 || ok2 {
   101  		if ok2 {
   102  			bv = *bvp
   103  		}
   104  
   105  		var message lproto.BaggageMessage
   106  
   107  		if err := proto.Unmarshal(data, &message); err != nil {
   108  			return fmt.Errorf("baggage: Unmarshal: %v", err)
   109  		}
   110  
   111  		for _, ns := range message.GetNamespace() {
   112  			if ns == nil {
   113  				panic("internal error")
   114  			}
   115  			bags := make(ByteBaggage)
   116  			for _, bag := range ns.GetBag() {
   117  				if bag == nil {
   118  					panic("internal error")
   119  				}
   120  				bags[string(bag.GetKey())] = bag.GetValue()
   121  			}
   122  			bv[string(ns.GetKey())] = bags
   123  		}
   124  
   125  		return nil
   126  	}
   127  
   128  	rv := reflect.ValueOf(v)
   129  	typ := rv.Type()
   130  
   131  	if typ.Kind() != reflect.Ptr {
   132  		return fmt.Errorf("baggage: Unmarshal non-pointer %v", typ)
   133  	}
   134  
   135  	rv = rv.Elem()
   136  	typ = typ.Elem()
   137  
   138  	unmarshalSettingsCache.RLock()
   139  	settings, ok := unmarshalSettingsCache.m[typ]
   140  	unmarshalSettingsCache.RUnlock()
   141  	if !ok {
   142  		var err error
   143  		settings, err = makeUnmarshalSettings(typ)
   144  		if err != nil {
   145  			return err
   146  		}
   147  
   148  		unmarshalSettingsCache.Lock()
   149  		unmarshalSettingsCache.m[typ] = settings
   150  		unmarshalSettingsCache.Unlock()
   151  	}
   152  
   153  	var message lproto.BaggageMessage
   154  
   155  	if err := proto.Unmarshal(data, &message); err != nil {
   156  		return fmt.Errorf("baggage: Unmarshal: %v", err)
   157  	}
   158  
   159  	for _, ns := range message.GetNamespace() {
   160  		if ns == nil {
   161  			panic("internal error")
   162  		}
   163  
   164  		name := reflect.New(settings.namespaceNameTyp)
   165  		if settings.namespaceNameTyp == stringTyp {
   166  			name.Elem().SetString(string(ns.Key))
   167  		} else {
   168  			err := name.Interface().(Unmarshaler).UnmarshalBaggage(ns.Key)
   169  			if err != nil {
   170  				return fmt.Errorf("baggage: Unmarshal: namespace key: %v", err)
   171  			}
   172  		}
   173  		name = name.Elem()
   174  
   175  		namespace := reflect.MakeMap(settings.namespaceTyp)
   176  		for _, bag := range ns.GetBag() {
   177  			if bag == nil {
   178  				panic("internal error")
   179  			}
   180  
   181  			bk := reflect.New(settings.bagNameTyp)
   182  			if settings.bagNameTyp == stringTyp {
   183  				bk.Elem().SetString(string(bag.Key))
   184  			} else {
   185  				err := bk.Interface().(Unmarshaler).UnmarshalBaggage(bag.Key)
   186  				if err != nil {
   187  					return fmt.Errorf("baggage: Unmarshal: baggage key: %v", err)
   188  				}
   189  			}
   190  			bk = bk.Elem()
   191  
   192  			bv := reflect.MakeSlice(reflect.SliceOf(settings.bagElemTyp), len(bag.Value), len(bag.Value))
   193  			for i, v := range bag.Value {
   194  				elem := bv.Index(i)
   195  				if settings.bagElemTyp == byteSliceTyp {
   196  					elem.Set(reflect.ValueOf(v))
   197  				} else {
   198  					err := elem.Addr().Interface().(Unmarshaler).UnmarshalBaggage(v)
   199  					if err != nil {
   200  						return fmt.Errorf("baggage: Unmarshal: baggage element: %v", err)
   201  					}
   202  				}
   203  			}
   204  
   205  			namespace.SetMapIndex(bk, bv)
   206  		}
   207  
   208  		rv.SetMapIndex(name, namespace)
   209  	}
   210  
   211  	return nil
   212  }
   213  
   214  var marshalSettingsCache = struct {
   215  	m map[reflect.Type]marshalSettings
   216  	sync.RWMutex
   217  }{m: make(map[reflect.Type]marshalSettings)}
   218  
   219  var unmarshalSettingsCache = struct {
   220  	m map[reflect.Type]unmarshalSettings
   221  	sync.RWMutex
   222  }{m: make(map[reflect.Type]unmarshalSettings)}
   223  
   224  type marshalSettings struct {
   225  	bagElemTyp       reflect.Type
   226  	bagNameTyp       reflect.Type
   227  	namespaceNameTyp reflect.Type
   228  	namespaceTyp     reflect.Type
   229  }
   230  
   231  type unmarshalSettings struct {
   232  	bagElemTyp       reflect.Type
   233  	bagNameTyp       reflect.Type
   234  	namespaceNameTyp reflect.Type
   235  	namespaceTyp     reflect.Type
   236  }
   237  
   238  // type converter struct {
   239  // 	bagElemToByteSlice       func(v reflect.Value) []byte
   240  // 	byteSliceToBagElem       func(b []byte) reflect.Value
   241  // 	bagNameToByteSlice       func(v reflect.Value) []byte
   242  // 	byteSliceToBagName       func(b []byte) reflect.Value
   243  // 	namespaceNameToByteSlice func(v reflect.Value) []byte
   244  // 	byteSliceToNamespaceName func(b []byte) reflect.Value
   245  // }
   246  
   247  var (
   248  	stringTyp    = reflect.TypeOf("")
   249  	byteSliceTyp = reflect.TypeOf([]byte(nil))
   250  
   251  	marshalerTyp   = reflect.TypeOf([]Marshaler(nil)).Elem()
   252  	unmarshalerTyp = reflect.TypeOf([]Unmarshaler(nil)).Elem()
   253  )
   254  
   255  func makeMarshalSettings(t reflect.Type) (marshalSettings, error) {
   256  	switch {
   257  	case t.Kind() != reflect.Map:
   258  		fallthrough
   259  	case t.Elem().Kind() != reflect.Map:
   260  		fallthrough
   261  	case t.Elem().Elem().Kind() != reflect.Slice:
   262  		return marshalSettings{}, fmt.Errorf("baggage: Marshal: type must be of the form map[T]map[U][]V")
   263  	}
   264  
   265  	var settings marshalSettings
   266  
   267  	// namespace name type
   268  	tt := t.Key()
   269  	settings.namespaceTyp = t.Elem()
   270  	settings.namespaceNameTyp = tt
   271  	switch {
   272  	case tt == stringTyp:
   273  	case tt.Implements(marshalerTyp):
   274  	default:
   275  		return marshalSettings{}, fmt.Errorf("baggage: Marshal: type %v is not string and does not implement Marshaler", tt)
   276  	}
   277  
   278  	// bage name type
   279  	tt = t.Elem().Key()
   280  	settings.bagNameTyp = tt
   281  	switch {
   282  	case tt == stringTyp:
   283  	case tt.Implements(marshalerTyp):
   284  	default:
   285  		return marshalSettings{}, fmt.Errorf("baggage: Marshal: type %v is not string and does not implement Marshaler", tt)
   286  	}
   287  
   288  	// bag element type
   289  	tt = t.Elem().Elem().Elem()
   290  	settings.bagElemTyp = tt
   291  	switch {
   292  	case tt == byteSliceTyp:
   293  	case tt.Implements(marshalerTyp):
   294  	default:
   295  		return marshalSettings{}, fmt.Errorf("baggage: Marshal: type %v is not []byte and does not implement Marshaler", tt)
   296  	}
   297  
   298  	return settings, nil
   299  }
   300  
   301  func makeUnmarshalSettings(t reflect.Type) (unmarshalSettings, error) {
   302  	switch {
   303  	case t.Kind() != reflect.Map:
   304  		fallthrough
   305  	case t.Elem().Kind() != reflect.Map:
   306  		fallthrough
   307  	case t.Elem().Elem().Kind() != reflect.Slice:
   308  		return unmarshalSettings{}, fmt.Errorf("baggage: Unmarshal: type must be of the form map[T]map[U][]V")
   309  	}
   310  
   311  	var settings unmarshalSettings
   312  
   313  	// namespace name type
   314  	tt := t.Key()
   315  	settings.namespaceTyp = t.Elem()
   316  	settings.namespaceNameTyp = tt
   317  	switch {
   318  	case tt == stringTyp:
   319  	case reflect.PtrTo(tt).Implements(unmarshalerTyp):
   320  	default:
   321  		return unmarshalSettings{}, fmt.Errorf("baggage: Unmarshal: type %v is not string and does not implement Unmarshaler", tt)
   322  	}
   323  
   324  	// bage name type
   325  	tt = t.Elem().Key()
   326  	settings.bagNameTyp = tt
   327  	switch {
   328  	case tt == stringTyp:
   329  	case reflect.PtrTo(tt).Implements(unmarshalerTyp):
   330  	default:
   331  		return unmarshalSettings{}, fmt.Errorf("baggage: Unmarshal: type %v is not string and does not implement Unmarshaler", tt)
   332  	}
   333  
   334  	// bag element type
   335  	tt = t.Elem().Elem().Elem()
   336  	settings.bagElemTyp = tt
   337  	switch {
   338  	case tt == byteSliceTyp:
   339  	case reflect.PtrTo(tt).Implements(unmarshalerTyp):
   340  	default:
   341  		return unmarshalSettings{}, fmt.Errorf("baggage: Unmarshal: type %v is not []byte and does not implement Unmarshaler", tt)
   342  	}
   343  
   344  	return settings, nil
   345  }