github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/types/ref.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // This file incorporates work covered by the following copyright and 16 // permission notice: 17 // 18 // Copyright 2016 Attic Labs, Inc. All rights reserved. 19 // Licensed under the Apache License, version 2.0: 20 // http://www.apache.org/licenses/LICENSE-2.0 21 22 package types 23 24 import ( 25 "bytes" 26 "context" 27 28 "github.com/dolthub/dolt/go/store/hash" 29 ) 30 31 type Ref struct { 32 valueImpl 33 } 34 35 type refPart uint32 36 37 const ( 38 refPartKind refPart = iota 39 refPartTargetHash 40 refPartTargetType 41 refPartHeight 42 refPartEnd 43 ) 44 45 func NewRef(v Value, nbf *NomsBinFormat) (Ref, error) { 46 h, err := v.Hash(nbf) 47 48 if err != nil { 49 return Ref{}, err 50 } 51 52 mch, err := maxChunkHeight(nbf, v) 53 54 if err != nil { 55 return Ref{}, err 56 } 57 58 t, err := TypeOf(v) 59 60 if err != nil { 61 return Ref{}, err 62 } 63 64 return constructRef(nbf, h, t, mch+1) 65 } 66 67 // ToRefOfValue returns a new Ref that points to the same target as |r|, but 68 // with the type 'Ref<Value>'. 69 func ToRefOfValue(r Ref, nbf *NomsBinFormat) (Ref, error) { 70 return constructRef(nbf, r.TargetHash(), PrimitiveTypeMap[ValueKind], r.Height()) 71 } 72 73 func constructRef(nbf *NomsBinFormat, targetHash hash.Hash, targetType *Type, height uint64) (Ref, error) { 74 w := newBinaryNomsWriter() 75 76 offsets := make([]uint32, refPartEnd) 77 offsets[refPartKind] = w.offset 78 err := RefKind.writeTo(&w, nbf) 79 80 if err != nil { 81 return Ref{}, err 82 } 83 84 offsets[refPartTargetHash] = w.offset 85 w.writeHash(targetHash) 86 offsets[refPartTargetType] = w.offset 87 err = targetType.writeToAsType(&w, map[string]*Type{}, nbf) 88 89 if err != nil { 90 return Ref{}, err 91 } 92 93 offsets[refPartHeight] = w.offset 94 w.writeCount(height) 95 96 return Ref{valueImpl{nil, nbf, w.data(), offsets}}, nil 97 } 98 99 // readRef reads the data provided by a reader and moves the reader forward. 100 func readRef(nbf *NomsBinFormat, dec *typedBinaryNomsReader) (Ref, error) { 101 start := dec.pos() 102 offsets, err := skipRef(dec) 103 104 if err != nil { 105 return Ref{}, err 106 } 107 108 end := dec.pos() 109 return Ref{valueImpl{nil, nbf, dec.byteSlice(start, end), offsets}}, nil 110 } 111 112 // skipRef moves the reader forward, past the data representing the Ref, and returns the offsets of the component parts. 113 func skipRef(dec *typedBinaryNomsReader) ([]uint32, error) { 114 offsets := make([]uint32, refPartEnd) 115 offsets[refPartKind] = dec.pos() 116 dec.skipKind() 117 offsets[refPartTargetHash] = dec.pos() 118 dec.skipHash() // targetHash 119 offsets[refPartTargetType] = dec.pos() 120 err := dec.skipType() // targetType 121 122 if err != nil { 123 return nil, err 124 } 125 126 offsets[refPartHeight] = dec.pos() 127 dec.skipCount() // height 128 return offsets, nil 129 } 130 131 func maxChunkHeight(nbf *NomsBinFormat, v Value) (max uint64, err error) { 132 err = v.WalkRefs(nbf, func(r Ref) error { 133 if height := r.Height(); height > max { 134 max = height 135 } 136 137 return nil 138 }) 139 140 if err != nil { 141 return 0, err 142 } 143 144 return max, nil 145 } 146 147 func (r Ref) offsetAtPart(part refPart) uint32 { 148 return r.offsets[part] - r.offsets[refPartKind] 149 } 150 151 func (r Ref) decoderAtPart(part refPart) valueDecoder { 152 offset := r.offsetAtPart(part) 153 return newValueDecoder(r.buff[offset:], nil) 154 } 155 156 func (r Ref) Format() *NomsBinFormat { 157 return r.format() 158 } 159 160 func (r Ref) TargetHash() hash.Hash { 161 dec := r.decoderAtPart(refPartTargetHash) 162 return dec.readHash() 163 } 164 165 func (r Ref) Height() uint64 { 166 dec := r.decoderAtPart(refPartHeight) 167 return dec.readCount() 168 } 169 170 func (r Ref) TargetValue(ctx context.Context, vr ValueReader) (Value, error) { 171 return vr.ReadValue(ctx, r.TargetHash()) 172 } 173 174 func (r Ref) TargetType() (*Type, error) { 175 dec := r.decoderAtPart(refPartTargetType) 176 return dec.readType() 177 } 178 179 // Value interface 180 func (r Ref) isPrimitive() bool { 181 return false 182 } 183 184 func (r Ref) Value(ctx context.Context) (Value, error) { 185 return r, nil 186 } 187 188 func (r Ref) WalkValues(ctx context.Context, cb ValueCallback) error { 189 return nil 190 } 191 192 func (r Ref) typeOf() (*Type, error) { 193 t, err := r.TargetType() 194 195 if err != nil { 196 return nil, err 197 } 198 199 return makeCompoundType(RefKind, t) 200 } 201 202 func (r Ref) isSameTargetType(other Ref) bool { 203 targetTypeBytes := r.buff[r.offsetAtPart(refPartTargetType):r.offsetAtPart(refPartHeight)] 204 otherTargetTypeBytes := other.buff[other.offsetAtPart(refPartTargetType):other.offsetAtPart(refPartHeight)] 205 return bytes.Equal(targetTypeBytes, otherTargetTypeBytes) 206 } 207 208 func (r Ref) readFrom(nbf *NomsBinFormat, b *binaryNomsReader) (Value, error) { 209 panic("unreachable") 210 } 211 212 func (r Ref) skip(nbf *NomsBinFormat, b *binaryNomsReader) { 213 panic("unreachable") 214 } 215 216 func (r Ref) String() string { 217 panic("unreachable") 218 } 219 220 func (r Ref) HumanReadableString() string { 221 panic("unreachable") 222 }