kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/serving/xrefs/columnar/columnar_encoding.go (about)

     1  /*
     2   * Copyright 2018 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  // Package columnar implements the columnar table format for a Kythe xrefs service.
    18  package columnar // import "kythe.io/kythe/go/serving/xrefs/columnar"
    19  
    20  import (
    21  	"crypto/sha256"
    22  	"encoding/hex"
    23  	"fmt"
    24  
    25  	"kythe.io/kythe/go/util/keys"
    26  	"kythe.io/kythe/go/util/kytheuri"
    27  
    28  	"google.golang.org/protobuf/proto"
    29  
    30  	scpb "kythe.io/kythe/proto/schema_go_proto"
    31  	spb "kythe.io/kythe/proto/storage_go_proto"
    32  	xspb "kythe.io/kythe/proto/xref_serving_go_proto"
    33  )
    34  
    35  var (
    36  	// DecorationsKeyPrefix is the common key prefix for all Kythe columnar
    37  	// FileDecoration key-value entries.
    38  	DecorationsKeyPrefix, _ = keys.Append(nil, "fd")
    39  
    40  	// CrossReferencesKeyPrefix is the common key prefix for all Kythe columnar
    41  	// CrossReferences key-value entries.
    42  	CrossReferencesKeyPrefix, _ = keys.Append(nil, "xr")
    43  )
    44  
    45  func init() {
    46  	// Restrict the capacity of the key prefixes to ensure appending to it creates a new array.
    47  	DecorationsKeyPrefix = DecorationsKeyPrefix[:len(DecorationsKeyPrefix):len(DecorationsKeyPrefix)]
    48  	CrossReferencesKeyPrefix = CrossReferencesKeyPrefix[:len(CrossReferencesKeyPrefix):len(CrossReferencesKeyPrefix)]
    49  }
    50  
    51  // Columnar file decorations group numbers.
    52  // See: kythe/proto/xref_serving.proto
    53  const (
    54  	columnarDecorationsIndexGroup              = -1 // no group number
    55  	columnarDecorationsTextGroup               = 0
    56  	columnarDecorationsTargetGroup             = 10
    57  	columnarDecorationsTargetOverrideGroup     = 20
    58  	columnarDecorationsTargetNodeGroup         = 30
    59  	columnarDecorationsTargetDefinitionGroup   = 40
    60  	columnarDecorationsDefinitionLocationGroup = 50
    61  	columnarDecorationsOverrideGroup           = 60
    62  	columnarDecorationsDiagnosticGroup         = 70
    63  )
    64  
    65  // KV is a single columnar key-value entry.
    66  type KV struct{ Key, Value []byte }
    67  
    68  // EncodeDecorationsEntry encodes a columnar FileDecorations entry.
    69  func EncodeDecorationsEntry(keyPrefix []byte, fd *xspb.FileDecorations) (*KV, error) {
    70  	switch e := fd.Entry.(type) {
    71  	case *xspb.FileDecorations_Index_:
    72  		return encodeDecorIndex(keyPrefix, fd.File, e.Index)
    73  	case *xspb.FileDecorations_Text_:
    74  		return encodeDecorText(keyPrefix, fd.File, e.Text)
    75  	case *xspb.FileDecorations_Target_:
    76  		return encodeDecorTarget(keyPrefix, fd.File, e.Target)
    77  	case *xspb.FileDecorations_TargetOverride_:
    78  		return encodeDecorTargetOverride(keyPrefix, fd.File, e.TargetOverride)
    79  	case *xspb.FileDecorations_TargetNode_:
    80  		return encodeDecorTargetNode(keyPrefix, fd.File, e.TargetNode)
    81  	case *xspb.FileDecorations_TargetDefinition_:
    82  		return encodeDecorTargetDefinition(keyPrefix, fd.File, e.TargetDefinition)
    83  	case *xspb.FileDecorations_DefinitionLocation_:
    84  		return encodeDecorDefinitionLocation(keyPrefix, fd.File, e.DefinitionLocation)
    85  	case *xspb.FileDecorations_Override_:
    86  		return encodeDecorOverride(keyPrefix, fd.File, e.Override)
    87  	case *xspb.FileDecorations_Diagnostic_:
    88  		return encodeDecorDiagnostic(keyPrefix, fd.File, e.Diagnostic)
    89  	default:
    90  		return nil, fmt.Errorf("unknown FileDecorations entry: %T", e)
    91  	}
    92  }
    93  
    94  func encodeDecorIndex(prefix []byte, file *spb.VName, idx *xspb.FileDecorations_Index) (*KV, error) {
    95  	key, err := keys.Append(prefix, file)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	val, err := proto.Marshal(idx)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	return &KV{key, val}, nil
   104  }
   105  
   106  func encodeDecorText(prefix []byte, file *spb.VName, t *xspb.FileDecorations_Text) (*KV, error) {
   107  	key, err := keys.Append(prefix, file, columnarDecorationsTextGroup, t.StartOffset, t.EndOffset)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	// Encode the subset of the value proto not encoded in the key.
   112  	val, err := proto.Marshal(&xspb.FileDecorations_Text{Text: t.Text})
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	return &KV{key, val}, nil
   117  }
   118  
   119  func encodeDecorTarget(prefix []byte, file *spb.VName, t *xspb.FileDecorations_Target) (*KV, error) {
   120  	key, err := keys.Append(prefix, file,
   121  		columnarDecorationsTargetGroup, t.BuildConfig, t.StartOffset, t.EndOffset,
   122  		t.GetGenericKind(), int32(t.GetKytheKind()), t.Target)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	val, err := proto.Marshal(&xspb.FileDecorations_Target{})
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	return &KV{key, val}, nil
   131  }
   132  
   133  func encodeDecorTargetOverride(prefix []byte, file *spb.VName, to *xspb.FileDecorations_TargetOverride) (*KV, error) {
   134  	key, err := keys.Append(prefix, file,
   135  		columnarDecorationsTargetOverrideGroup, to.Overridden, int32(to.Kind), to.Overriding)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	val, err := proto.Marshal(to)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	return &KV{key, val}, nil
   144  }
   145  func encodeDecorTargetNode(prefix []byte, file *spb.VName, tn *xspb.FileDecorations_TargetNode) (*KV, error) {
   146  	key, err := keys.Append(prefix, file, columnarDecorationsTargetNodeGroup, tn.Node.Source)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	val, err := proto.Marshal(tn)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	return &KV{key, val}, nil
   155  }
   156  func encodeDecorTargetDefinition(prefix []byte, file *spb.VName, td *xspb.FileDecorations_TargetDefinition) (*KV, error) {
   157  	key, err := keys.Append(prefix, file, columnarDecorationsTargetDefinitionGroup, td.Target)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	// Encode the subset of the value proto not encoded in the key.
   162  	val, err := proto.Marshal(&xspb.FileDecorations_TargetDefinition{Definition: td.Definition})
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	return &KV{key, val}, nil
   167  }
   168  func encodeDecorDefinitionLocation(prefix []byte, file *spb.VName, def *xspb.FileDecorations_DefinitionLocation) (*KV, error) {
   169  	// TODO(schroederc): use VNames throughout pipeline
   170  	defVName, err := kytheuri.ToVName(def.Location.Ticket)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	key, err := keys.Append(prefix, file, columnarDecorationsDefinitionLocationGroup, defVName)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	val, err := proto.Marshal(def)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  	return &KV{key, val}, nil
   183  }
   184  func encodeDecorOverride(prefix []byte, file *spb.VName, o *xspb.FileDecorations_Override) (*KV, error) {
   185  	key, err := keys.Append(prefix, file, columnarDecorationsOverrideGroup, o.Override)
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  	// Encode the subset of the value proto not encoded in the key.
   190  	val, err := proto.Marshal(&xspb.FileDecorations_Override{MarkedSource: o.MarkedSource})
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  	return &KV{key, val}, nil
   195  }
   196  func encodeDecorDiagnostic(prefix []byte, file *spb.VName, d *xspb.FileDecorations_Diagnostic) (*KV, error) {
   197  	val, err := proto.Marshal(d)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	h := sha256.Sum224(val)
   202  	key, err := keys.Append(prefix, file, columnarDecorationsDiagnosticGroup, d.Diagnostic.Span.GetStart().GetByteOffset(), d.Diagnostic.Span.GetEnd().GetByteOffset(), hex.EncodeToString(h[:]))
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  	return &KV{key, val}, nil
   207  }
   208  
   209  // DecodeDecorationsEntry decodes a columnar FileDecorations entry.
   210  func DecodeDecorationsEntry(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   211  	kind := columnarDecorationsIndexGroup
   212  	if key != "" {
   213  		var err error
   214  		key, err = keys.Parse(key, &kind)
   215  		if err != nil {
   216  			return nil, fmt.Errorf("invalid FileDecorations group kind: %v", err)
   217  		}
   218  	}
   219  	switch kind {
   220  	case columnarDecorationsIndexGroup:
   221  		return decodeDecorIndex(file, key, val)
   222  	case columnarDecorationsTextGroup:
   223  		return decodeDecorText(file, key, val)
   224  	case columnarDecorationsTargetGroup:
   225  		return decodeDecorTarget(file, key, val)
   226  	case columnarDecorationsTargetOverrideGroup:
   227  		return decodeDecorTargetOverride(file, key, val)
   228  	case columnarDecorationsTargetNodeGroup:
   229  		return decodeDecorTargetNode(file, key, val)
   230  	case columnarDecorationsTargetDefinitionGroup:
   231  		return decodeDecorTargetDefinition(file, key, val)
   232  	case columnarDecorationsDefinitionLocationGroup:
   233  		return decodeDecorDefinitionLocation(file, key, val)
   234  	case columnarDecorationsOverrideGroup:
   235  		return decodeDecorOverride(file, key, val)
   236  	case columnarDecorationsDiagnosticGroup:
   237  		return decodeDecorDiagnostic(file, key, val)
   238  	default:
   239  		return nil, fmt.Errorf("unknown group kind: %d", kind)
   240  	}
   241  }
   242  
   243  func decodeDecorIndex(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   244  	var idx xspb.FileDecorations_Index
   245  	if err := proto.Unmarshal(val, &idx); err != nil {
   246  		return nil, err
   247  	}
   248  	return &xspb.FileDecorations{
   249  		File:  file,
   250  		Entry: &xspb.FileDecorations_Index_{&idx},
   251  	}, nil
   252  }
   253  
   254  func decodeDecorText(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   255  	var text xspb.FileDecorations_Text
   256  	if err := proto.Unmarshal(val, &text); err != nil {
   257  		return nil, err
   258  	}
   259  	return &xspb.FileDecorations{
   260  		File:  file,
   261  		Entry: &xspb.FileDecorations_Text_{&text},
   262  	}, nil
   263  }
   264  
   265  func decodeDecorTarget(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   266  	target := &xspb.FileDecorations_Target{Target: &spb.VName{}}
   267  	var (
   268  		kytheKindNum int32
   269  		genericKind  string
   270  	)
   271  	key, err := keys.Parse(key,
   272  		&target.BuildConfig, &target.StartOffset, &target.EndOffset,
   273  		&genericKind, &kytheKindNum, target.Target)
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  
   278  	if genericKind != "" {
   279  		target.Kind = &xspb.FileDecorations_Target_GenericKind{genericKind}
   280  	} else {
   281  		target.Kind = &xspb.FileDecorations_Target_KytheKind{scpb.EdgeKind(kytheKindNum)}
   282  	}
   283  	return &xspb.FileDecorations{
   284  		File:  file,
   285  		Entry: &xspb.FileDecorations_Target_{target},
   286  	}, nil
   287  }
   288  
   289  func decodeDecorTargetOverride(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   290  	var overridden, overriding spb.VName
   291  	var kind int32
   292  	key, err := keys.Parse(key, &overridden, &kind, &overriding)
   293  	if err != nil {
   294  		return nil, err
   295  	} else if key != "" {
   296  		return nil, fmt.Errorf("unexpected TargetOverride key suffix: %q", key)
   297  	}
   298  	var to xspb.FileDecorations_TargetOverride
   299  	if err = proto.Unmarshal(val, &to); err != nil {
   300  		return nil, err
   301  	}
   302  	return &xspb.FileDecorations{
   303  		File:  file,
   304  		Entry: &xspb.FileDecorations_TargetOverride_{&to},
   305  	}, nil
   306  }
   307  
   308  func decodeDecorTargetNode(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   309  	var tn xspb.FileDecorations_TargetNode
   310  	if err := proto.Unmarshal(val, &tn); err != nil {
   311  		return nil, err
   312  	}
   313  	return &xspb.FileDecorations{
   314  		File:  file,
   315  		Entry: &xspb.FileDecorations_TargetNode_{&tn},
   316  	}, nil
   317  }
   318  
   319  func decodeDecorTargetDefinition(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   320  	var target spb.VName
   321  	key, err := keys.Parse(key, &target)
   322  	if err != nil {
   323  		return nil, err
   324  	} else if key != "" {
   325  		return nil, fmt.Errorf("unexpected TargetDefinition key suffix: %q", key)
   326  	}
   327  	var def xspb.FileDecorations_TargetDefinition
   328  	if err := proto.Unmarshal(val, &def); err != nil {
   329  		return nil, err
   330  	}
   331  	def.Target = &target
   332  	return &xspb.FileDecorations{
   333  		File:  file,
   334  		Entry: &xspb.FileDecorations_TargetDefinition_{&def},
   335  	}, nil
   336  }
   337  
   338  func decodeDecorDefinitionLocation(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   339  	var loc xspb.FileDecorations_DefinitionLocation
   340  	if err := proto.Unmarshal(val, &loc); err != nil {
   341  		return nil, err
   342  	}
   343  	return &xspb.FileDecorations{
   344  		File:  file,
   345  		Entry: &xspb.FileDecorations_DefinitionLocation_{&loc},
   346  	}, nil
   347  }
   348  
   349  func decodeDecorOverride(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   350  	var target spb.VName
   351  	key, err := keys.Parse(key, &target)
   352  	if err != nil {
   353  		return nil, err
   354  	} else if key != "" {
   355  		return nil, fmt.Errorf("unexpected Override key suffix: %q", key)
   356  	}
   357  	var o xspb.FileDecorations_Override
   358  	if err := proto.Unmarshal(val, &o); err != nil {
   359  		return nil, err
   360  	}
   361  	o.Override = &target
   362  	return &xspb.FileDecorations{
   363  		File:  file,
   364  		Entry: &xspb.FileDecorations_Override_{&o},
   365  	}, nil
   366  }
   367  
   368  func decodeDecorDiagnostic(file *spb.VName, key string, val []byte) (*xspb.FileDecorations, error) {
   369  	var o xspb.FileDecorations_Diagnostic
   370  	if err := proto.Unmarshal(val, &o); err != nil {
   371  		return nil, err
   372  	}
   373  	return &xspb.FileDecorations{
   374  		File:  file,
   375  		Entry: &xspb.FileDecorations_Diagnostic_{&o},
   376  	}, nil
   377  }
   378  
   379  // Columnar file decorations group numbers.
   380  // See: kythe/proto/xref_serving.proto
   381  const (
   382  	columnarXRefsIndexGroup          = -1 // no group number
   383  	columnarXRefsReferenceGroup      = 0
   384  	columnarXRefsRelationGroup       = 10
   385  	columnarXRefsCallerGroup         = 20
   386  	columnarXRefsRelatedNodeGroup    = 30
   387  	columnarXRefsNodeDefinitionGroup = 40
   388  )
   389  
   390  // EncodeCrossReferencesEntry encodes a columnar CrossReferences entry.
   391  func EncodeCrossReferencesEntry(keyPrefix []byte, xr *xspb.CrossReferences) (*KV, error) {
   392  	switch e := xr.Entry.(type) {
   393  	case *xspb.CrossReferences_Index_:
   394  		return encodeXRefIndex(keyPrefix, xr.Source, e.Index)
   395  	case *xspb.CrossReferences_Reference_:
   396  		return encodeXRefReference(keyPrefix, xr.Source, e.Reference)
   397  	case *xspb.CrossReferences_Relation_:
   398  		return encodeXRefRelation(keyPrefix, xr.Source, e.Relation)
   399  	case *xspb.CrossReferences_Caller_:
   400  		return encodeXRefCaller(keyPrefix, xr.Source, e.Caller)
   401  	case *xspb.CrossReferences_Callsite_:
   402  		return encodeXRefCallsite(keyPrefix, xr.Source, e.Callsite)
   403  	case *xspb.CrossReferences_RelatedNode_:
   404  		return encodeXRefRelatedNode(keyPrefix, xr.Source, e.RelatedNode)
   405  	case *xspb.CrossReferences_NodeDefinition_:
   406  		return encodeXRefNodeDefinition(keyPrefix, xr.Source, e.NodeDefinition)
   407  	default:
   408  		return nil, fmt.Errorf("unknown CrossReferences entry: %T", e)
   409  	}
   410  }
   411  
   412  func encodeXRefIndex(prefix []byte, src *spb.VName, idx *xspb.CrossReferences_Index) (*KV, error) {
   413  	key, err := keys.Append(prefix, src)
   414  	if err != nil {
   415  		return nil, err
   416  	}
   417  	val, err := proto.Marshal(idx)
   418  	if err != nil {
   419  		return nil, err
   420  	}
   421  	return &KV{key, val}, nil
   422  }
   423  
   424  func encodeXRefReference(prefix []byte, src *spb.VName, r *xspb.CrossReferences_Reference) (*KV, error) {
   425  	uri, err := kytheuri.Parse(r.Location.Ticket)
   426  	if err != nil {
   427  		return nil, err
   428  	}
   429  	file := &spb.VName{
   430  		Corpus: uri.Corpus,
   431  		Root:   uri.Root,
   432  		Path:   uri.Path,
   433  	}
   434  	key, err := keys.Append(prefix, src, columnarXRefsReferenceGroup,
   435  		r.GetGenericKind(), int32(r.GetKytheKind()), file,
   436  		r.Location.Span.GetStart().GetByteOffset(), r.Location.Span.GetEnd().GetByteOffset())
   437  	if err != nil {
   438  		return nil, err
   439  	}
   440  	val, err := proto.Marshal(&xspb.CrossReferences_Reference{Location: r.Location})
   441  	if err != nil {
   442  		return nil, err
   443  	}
   444  	return &KV{key, val}, nil
   445  }
   446  
   447  func encodeXRefRelation(prefix []byte, src *spb.VName, r *xspb.CrossReferences_Relation) (*KV, error) {
   448  	key, err := keys.Append(prefix, src, columnarXRefsRelationGroup,
   449  		r.GetGenericKind(), int32(r.GetKytheKind()), r.Ordinal, r.Reverse, r.Node)
   450  	if err != nil {
   451  		return nil, err
   452  	}
   453  	val, err := proto.Marshal(&xspb.CrossReferences_Relation{})
   454  	if err != nil {
   455  		return nil, err
   456  	}
   457  	return &KV{key, val}, nil
   458  }
   459  
   460  func encodeXRefCaller(prefix []byte, src *spb.VName, c *xspb.CrossReferences_Caller) (*KV, error) {
   461  	key, err := keys.Append(prefix, src, columnarXRefsCallerGroup, c.Caller)
   462  	if err != nil {
   463  		return nil, err
   464  	}
   465  	val, err := proto.Marshal(&xspb.CrossReferences_Caller{
   466  		Location:     c.Location,
   467  		MarkedSource: c.MarkedSource,
   468  	})
   469  	if err != nil {
   470  		return nil, err
   471  	}
   472  	return &KV{key, val}, nil
   473  }
   474  
   475  func encodeXRefCallsite(prefix []byte, src *spb.VName, c *xspb.CrossReferences_Callsite) (*KV, error) {
   476  	uri, err := kytheuri.Parse(c.Location.Ticket)
   477  	if err != nil {
   478  		return nil, err
   479  	}
   480  	file := &spb.VName{
   481  		Corpus: uri.Corpus,
   482  		Root:   uri.Root,
   483  		Path:   uri.Path,
   484  	}
   485  	key, err := keys.Append(prefix, src, columnarXRefsCallerGroup,
   486  		c.Caller, int32(c.Kind), file,
   487  		c.Location.Span.GetStart().GetByteOffset(), c.Location.Span.GetEnd().GetByteOffset())
   488  	if err != nil {
   489  		return nil, err
   490  	}
   491  	val, err := proto.Marshal(&xspb.CrossReferences_Callsite{
   492  		Location: c.Location,
   493  	})
   494  	if err != nil {
   495  		return nil, err
   496  	}
   497  	return &KV{key, val}, nil
   498  }
   499  
   500  func encodeXRefRelatedNode(prefix []byte, src *spb.VName, n *xspb.CrossReferences_RelatedNode) (*KV, error) {
   501  	key, err := keys.Append(prefix, src, columnarXRefsRelatedNodeGroup, n.Node.Source)
   502  	if err != nil {
   503  		return nil, err
   504  	}
   505  	val, err := proto.Marshal(n)
   506  	if err != nil {
   507  		return nil, err
   508  	}
   509  	return &KV{key, val}, nil
   510  }
   511  
   512  func encodeXRefNodeDefinition(prefix []byte, src *spb.VName, def *xspb.CrossReferences_NodeDefinition) (*KV, error) {
   513  	key, err := keys.Append(prefix, src, columnarXRefsNodeDefinitionGroup, def.Node)
   514  	if err != nil {
   515  		return nil, err
   516  	}
   517  	val, err := proto.Marshal(&xspb.CrossReferences_NodeDefinition{Location: def.Location})
   518  	if err != nil {
   519  		return nil, err
   520  	}
   521  	return &KV{key, val}, nil
   522  }
   523  
   524  // DecodeCrossReferencesEntry decodes a columnar CrossReferences entry.
   525  func DecodeCrossReferencesEntry(src *spb.VName, key string, val []byte) (*xspb.CrossReferences, error) {
   526  	kind := columnarXRefsIndexGroup
   527  	if key != "" {
   528  		var err error
   529  		key, err = keys.Parse(key, &kind)
   530  		if err != nil {
   531  			return nil, fmt.Errorf("invalid CrossReferences group kind: %v", err)
   532  		}
   533  	}
   534  	switch kind {
   535  	case columnarXRefsIndexGroup:
   536  		return decodeXRefIndex(src, key, val)
   537  	case columnarXRefsReferenceGroup:
   538  		return decodeXRefReference(src, key, val)
   539  	case columnarXRefsRelationGroup:
   540  		return decodeXRefRelation(src, key, val)
   541  	case columnarXRefsCallerGroup:
   542  		return decodeXRefCallerOrCallsite(src, key, val)
   543  	case columnarXRefsRelatedNodeGroup:
   544  		return decodeXRefRelatedNode(src, key, val)
   545  	case columnarXRefsNodeDefinitionGroup:
   546  		return decodeXRefNodeDefinition(src, key, val)
   547  	default:
   548  		return nil, fmt.Errorf("unknown group kind: %d", kind)
   549  	}
   550  }
   551  
   552  func decodeXRefIndex(src *spb.VName, key string, val []byte) (*xspb.CrossReferences, error) {
   553  	var idx xspb.CrossReferences_Index
   554  	if err := proto.Unmarshal(val, &idx); err != nil {
   555  		return nil, err
   556  	}
   557  	return &xspb.CrossReferences{
   558  		Source: src,
   559  		Entry:  &xspb.CrossReferences_Index_{&idx},
   560  	}, nil
   561  }
   562  
   563  func decodeXRefReference(src *spb.VName, key string, val []byte) (*xspb.CrossReferences, error) {
   564  	var (
   565  		genericKind string
   566  		kytheKind   int32
   567  	)
   568  	key, err := keys.Parse(key, &genericKind, &kytheKind)
   569  	if err != nil {
   570  		return nil, err
   571  	}
   572  	var ref xspb.CrossReferences_Reference
   573  	if err := proto.Unmarshal(val, &ref); err != nil {
   574  		return nil, err
   575  	}
   576  	if genericKind != "" {
   577  		ref.Kind = &xspb.CrossReferences_Reference_GenericKind{genericKind}
   578  	} else {
   579  		ref.Kind = &xspb.CrossReferences_Reference_KytheKind{scpb.EdgeKind(kytheKind)}
   580  	}
   581  	return &xspb.CrossReferences{
   582  		Source: src,
   583  		Entry:  &xspb.CrossReferences_Reference_{&ref},
   584  	}, nil
   585  }
   586  
   587  func decodeXRefRelation(src *spb.VName, key string, val []byte) (*xspb.CrossReferences, error) {
   588  	var (
   589  		genericKind string
   590  		kytheKind   int32
   591  		ordinal     int32
   592  		reverse     bool
   593  		node        spb.VName
   594  	)
   595  	key, err := keys.Parse(key, &genericKind, &kytheKind, &ordinal, &reverse, &node)
   596  	if err != nil {
   597  		return nil, err
   598  	}
   599  	var r xspb.CrossReferences_Relation
   600  	if err := proto.Unmarshal(val, &r); err != nil {
   601  		return nil, err
   602  	}
   603  	r.Reverse = reverse
   604  	r.Ordinal = ordinal
   605  	r.Node = &node
   606  	if genericKind != "" {
   607  		r.Kind = &xspb.CrossReferences_Relation_GenericKind{genericKind}
   608  	} else {
   609  		r.Kind = &xspb.CrossReferences_Relation_KytheKind{scpb.EdgeKind(kytheKind)}
   610  	}
   611  	return &xspb.CrossReferences{
   612  		Source: src,
   613  		Entry:  &xspb.CrossReferences_Relation_{&r},
   614  	}, nil
   615  }
   616  
   617  func decodeXRefCallerOrCallsite(src *spb.VName, key string, val []byte) (*xspb.CrossReferences, error) {
   618  	var caller spb.VName
   619  	key, err := keys.Parse(key, &caller)
   620  	if err != nil {
   621  		return nil, err
   622  	}
   623  
   624  	if key == "" {
   625  		var c xspb.CrossReferences_Caller
   626  		if err := proto.Unmarshal(val, &c); err != nil {
   627  			return nil, err
   628  		}
   629  		c.Caller = &caller
   630  		return &xspb.CrossReferences{
   631  			Source: src,
   632  			Entry:  &xspb.CrossReferences_Caller_{&c},
   633  		}, nil
   634  	}
   635  
   636  	var kind int32
   637  	key, err = keys.Parse(key, &kind)
   638  	if err != nil {
   639  		return nil, err
   640  	}
   641  
   642  	var c xspb.CrossReferences_Callsite
   643  	if err := proto.Unmarshal(val, &c); err != nil {
   644  		return nil, err
   645  	}
   646  	c.Caller = &caller
   647  	c.Kind = xspb.CrossReferences_Callsite_Kind(kind)
   648  	return &xspb.CrossReferences{
   649  		Source: src,
   650  		Entry:  &xspb.CrossReferences_Callsite_{&c},
   651  	}, nil
   652  }
   653  
   654  func decodeXRefRelatedNode(src *spb.VName, key string, val []byte) (*xspb.CrossReferences, error) {
   655  	var rn xspb.CrossReferences_RelatedNode
   656  	if err := proto.Unmarshal(val, &rn); err != nil {
   657  		return nil, err
   658  	}
   659  	return &xspb.CrossReferences{
   660  		Source: src,
   661  		Entry:  &xspb.CrossReferences_RelatedNode_{&rn},
   662  	}, nil
   663  }
   664  
   665  func decodeXRefNodeDefinition(src *spb.VName, key string, val []byte) (*xspb.CrossReferences, error) {
   666  	var node spb.VName
   667  	key, err := keys.Parse(key, &node)
   668  	if err != nil {
   669  		return nil, err
   670  	}
   671  	if len(key) != 0 {
   672  		return nil, fmt.Errorf("unexpected trailing key: %q", key)
   673  	}
   674  	var def xspb.CrossReferences_NodeDefinition
   675  	if err := proto.Unmarshal(val, &def); err != nil {
   676  		return nil, err
   677  	}
   678  	def.Node = &node
   679  	return &xspb.CrossReferences{
   680  		Source: src,
   681  		Entry:  &xspb.CrossReferences_NodeDefinition_{&def},
   682  	}, nil
   683  }