Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(497)

Side by Side Diff: service/datastore/serialize/serialize.go

Issue 2569923002: Split Buffer into WriteBuffer/ReadBuffer. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package serialize 5 package serialize
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "errors" 9 "errors"
10 "fmt" 10 "fmt"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 44
45 // With- and WithoutContext indicate if the serialization method should include 45 // With- and WithoutContext indicate if the serialization method should include
46 // context for Keys. See KeyContext for more information. 46 // context for Keys. See KeyContext for more information.
47 const ( 47 const (
48 WithContext KeyContext = true 48 WithContext KeyContext = true
49 WithoutContext = false 49 WithoutContext = false
50 ) 50 )
51 51
52 // WriteKey encodes a key to the buffer. If context is WithContext, then this 52 // WriteKey encodes a key to the buffer. If context is WithContext, then this
53 // encoded value will include the appid and namespace of the key. 53 // encoded value will include the appid and namespace of the key.
54 func WriteKey(buf Buffer, context KeyContext, k *ds.Key) (err error) { 54 func WriteKey(buf WriteBuffer, context KeyContext, k *ds.Key) (err error) {
55 // [appid ++ namespace]? ++ [1 ++ token]* ++ NULL 55 // [appid ++ namespace]? ++ [1 ++ token]* ++ NULL
56 defer recoverTo(&err) 56 defer recoverTo(&err)
57 appid, namespace, toks := k.Split() 57 appid, namespace, toks := k.Split()
58 if context == WithContext { 58 if context == WithContext {
59 panicIf(buf.WriteByte(1)) 59 panicIf(buf.WriteByte(1))
60 _, e := cmpbin.WriteString(buf, appid) 60 _, e := cmpbin.WriteString(buf, appid)
61 panicIf(e) 61 panicIf(e)
62 _, e = cmpbin.WriteString(buf, namespace) 62 _, e = cmpbin.WriteString(buf, namespace)
63 panicIf(e) 63 panicIf(e)
64 } else { 64 } else {
65 panicIf(buf.WriteByte(0)) 65 panicIf(buf.WriteByte(0))
66 } 66 }
67 for _, tok := range toks { 67 for _, tok := range toks {
68 panicIf(buf.WriteByte(1)) 68 panicIf(buf.WriteByte(1))
69 panicIf(WriteKeyTok(buf, tok)) 69 panicIf(WriteKeyTok(buf, tok))
70 } 70 }
71 return buf.WriteByte(0) 71 return buf.WriteByte(0)
72 } 72 }
73 73
74 // ReadKey deserializes a key from the buffer. The value of context must match 74 // ReadKey deserializes a key from the buffer. The value of context must match
75 // the value of context that was passed to WriteKey when the key was encoded. 75 // the value of context that was passed to WriteKey when the key was encoded.
76 // If context == WithoutContext, then the appid and namespace parameters are 76 // If context == WithoutContext, then the appid and namespace parameters are
77 // used in the decoded Key. Otherwise they're ignored. 77 // used in the decoded Key. Otherwise they're ignored.
78 func ReadKey(buf Buffer, context KeyContext, inKC ds.KeyContext) (ret *ds.Key, e rr error) { 78 func ReadKey(buf ReadBuffer, context KeyContext, inKC ds.KeyContext) (ret *ds.Ke y, err error) {
79 defer recoverTo(&err) 79 defer recoverTo(&err)
80 actualCtx, e := buf.ReadByte() 80 actualCtx, e := buf.ReadByte()
81 panicIf(e) 81 panicIf(e)
82 82
83 var kc ds.KeyContext 83 var kc ds.KeyContext
84 if actualCtx == 1 { 84 if actualCtx == 1 {
85 kc.AppID, _, e = cmpbin.ReadString(buf) 85 kc.AppID, _, e = cmpbin.ReadString(buf)
86 panicIf(e) 86 panicIf(e)
87 kc.Namespace, _, e = cmpbin.ReadString(buf) 87 kc.Namespace, _, e = cmpbin.ReadString(buf)
88 panicIf(e) 88 panicIf(e)
(...skipping 25 matching lines...) Expand all
114 panicIf(e) 114 panicIf(e)
115 115
116 toks = append(toks, tok) 116 toks = append(toks, tok)
117 } 117 }
118 118
119 return kc.NewKeyToks(toks), nil 119 return kc.NewKeyToks(toks), nil
120 } 120 }
121 121
122 // WriteKeyTok writes a KeyTok to the buffer. You usually want WriteKey 122 // WriteKeyTok writes a KeyTok to the buffer. You usually want WriteKey
123 // instead of this. 123 // instead of this.
124 func WriteKeyTok(buf Buffer, tok ds.KeyTok) (err error) { 124 func WriteKeyTok(buf WriteBuffer, tok ds.KeyTok) (err error) {
125 // tok.kind ++ typ ++ [tok.stringID || tok.intID] 125 // tok.kind ++ typ ++ [tok.stringID || tok.intID]
126 defer recoverTo(&err) 126 defer recoverTo(&err)
127 _, e := cmpbin.WriteString(buf, tok.Kind) 127 _, e := cmpbin.WriteString(buf, tok.Kind)
128 panicIf(e) 128 panicIf(e)
129 if tok.StringID != "" { 129 if tok.StringID != "" {
130 panicIf(buf.WriteByte(byte(ds.PTString))) 130 panicIf(buf.WriteByte(byte(ds.PTString)))
131 _, e := cmpbin.WriteString(buf, tok.StringID) 131 _, e := cmpbin.WriteString(buf, tok.StringID)
132 panicIf(e) 132 panicIf(e)
133 } else { 133 } else {
134 panicIf(buf.WriteByte(byte(ds.PTInt))) 134 panicIf(buf.WriteByte(byte(ds.PTInt)))
135 _, e := cmpbin.WriteInt(buf, tok.IntID) 135 _, e := cmpbin.WriteInt(buf, tok.IntID)
136 panicIf(e) 136 panicIf(e)
137 } 137 }
138 return nil 138 return nil
139 } 139 }
140 140
141 // ReadKeyTok reads a KeyTok from the buffer. You usually want ReadKey 141 // ReadKeyTok reads a KeyTok from the buffer. You usually want ReadKey
142 // instead of this. 142 // instead of this.
143 func ReadKeyTok(buf Buffer) (ret ds.KeyTok, err error) { 143 func ReadKeyTok(buf ReadBuffer) (ret ds.KeyTok, err error) {
144 defer recoverTo(&err) 144 defer recoverTo(&err)
145 e := error(nil) 145 e := error(nil)
146 ret.Kind, _, e = cmpbin.ReadString(buf) 146 ret.Kind, _, e = cmpbin.ReadString(buf)
147 panicIf(e) 147 panicIf(e)
148 148
149 typ, e := buf.ReadByte() 149 typ, e := buf.ReadByte()
150 panicIf(e) 150 panicIf(e)
151 151
152 switch ds.PropertyType(typ) { 152 switch ds.PropertyType(typ) {
153 case ds.PTString: 153 case ds.PTString:
154 ret.StringID, _, err = cmpbin.ReadString(buf) 154 ret.StringID, _, err = cmpbin.ReadString(buf)
155 case ds.PTInt: 155 case ds.PTInt:
156 ret.IntID, _, err = cmpbin.ReadInt(buf) 156 ret.IntID, _, err = cmpbin.ReadInt(buf)
157 if err == nil && ret.IntID <= 0 { 157 if err == nil && ret.IntID <= 0 {
158 err = errors.New("helper: decoded key with empty stringI D and zero/negative intID") 158 err = errors.New("helper: decoded key with empty stringI D and zero/negative intID")
159 } 159 }
160 default: 160 default:
161 err = fmt.Errorf("helper: invalid type %s", ds.PropertyType(typ) ) 161 err = fmt.Errorf("helper: invalid type %s", ds.PropertyType(typ) )
162 } 162 }
163 return 163 return
164 } 164 }
165 165
166 // WriteGeoPoint writes a GeoPoint to the buffer. 166 // WriteGeoPoint writes a GeoPoint to the buffer.
167 func WriteGeoPoint(buf Buffer, gp ds.GeoPoint) (err error) { 167 func WriteGeoPoint(buf WriteBuffer, gp ds.GeoPoint) (err error) {
168 defer recoverTo(&err) 168 defer recoverTo(&err)
169 _, e := cmpbin.WriteFloat64(buf, gp.Lat) 169 _, e := cmpbin.WriteFloat64(buf, gp.Lat)
170 panicIf(e) 170 panicIf(e)
171 _, e = cmpbin.WriteFloat64(buf, gp.Lng) 171 _, e = cmpbin.WriteFloat64(buf, gp.Lng)
172 return e 172 return e
173 } 173 }
174 174
175 // ReadGeoPoint reads a GeoPoint from the buffer. 175 // ReadGeoPoint reads a GeoPoint from the buffer.
176 func ReadGeoPoint(buf Buffer) (gp ds.GeoPoint, err error) { 176 func ReadGeoPoint(buf ReadBuffer) (gp ds.GeoPoint, err error) {
177 defer recoverTo(&err) 177 defer recoverTo(&err)
178 e := error(nil) 178 e := error(nil)
179 gp.Lat, _, e = cmpbin.ReadFloat64(buf) 179 gp.Lat, _, e = cmpbin.ReadFloat64(buf)
180 panicIf(e) 180 panicIf(e)
181 181
182 gp.Lng, _, e = cmpbin.ReadFloat64(buf) 182 gp.Lng, _, e = cmpbin.ReadFloat64(buf)
183 panicIf(e) 183 panicIf(e)
184 184
185 if !gp.Valid() { 185 if !gp.Valid() {
186 err = fmt.Errorf("helper: decoded invalid GeoPoint: %v", gp) 186 err = fmt.Errorf("helper: decoded invalid GeoPoint: %v", gp)
187 } 187 }
188 return 188 return
189 } 189 }
190 190
191 // WriteTime writes a time.Time to the buffer. 191 // WriteTime writes a time.Time to the buffer.
192 // 192 //
193 // The supplied time is rounded via datastore.RoundTime and written as a 193 // The supplied time is rounded via datastore.RoundTime and written as a
194 // microseconds-since-epoch integer to comform to datastore storage standards. 194 // microseconds-since-epoch integer to comform to datastore storage standards.
195 func WriteTime(buf Buffer, t time.Time) error { 195 func WriteTime(buf WriteBuffer, t time.Time) error {
196 name, off := t.Zone() 196 name, off := t.Zone()
197 if name != "UTC" || off != 0 { 197 if name != "UTC" || off != 0 {
198 panic(fmt.Errorf("helper: UTC OR DEATH: %s", t)) 198 panic(fmt.Errorf("helper: UTC OR DEATH: %s", t))
199 } 199 }
200 200
201 _, err := cmpbin.WriteInt(buf, ds.TimeToInt(t)) 201 _, err := cmpbin.WriteInt(buf, ds.TimeToInt(t))
202 return err 202 return err
203 } 203 }
204 204
205 // ReadTime reads a time.Time from the buffer. 205 // ReadTime reads a time.Time from the buffer.
206 func ReadTime(buf Buffer) (time.Time, error) { 206 func ReadTime(buf ReadBuffer) (time.Time, error) {
207 v, _, err := cmpbin.ReadInt(buf) 207 v, _, err := cmpbin.ReadInt(buf)
208 if err != nil { 208 if err != nil {
209 return time.Time{}, err 209 return time.Time{}, err
210 } 210 }
211 return ds.IntToTime(v), nil 211 return ds.IntToTime(v), nil
212 } 212 }
213 213
214 // WriteProperty writes a Property to the buffer. `context` behaves the same 214 // WriteProperty writes a Property to the buffer. `context` behaves the same
215 // way that it does for WriteKey, but only has an effect if `p` contains a 215 // way that it does for WriteKey, but only has an effect if `p` contains a
216 // Key as its IndexValue. 216 // Key as its IndexValue.
217 func WriteProperty(buf Buffer, context KeyContext, p ds.Property) error { 217 func WriteProperty(buf WriteBuffer, context KeyContext, p ds.Property) error {
218 return writePropertyImpl(buf, context, &p, false) 218 return writePropertyImpl(buf, context, &p, false)
219 } 219 }
220 220
221 // WriteIndexProperty writes a Property to the buffer as its native index type. 221 // WriteIndexProperty writes a Property to the buffer as its native index type.
222 // `context` behaves the same way that it does for WriteKey, but only has an 222 // `context` behaves the same way that it does for WriteKey, but only has an
223 // effect if `p` contains a Key as its IndexValue. 223 // effect if `p` contains a Key as its IndexValue.
224 func WriteIndexProperty(buf Buffer, context KeyContext, p ds.Property) error { 224 func WriteIndexProperty(buf WriteBuffer, context KeyContext, p ds.Property) erro r {
225 return writePropertyImpl(buf, context, &p, true) 225 return writePropertyImpl(buf, context, &p, true)
226 } 226 }
227 227
228 // writePropertyImpl is an implementation of WriteProperty and 228 // writePropertyImpl is an implementation of WriteProperty and
229 // WriteIndexProperty. 229 // WriteIndexProperty.
230 func writePropertyImpl(buf Buffer, context KeyContext, p *ds.Property, index boo l) (err error) { 230 func writePropertyImpl(buf WriteBuffer, context KeyContext, p *ds.Property, inde x bool) (err error) {
231 defer recoverTo(&err) 231 defer recoverTo(&err)
232 232
233 it, v := p.IndexTypeAndValue() 233 it, v := p.IndexTypeAndValue()
234 if !index { 234 if !index {
235 it = p.Type() 235 it = p.Type()
236 } 236 }
237 typb := byte(it) 237 typb := byte(it)
238 if p.IndexSetting() != ds.NoIndex { 238 if p.IndexSetting() != ds.NoIndex {
239 typb |= 0x80 239 typb |= 0x80
240 } 240 }
241 panicIf(buf.WriteByte(typb)) 241 panicIf(buf.WriteByte(typb))
242 242
243 err = writeIndexValue(buf, context, v) 243 err = writeIndexValue(buf, context, v)
244 return 244 return
245 } 245 }
246 246
247 // writeIndexValue writes the index value of v to buf. 247 // writeIndexValue writes the index value of v to buf.
248 // 248 //
249 // v may be one of the return types from ds.Property's GetIndexTypeAndValue 249 // v may be one of the return types from ds.Property's GetIndexTypeAndValue
250 // method. 250 // method.
251 func writeIndexValue(buf Buffer, context KeyContext, v interface{}) (err error) { 251 func writeIndexValue(buf WriteBuffer, context KeyContext, v interface{}) (err er ror) {
252 switch t := v.(type) { 252 switch t := v.(type) {
253 case nil: 253 case nil:
254 case bool: 254 case bool:
255 b := byte(0) 255 b := byte(0)
256 if t { 256 if t {
257 b = 1 257 b = 1
258 } 258 }
259 err = buf.WriteByte(b) 259 err = buf.WriteByte(b)
260 case int64: 260 case int64:
261 _, err = cmpbin.WriteInt(buf, t) 261 _, err = cmpbin.WriteInt(buf, t)
(...skipping 10 matching lines...) Expand all
272 272
273 default: 273 default:
274 err = fmt.Errorf("unsupported type: %T", t) 274 err = fmt.Errorf("unsupported type: %T", t)
275 } 275 }
276 return 276 return
277 } 277 }
278 278
279 // ReadProperty reads a Property from the buffer. `context` and `kc` behave the 279 // ReadProperty reads a Property from the buffer. `context` and `kc` behave the
280 // same way they do for ReadKey, but only have an effect if the decoded property 280 // same way they do for ReadKey, but only have an effect if the decoded property
281 // has a Key value. 281 // has a Key value.
282 func ReadProperty(buf Buffer, context KeyContext, kc ds.KeyContext) (p ds.Proper ty, err error) { 282 func ReadProperty(buf ReadBuffer, context KeyContext, kc ds.KeyContext) (p ds.Pr operty, err error) {
283 val := interface{}(nil) 283 val := interface{}(nil)
284 b, err := buf.ReadByte() 284 b, err := buf.ReadByte()
285 if err != nil { 285 if err != nil {
286 return 286 return
287 } 287 }
288 is := ds.ShouldIndex 288 is := ds.ShouldIndex
289 if (b & 0x80) == 0 { 289 if (b & 0x80) == 0 {
290 is = ds.NoIndex 290 is = ds.NoIndex
291 } 291 }
292 switch ds.PropertyType(b & 0x7f) { 292 switch ds.PropertyType(b & 0x7f) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 } 324 }
325 325
326 // WritePropertyMap writes an entire PropertyMap to the buffer. `context` 326 // WritePropertyMap writes an entire PropertyMap to the buffer. `context`
327 // behaves the same way that it does for WriteKey. 327 // behaves the same way that it does for WriteKey.
328 // 328 //
329 // If WritePropertyMapDeterministic is true, then the rows will be sorted by 329 // If WritePropertyMapDeterministic is true, then the rows will be sorted by
330 // property name before they're serialized to buf (mostly useful for testing, 330 // property name before they're serialized to buf (mostly useful for testing,
331 // but also potentially useful if you need to make a hash of the property data). 331 // but also potentially useful if you need to make a hash of the property data).
332 // 332 //
333 // Write skips metadata keys. 333 // Write skips metadata keys.
334 func WritePropertyMap(buf Buffer, context KeyContext, pm ds.PropertyMap) (err er ror) { 334 func WritePropertyMap(buf WriteBuffer, context KeyContext, pm ds.PropertyMap) (e rr error) {
335 defer recoverTo(&err) 335 defer recoverTo(&err)
336 rows := make(sort.StringSlice, 0, len(pm)) 336 rows := make(sort.StringSlice, 0, len(pm))
337 tmpBuf := &bytes.Buffer{} 337 tmpBuf := &bytes.Buffer{}
338 pm, _ = pm.Save(false) 338 pm, _ = pm.Save(false)
339 for name, pdata := range pm { 339 for name, pdata := range pm {
340 tmpBuf.Reset() 340 tmpBuf.Reset()
341 _, e := cmpbin.WriteString(tmpBuf, name) 341 _, e := cmpbin.WriteString(tmpBuf, name)
342 panicIf(e) 342 panicIf(e)
343 343
344 switch t := pdata.(type) { 344 switch t := pdata.(type) {
(...skipping 23 matching lines...) Expand all
368 panicIf(e) 368 panicIf(e)
369 for _, r := range rows { 369 for _, r := range rows {
370 _, e := buf.WriteString(r) 370 _, e := buf.WriteString(r)
371 panicIf(e) 371 panicIf(e)
372 } 372 }
373 return 373 return
374 } 374 }
375 375
376 // ReadPropertyMap reads a PropertyMap from the buffer. `context` and 376 // ReadPropertyMap reads a PropertyMap from the buffer. `context` and
377 // friends behave the same way that they do for ReadKey. 377 // friends behave the same way that they do for ReadKey.
378 func ReadPropertyMap(buf Buffer, context KeyContext, kc ds.KeyContext) (pm ds.Pr opertyMap, err error) { 378 func ReadPropertyMap(buf ReadBuffer, context KeyContext, kc ds.KeyContext) (pm d s.PropertyMap, err error) {
379 defer recoverTo(&err) 379 defer recoverTo(&err)
380 380
381 numRows := uint64(0) 381 numRows := uint64(0)
382 numRows, _, e := cmpbin.ReadUint(buf) 382 numRows, _, e := cmpbin.ReadUint(buf)
383 panicIf(e) 383 panicIf(e)
384 if numRows > ReadPropertyMapReasonableLimit { 384 if numRows > ReadPropertyMapReasonableLimit {
385 err = fmt.Errorf("helper: tried to decode map with huge number o f rows %d", numRows) 385 err = fmt.Errorf("helper: tried to decode map with huge number o f rows %d", numRows)
386 return 386 return
387 } 387 }
388 388
(...skipping 24 matching lines...) Expand all
413 panicIf(err) 413 panicIf(err)
414 props = append(props, prop) 414 props = append(props, prop)
415 } 415 }
416 pm[name] = props 416 pm[name] = props
417 } 417 }
418 } 418 }
419 return 419 return
420 } 420 }
421 421
422 // WriteIndexColumn writes an IndexColumn to the buffer. 422 // WriteIndexColumn writes an IndexColumn to the buffer.
423 func WriteIndexColumn(buf Buffer, c ds.IndexColumn) (err error) { 423 func WriteIndexColumn(buf WriteBuffer, c ds.IndexColumn) (err error) {
424 defer recoverTo(&err) 424 defer recoverTo(&err)
425 425
426 if !c.Descending { 426 if !c.Descending {
427 panicIf(buf.WriteByte(0)) 427 panicIf(buf.WriteByte(0))
428 } else { 428 } else {
429 panicIf(buf.WriteByte(1)) 429 panicIf(buf.WriteByte(1))
430 } 430 }
431 _, err = cmpbin.WriteString(buf, c.Property) 431 _, err = cmpbin.WriteString(buf, c.Property)
432 return 432 return
433 } 433 }
434 434
435 // ReadIndexColumn reads an IndexColumn from the buffer. 435 // ReadIndexColumn reads an IndexColumn from the buffer.
436 func ReadIndexColumn(buf Buffer) (c ds.IndexColumn, err error) { 436 func ReadIndexColumn(buf ReadBuffer) (c ds.IndexColumn, err error) {
437 defer recoverTo(&err) 437 defer recoverTo(&err)
438 438
439 dir, err := buf.ReadByte() 439 dir, err := buf.ReadByte()
440 panicIf(err) 440 panicIf(err)
441 441
442 c.Descending = dir != 0 442 c.Descending = dir != 0
443 c.Property, _, err = cmpbin.ReadString(buf) 443 c.Property, _, err = cmpbin.ReadString(buf)
444 return 444 return
445 } 445 }
446 446
447 // WriteIndexDefinition writes an IndexDefinition to the buffer 447 // WriteIndexDefinition writes an IndexDefinition to the buffer
448 func WriteIndexDefinition(buf Buffer, i ds.IndexDefinition) (err error) { 448 func WriteIndexDefinition(buf WriteBuffer, i ds.IndexDefinition) (err error) {
449 defer recoverTo(&err) 449 defer recoverTo(&err)
450 450
451 _, err = cmpbin.WriteString(buf, i.Kind) 451 _, err = cmpbin.WriteString(buf, i.Kind)
452 panicIf(err) 452 panicIf(err)
453 if !i.Ancestor { 453 if !i.Ancestor {
454 panicIf(buf.WriteByte(0)) 454 panicIf(buf.WriteByte(0))
455 } else { 455 } else {
456 panicIf(buf.WriteByte(1)) 456 panicIf(buf.WriteByte(1))
457 } 457 }
458 for _, sb := range i.SortBy { 458 for _, sb := range i.SortBy {
459 panicIf(buf.WriteByte(1)) 459 panicIf(buf.WriteByte(1))
460 panicIf(WriteIndexColumn(buf, sb)) 460 panicIf(WriteIndexColumn(buf, sb))
461 } 461 }
462 return buf.WriteByte(0) 462 return buf.WriteByte(0)
463 } 463 }
464 464
465 // ReadIndexDefinition reads an IndexDefinition from the buffer. 465 // ReadIndexDefinition reads an IndexDefinition from the buffer.
466 func ReadIndexDefinition(buf Buffer) (i ds.IndexDefinition, err error) { 466 func ReadIndexDefinition(buf ReadBuffer) (i ds.IndexDefinition, err error) {
467 defer recoverTo(&err) 467 defer recoverTo(&err)
468 468
469 i.Kind, _, err = cmpbin.ReadString(buf) 469 i.Kind, _, err = cmpbin.ReadString(buf)
470 panicIf(err) 470 panicIf(err)
471 471
472 anc, err := buf.ReadByte() 472 anc, err := buf.ReadByte()
473 panicIf(err) 473 panicIf(err)
474 474
475 i.Ancestor = anc == 1 475 i.Ancestor = anc == 1
476 476
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 } 634 }
635 } 635 }
636 636
637 func recoverTo(err *error) { 637 func recoverTo(err *error) {
638 if r := recover(); r != nil { 638 if r := recover(); r != nil {
639 if rerr := r.(parseError); rerr != nil { 639 if rerr := r.(parseError); rerr != nil {
640 *err = error(rerr) 640 *err = error(rerr)
641 } 641 }
642 } 642 }
643 } 643 }
OLDNEW
« no previous file with comments | « service/datastore/serialize/invertible.go ('k') | service/datastore/serialize/serialize_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698