123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 |
- package ndr
- import (
- "errors"
- "fmt"
- "reflect"
- )
- // Union interface must be implemented by structs that will be unmarshaled into from the NDR byte stream union representation.
- // The union's discriminating tag will be passed to the SwitchFunc method.
- // The discriminating tag field must have the struct tag: `ndr:"unionTag"`
- // If the union is encapsulated the discriminating tag field must have the struct tag: `ndr:"encapsulated"`
- // The possible value fields that can be selected from must have the struct tag: `ndr:"unionField"`
- type Union interface {
- SwitchFunc(t interface{}) string
- }
- // Union related constants such as struct tag values
- const (
- unionSelectionFuncName = "SwitchFunc"
- TagEncapsulated = "encapsulated"
- TagUnionTag = "unionTag"
- TagUnionField = "unionField"
- )
- func (dec *Decoder) isUnion(field reflect.Value, tag reflect.StructTag) (r reflect.Value) {
- ndrTag := parseTags(tag)
- if !ndrTag.HasValue(TagUnionTag) {
- return
- }
- r = field
- // For a non-encapsulated union, the discriminant is marshalled into the transmitted data stream twice: once as the
- // field or parameter, which is referenced by the switch_is construct, in the procedure argument list; and once as
- // the first part of the union representation.
- if !ndrTag.HasValue(TagEncapsulated) {
- dec.r.Discard(int(r.Type().Size()))
- }
- return
- }
- // unionSelectedField returns the field name of which of the union values to fill
- func unionSelectedField(union, discriminant reflect.Value) (string, error) {
- if !union.Type().Implements(reflect.TypeOf(new(Union)).Elem()) {
- return "", errors.New("struct does not implement union interface")
- }
- args := []reflect.Value{discriminant}
- // Call the SelectFunc of the union struct to find the name of the field to fill with the value selected.
- sf := union.MethodByName(unionSelectionFuncName)
- if !sf.IsValid() {
- return "", fmt.Errorf("could not find a selection function called %s in the unions struct representation", unionSelectionFuncName)
- }
- f := sf.Call(args)
- if f[0].Kind() != reflect.String || f[0].String() == "" {
- return "", fmt.Errorf("the union select function did not return a string for the name of the field to fill")
- }
- return f[0].String(), nil
- }
|