github.com/ipld/go-ipld-prime@v0.21.0/testutil/multibytenode.go (about) 1 package testutil 2 3 import ( 4 "io" 5 6 "github.com/ipld/go-ipld-prime/datamodel" 7 "github.com/ipld/go-ipld-prime/node/basicnode" 8 ) 9 10 var _ datamodel.Node = MultiByteNode{} 11 var _ datamodel.LargeBytesNode = (*MultiByteNode)(nil) 12 13 // MultiByteNode is a node that is a concatenation of multiple byte slices. 14 // It's not particularly sophisticated but lets us exercise LargeBytesNode in a 15 // non-trivial way. 16 // The novel behaviour of Read() and Seek() on the AsLargeBytes is similar to 17 // that which would be expected from a LBN ADL, such as UnixFS sharded files. 18 type MultiByteNode struct { 19 bytes [][]byte 20 } 21 22 func NewMultiByteNode(bytes ...[]byte) MultiByteNode { 23 return MultiByteNode{bytes: bytes} 24 } 25 26 func (mbn MultiByteNode) Kind() datamodel.Kind { 27 return datamodel.Kind_Bytes 28 } 29 30 func (mbn MultiByteNode) AsBytes() ([]byte, error) { 31 ret := make([]byte, 0, mbn.TotalLength()) 32 for _, b := range mbn.bytes { 33 ret = append(ret, b...) 34 } 35 return ret, nil 36 } 37 38 func (mbn MultiByteNode) TotalLength() int { 39 var size int 40 for _, b := range mbn.bytes { 41 size += len(b) 42 } 43 return size 44 } 45 46 func (mbn MultiByteNode) AsLargeBytes() (io.ReadSeeker, error) { 47 return &mbnReadSeeker{node: mbn}, nil 48 } 49 50 func (mbn MultiByteNode) AsBool() (bool, error) { 51 return false, datamodel.ErrWrongKind{TypeName: "bool", MethodName: "AsBool", AppropriateKind: datamodel.KindSet_JustBytes} 52 } 53 54 func (mbn MultiByteNode) AsInt() (int64, error) { 55 return 0, datamodel.ErrWrongKind{TypeName: "int", MethodName: "AsInt", AppropriateKind: datamodel.KindSet_JustBytes} 56 } 57 58 func (mbn MultiByteNode) AsFloat() (float64, error) { 59 return 0, datamodel.ErrWrongKind{TypeName: "float", MethodName: "AsFloat", AppropriateKind: datamodel.KindSet_JustBytes} 60 } 61 62 func (mbn MultiByteNode) AsString() (string, error) { 63 return "", datamodel.ErrWrongKind{TypeName: "string", MethodName: "AsString", AppropriateKind: datamodel.KindSet_JustBytes} 64 } 65 66 func (mbn MultiByteNode) AsLink() (datamodel.Link, error) { 67 return nil, datamodel.ErrWrongKind{TypeName: "link", MethodName: "AsLink", AppropriateKind: datamodel.KindSet_JustBytes} 68 } 69 70 func (mbn MultiByteNode) AsNode() (datamodel.Node, error) { 71 return nil, nil 72 } 73 74 func (mbn MultiByteNode) Size() int { 75 return 0 76 } 77 78 func (mbn MultiByteNode) IsAbsent() bool { 79 return false 80 } 81 82 func (mbn MultiByteNode) IsNull() bool { 83 return false 84 } 85 86 func (mbn MultiByteNode) Length() int64 { 87 return 0 88 } 89 90 func (mbn MultiByteNode) ListIterator() datamodel.ListIterator { 91 return nil 92 } 93 94 func (mbn MultiByteNode) MapIterator() datamodel.MapIterator { 95 return nil 96 } 97 98 func (mbn MultiByteNode) LookupByIndex(idx int64) (datamodel.Node, error) { 99 return nil, datamodel.ErrWrongKind{} 100 } 101 102 func (mbn MultiByteNode) LookupByString(key string) (datamodel.Node, error) { 103 return nil, datamodel.ErrWrongKind{} 104 } 105 106 func (mbn MultiByteNode) LookupByNode(key datamodel.Node) (datamodel.Node, error) { 107 return nil, datamodel.ErrWrongKind{} 108 } 109 110 func (mbn MultiByteNode) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) { 111 return nil, datamodel.ErrWrongKind{} 112 } 113 114 func (mbn MultiByteNode) Prototype() datamodel.NodePrototype { 115 return basicnode.Prototype.Bytes // not really ... but it'll do for this test 116 } 117 118 type mbnReadSeeker struct { 119 node MultiByteNode 120 offset int 121 } 122 123 func (mbnrs *mbnReadSeeker) Read(p []byte) (int, error) { 124 var acc int 125 for _, byts := range mbnrs.node.bytes { 126 if mbnrs.offset-acc >= len(byts) { 127 acc += len(byts) 128 continue 129 } 130 n := copy(p, byts[mbnrs.offset-acc:]) 131 mbnrs.offset += n 132 return n, nil 133 } 134 return 0, io.EOF 135 } 136 137 func (mbnrs *mbnReadSeeker) Seek(offset int64, whence int) (int64, error) { 138 switch whence { 139 case io.SeekStart: 140 mbnrs.offset = int(offset) 141 case io.SeekCurrent: 142 mbnrs.offset += int(offset) 143 case io.SeekEnd: 144 mbnrs.offset = mbnrs.node.TotalLength() + int(offset) 145 } 146 return int64(mbnrs.offset), nil 147 }