github.com/ipld/go-ipld-prime@v0.21.0/linking/cid/cidLink.go (about)

     1  package cidlink
     2  
     3  import (
     4  	"fmt"
     5  
     6  	cid "github.com/ipfs/go-cid"
     7  	"github.com/ipld/go-ipld-prime/datamodel"
     8  	multihash "github.com/multiformats/go-multihash"
     9  )
    10  
    11  var (
    12  	_ datamodel.Link          = Link{}
    13  	_ datamodel.LinkPrototype = LinkPrototype{}
    14  )
    15  
    16  // Link implements the datamodel.Link interface using a CID.
    17  // See https://github.com/ipfs/go-cid for more information about CIDs.
    18  //
    19  // When using this value, typically you'll use it as `Link`, and not `*Link`.
    20  // This includes when handling the value as an `datamodel.Link` interface -- the non-pointer form is typically preferable.
    21  // This is because the datamodel.Link inteface is often desirable to be able to use as a golang map key,
    22  // and in that context, pointers would not result in the desired behavior.
    23  type Link struct {
    24  	cid.Cid
    25  }
    26  
    27  func (lnk Link) Prototype() datamodel.LinkPrototype {
    28  	return LinkPrototype{lnk.Cid.Prefix()}
    29  }
    30  func (lnk Link) String() string {
    31  	return lnk.Cid.String()
    32  }
    33  func (lnk Link) Binary() string {
    34  	return lnk.Cid.KeyString()
    35  }
    36  
    37  type LinkPrototype struct {
    38  	cid.Prefix
    39  }
    40  
    41  func (lp LinkPrototype) BuildLink(hashsum []byte) datamodel.Link {
    42  	// Does this method body look surprisingly complex?  I agree.
    43  	//  We actually have to do all this work.  The go-cid package doesn't expose a constructor that just lets us directly set the bytes and the prefix numbers next to each other.
    44  	//  No, `cid.Prefix.Sum` is not the method you are looking for: that expects the whole data body.
    45  	//  Most of the logic here is the same as the body of `cid.Prefix.Sum`; we just couldn't get at the relevant parts without copypasta.
    46  	//  There is also some logic that's sort of folded in from the go-multihash module.  This is really a mess.
    47  	//  The go-cid package needs review.  So does go-multihash.  Their responsibilies are not well compartmentalized and they don't play well with other stdlib golang interfaces.
    48  	p := lp.Prefix
    49  
    50  	length := p.MhLength
    51  	if p.MhType == multihash.IDENTITY {
    52  		length = -1
    53  	}
    54  	if p.Version == 0 && (p.MhType != multihash.SHA2_256 ||
    55  		(p.MhLength != 32 && p.MhLength != -1)) {
    56  		panic(fmt.Errorf("invalid cid v0 prefix"))
    57  	}
    58  
    59  	if length != -1 {
    60  		hashsum = hashsum[:p.MhLength]
    61  	}
    62  
    63  	mh, err := multihash.Encode(hashsum, p.MhType)
    64  	if err != nil {
    65  		panic(err) // No longer possible, but multihash still returns an error for legacy reasons.
    66  	}
    67  
    68  	switch lp.Prefix.Version {
    69  	case 0:
    70  		return Link{cid.NewCidV0(mh)}
    71  	case 1:
    72  		return Link{cid.NewCidV1(p.Codec, mh)}
    73  	default:
    74  		panic(fmt.Errorf("invalid cid version"))
    75  	}
    76  }