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 }