github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/elvish/eval/vals/struct.go (about)

     1  package vals
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/u-root/u-root/cmds/elvish/parse"
    10  	"github.com/xiaq/persistent/hash"
    11  )
    12  
    13  var (
    14  	ErrIndexMustBeString = errors.New("index must be string")
    15  )
    16  
    17  // Struct is like a Map with fixed keys.
    18  type Struct struct {
    19  	descriptor *StructDescriptor
    20  	fields     []interface{}
    21  }
    22  
    23  var _ Indexer = (*Struct)(nil)
    24  
    25  // NewStruct creates a new *Struct value.
    26  func NewStruct(descriptor *StructDescriptor, fields []interface{}) *Struct {
    27  	return &Struct{descriptor, fields}
    28  }
    29  
    30  func (*Struct) Kind() string {
    31  	return "map"
    32  }
    33  
    34  // Equal returns true if the rhs is MapLike and all pairs are equal.
    35  func (s *Struct) Equal(rhs interface{}) bool {
    36  	if s == rhs {
    37  		return true
    38  	}
    39  	s2, ok := rhs.(*Struct)
    40  	if !ok {
    41  		return false
    42  	}
    43  	if s.descriptor != s2.descriptor {
    44  		return false
    45  	}
    46  	for i, field := range s.fields {
    47  		if !Equal(field, s2.fields[i]) {
    48  			return false
    49  		}
    50  	}
    51  	return true
    52  }
    53  
    54  func (s *Struct) Hash() uint32 {
    55  	h := hash.DJBInit
    56  	for _, field := range s.fields {
    57  		h = hash.DJBCombine(h, Hash(field))
    58  	}
    59  	return h
    60  }
    61  
    62  func (s *Struct) Repr(indent int) string {
    63  	var builder MapReprBuilder
    64  	builder.Indent = indent
    65  	for i, name := range s.descriptor.fieldNames {
    66  		builder.WritePair(parse.Quote(name), indent+2, Repr(s.fields[i], indent+2))
    67  	}
    68  	return builder.String()
    69  }
    70  
    71  func (s *Struct) Len() int {
    72  	return len(s.descriptor.fieldNames)
    73  }
    74  
    75  func (s *Struct) Index(k interface{}) (interface{}, bool) {
    76  	i, ok := s.index(k)
    77  	if !ok {
    78  		return nil, false
    79  	}
    80  	return s.fields[i], true
    81  }
    82  
    83  func (s *Struct) Assoc(k, v interface{}) (interface{}, error) {
    84  	i, ok := s.index(k)
    85  	if !ok {
    86  		return nil, NoSuchKey(k)
    87  	}
    88  	fields := make([]interface{}, len(s.fields))
    89  	copy(fields, s.fields)
    90  	fields[i] = v
    91  	return &Struct{s.descriptor, fields}, nil
    92  }
    93  
    94  func (s *Struct) IterateKey(f func(interface{}) bool) {
    95  	for _, field := range s.descriptor.fieldNames {
    96  		if !f(string(field)) {
    97  			break
    98  		}
    99  	}
   100  }
   101  
   102  func (s *Struct) IteratePair(f func(interface{}, interface{}) bool) {
   103  	for i, field := range s.descriptor.fieldNames {
   104  		if !f(string(field), s.fields[i]) {
   105  			break
   106  		}
   107  	}
   108  }
   109  
   110  func (s *Struct) HasKey(k interface{}) bool {
   111  	_, ok := s.index(k)
   112  	return ok
   113  }
   114  
   115  func (s *Struct) index(k interface{}) (int, bool) {
   116  	kstring, ok := k.(string)
   117  	if !ok {
   118  		return 0, false
   119  	}
   120  	index, ok := s.descriptor.fieldIndex[kstring]
   121  	return index, ok
   122  }
   123  
   124  // MarshalJSON encodes the Struct to a JSON Object.
   125  func (s *Struct) MarshalJSON() ([]byte, error) {
   126  	var buf bytes.Buffer
   127  	buf.WriteByte('{')
   128  	for i, fieldName := range s.descriptor.fieldNames {
   129  		if i > 0 {
   130  			buf.WriteByte(',')
   131  		}
   132  		buf.Write(s.descriptor.jsonFieldNames[i])
   133  		buf.WriteByte(':')
   134  		fieldJSON, err := json.Marshal(s.fields[i])
   135  		if err != nil {
   136  			return nil, fmt.Errorf("cannot encode field %q: %v", fieldName, err)
   137  		}
   138  		buf.Write(fieldJSON)
   139  	}
   140  	buf.WriteByte('}')
   141  	return buf.Bytes(), nil
   142  }
   143  
   144  // StructDescriptor contains information about the fields in a Struct.
   145  type StructDescriptor struct {
   146  	fieldNames     []string
   147  	jsonFieldNames [][]byte
   148  	fieldIndex     map[string]int
   149  }
   150  
   151  // NewStructDescriptor creates a new struct descriptor from a list of field
   152  // names.
   153  func NewStructDescriptor(fields ...string) *StructDescriptor {
   154  	fieldNames := append([]string(nil), fields...)
   155  	jsonFieldNames := make([][]byte, len(fields))
   156  	fieldIndex := make(map[string]int)
   157  	for i, name := range fieldNames {
   158  		fieldIndex[name] = i
   159  		jsonFieldName, err := json.Marshal(name)
   160  		// json.Marshal should never fail on string.
   161  		if err != nil {
   162  			panic(err)
   163  		}
   164  		jsonFieldNames[i] = jsonFieldName
   165  	}
   166  	return &StructDescriptor{fieldNames, jsonFieldNames, fieldIndex}
   167  }