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

Unified Diff: helper/serialize.go

Issue 1243323002: Refactor a bit. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: fix golint Created 5 years, 5 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « helper/internal/protos/datastore/datastore_v3.pb.go ('k') | helper/serialize_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: helper/serialize.go
diff --git a/helper/serialize.go b/helper/serialize.go
deleted file mode 100644
index 41175257af361868c3e969d760d1fc353164be23..0000000000000000000000000000000000000000
--- a/helper/serialize.go
+++ /dev/null
@@ -1,343 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package helper
-
-import (
- "bytes"
- "errors"
- "fmt"
- "sort"
- "time"
-
- "github.com/luci/gae"
- "github.com/luci/luci-go/common/cmpbin"
-)
-
-// WriteDSPropertyMapDeterministic allows tests to make WriteDSPropertyMap
-// deterministic.
-var WriteDSPropertyMapDeterministic = false
-
-// ReadDSPropertyMapReasonableLimit sets a limit on the number of rows and
-// number of properties per row which can be read by ReadDSPropertyMap. The
-// total number of Property objects readable by this method is this number
-// squared (e.g. Limit rows * Limit properties)
-const ReadDSPropertyMapReasonableLimit uint64 = 30000
-
-// ReadKeyNumToksReasonableLimit is the maximum number of DSKey tokens that
-// ReadDSKey is willing to read for a single key.
-const ReadKeyNumToksReasonableLimit uint64 = 50
-
-// DSKeyContext controls whether the various Write and Read serializtion
-// routines should encode the context of DSKeys (read: the appid and namespace).
-// Frequently the appid and namespace of keys are known in advance and so there's
-// no reason to redundantly encode them.
-type DSKeyContext bool
-
-// With- and WithoutContext indicate if the serialization method should include
-// context for DSKeys. See DSKeyContext for more information.
-const (
- WithContext DSKeyContext = true
- WithoutContext = false
-)
-
-// WriteDSKey encodes a key to the buffer. If context is WithContext, then this
-// encoded value will include the appid and namespace of the key.
-func WriteDSKey(buf *bytes.Buffer, context DSKeyContext, k gae.DSKey) {
- // [appid ++ namespace]? ++ #tokens ++ tokens*
- appid, namespace, toks := DSKeySplit(k)
- if context == WithContext {
- buf.WriteByte(1)
- cmpbin.WriteString(buf, appid)
- cmpbin.WriteString(buf, namespace)
- } else {
- buf.WriteByte(0)
- }
- cmpbin.WriteUint(buf, uint64(len(toks)))
- for _, tok := range toks {
- WriteDSKeyTok(buf, tok)
- }
-}
-
-// ReadDSKey deserializes a key from the buffer. The value of context must match
-// the value of context that was passed to WriteDSKey when the key was encoded.
-// If context == WithoutContext, then the appid and namespace parameters are
-// used in the decoded DSKey. Otherwise they're ignored.
-func ReadDSKey(buf *bytes.Buffer, context DSKeyContext, appid, namespace string) (ret gae.DSKey, err error) {
- actualCtx, err := buf.ReadByte()
- if err != nil {
- return
- }
-
- actualAid, actualNS := "", ""
- if actualCtx == 1 {
- if actualAid, _, err = cmpbin.ReadString(buf); err != nil {
- return
- }
- if actualNS, _, err = cmpbin.ReadString(buf); err != nil {
- return
- }
- } else if actualCtx != 0 {
- err = fmt.Errorf("helper: expected actualCtx to be 0 or 1, got %d", actualCtx)
- return
- }
-
- if context == WithoutContext {
- // overrwrite with the supplied ones
- actualAid = appid
- actualNS = namespace
- }
-
- numToks := uint64(0)
- if numToks, _, err = cmpbin.ReadUint(buf); err != nil {
- return
- }
- if numToks > ReadKeyNumToksReasonableLimit {
- err = fmt.Errorf("helper: tried to decode huge key of length %d", numToks)
- return
- }
-
- toks := make([]gae.DSKeyTok, numToks)
- for i := uint64(0); i < numToks; i++ {
- if toks[i], err = ReadDSKeyTok(buf); err != nil {
- return
- }
- }
-
- return NewDSKeyToks(actualAid, actualNS, toks), nil
-}
-
-// WriteDSKeyTok writes a DSKeyTok to the buffer. You usually want WriteDSKey
-// instead of this.
-func WriteDSKeyTok(buf *bytes.Buffer, tok gae.DSKeyTok) {
- // tok.kind ++ typ ++ [tok.stringID || tok.intID]
- cmpbin.WriteString(buf, tok.Kind)
- if tok.StringID != "" {
- buf.WriteByte(byte(gae.DSPTString))
- cmpbin.WriteString(buf, tok.StringID)
- } else {
- buf.WriteByte(byte(gae.DSPTInt))
- cmpbin.WriteInt(buf, tok.IntID)
- }
-}
-
-// ReadDSKeyTok reads a DSKeyTok from the buffer. You usually want ReadDSKey
-// instead of this.
-func ReadDSKeyTok(buf *bytes.Buffer) (ret gae.DSKeyTok, err error) {
- if ret.Kind, _, err = cmpbin.ReadString(buf); err != nil {
- return
- }
- typ, err := buf.ReadByte()
- if err != nil {
- return
- }
- switch gae.DSPropertyType(typ) {
- case gae.DSPTString:
- ret.StringID, _, err = cmpbin.ReadString(buf)
- case gae.DSPTInt:
- ret.IntID, _, err = cmpbin.ReadInt(buf)
- if err == nil && ret.IntID <= 0 {
- err = errors.New("helper: decoded key with empty stringID and zero/negative intID")
- }
- default:
- err = fmt.Errorf("helper: invalid type %s", gae.DSPropertyType(typ))
- }
- return
-}
-
-// WriteDSGeoPoint writes a DSGeoPoint to the buffer.
-func WriteDSGeoPoint(buf *bytes.Buffer, gp gae.DSGeoPoint) {
- cmpbin.WriteFloat64(buf, gp.Lat)
- cmpbin.WriteFloat64(buf, gp.Lng)
-}
-
-// ReadDSGeoPoint reads a DSGeoPoint from the buffer.
-func ReadDSGeoPoint(buf *bytes.Buffer) (gp gae.DSGeoPoint, err error) {
- if gp.Lat, _, err = cmpbin.ReadFloat64(buf); err != nil {
- return
- }
- gp.Lng, _, err = cmpbin.ReadFloat64(buf)
- if err == nil && !gp.Valid() {
- err = fmt.Errorf("helper: decoded invalid DSGeoPoint: %v", gp)
- }
- return
-}
-
-// WriteTime writes a time.Time in a byte-sortable way.
-//
-// This method truncates the time to microseconds and drops the timezone,
-// because that's the (undocumented) way that the appengine SDK does it.
-func WriteTime(buf *bytes.Buffer, t time.Time) {
- name, off := t.Zone()
- if name != "UTC" || off != 0 {
- panic(fmt.Errorf("helper: UTC OR DEATH: %s", t))
- }
- cmpbin.WriteUint(buf, uint64(t.Unix())*1e6+uint64(t.Nanosecond()/1e3))
-}
-
-// ReadTime reads a time.Time from the buffer.
-func ReadTime(buf *bytes.Buffer) (time.Time, error) {
- v, _, err := cmpbin.ReadUint(buf)
- if err != nil {
- return time.Time{}, err
- }
- return time.Unix(int64(v/1e6), int64((v%1e6)*1e3)).UTC(), nil
-}
-
-// WriteDSProperty writes a DSProperty to the buffer. `context` behaves the same
-// way that it does for WriteDSKey, but only has an effect if `p` contains a
-// DSKey as its Value.
-func WriteDSProperty(buf *bytes.Buffer, p gae.DSProperty, context DSKeyContext) {
- typb := byte(p.Type())
- if p.IndexSetting() == gae.NoIndex {
- typb |= 0x80
- }
- buf.WriteByte(typb)
- switch p.Type() {
- case gae.DSPTNull, gae.DSPTBoolTrue, gae.DSPTBoolFalse:
- case gae.DSPTInt:
- cmpbin.WriteInt(buf, p.Value().(int64))
- case gae.DSPTFloat:
- cmpbin.WriteFloat64(buf, p.Value().(float64))
- case gae.DSPTString:
- cmpbin.WriteString(buf, p.Value().(string))
- case gae.DSPTBytes:
- if p.IndexSetting() == gae.NoIndex {
- cmpbin.WriteBytes(buf, p.Value().([]byte))
- } else {
- cmpbin.WriteBytes(buf, p.Value().(gae.DSByteString))
- }
- case gae.DSPTTime:
- WriteTime(buf, p.Value().(time.Time))
- case gae.DSPTGeoPoint:
- WriteDSGeoPoint(buf, p.Value().(gae.DSGeoPoint))
- case gae.DSPTKey:
- WriteDSKey(buf, context, p.Value().(gae.DSKey))
- case gae.DSPTBlobKey:
- cmpbin.WriteString(buf, string(p.Value().(gae.BSKey)))
- }
-}
-
-// ReadDSProperty reads a DSProperty from the buffer. `context`, `appid`, and
-// `namespace` behave the same way they do for ReadDSKey, but only have an
-// effect if the decoded property has a DSKey value.
-func ReadDSProperty(buf *bytes.Buffer, context DSKeyContext, appid, namespace string) (p gae.DSProperty, err error) {
- val := interface{}(nil)
- typb, err := buf.ReadByte()
- if err != nil {
- return
- }
- is := gae.ShouldIndex
- if (typb & 0x80) != 0 {
- is = gae.NoIndex
- }
- switch gae.DSPropertyType(typb & 0x7f) {
- case gae.DSPTNull:
- case gae.DSPTBoolTrue:
- val = true
- case gae.DSPTBoolFalse:
- val = false
- case gae.DSPTInt:
- val, _, err = cmpbin.ReadInt(buf)
- case gae.DSPTFloat:
- val, _, err = cmpbin.ReadFloat64(buf)
- case gae.DSPTString:
- val, _, err = cmpbin.ReadString(buf)
- case gae.DSPTBytes:
- b := []byte(nil)
- if b, _, err = cmpbin.ReadBytes(buf); err != nil {
- break
- }
- if is == gae.NoIndex {
- val = b
- } else {
- val = gae.DSByteString(b)
- }
- case gae.DSPTTime:
- val, err = ReadTime(buf)
- case gae.DSPTGeoPoint:
- val, err = ReadDSGeoPoint(buf)
- case gae.DSPTKey:
- val, err = ReadDSKey(buf, context, appid, namespace)
- case gae.DSPTBlobKey:
- s := ""
- if s, _, err = cmpbin.ReadString(buf); err != nil {
- break
- }
- val = gae.BSKey(s)
- default:
- err = fmt.Errorf("read: unknown type! %v", typb)
- }
- if err == nil {
- err = p.SetValue(val, is)
- }
- return
-}
-
-// WriteDSPropertyMap writes an entire DSPropertyMap to the buffer. `context`
-// behaves the same way that it does for WriteDSKey. If
-// WriteDSPropertyMapDeterministic is true, then the rows will be sorted by
-// property name before they're serialized to buf (mostly useful for testing,
-// but also potentially useful if you need to make a hash of the property data).
-func WriteDSPropertyMap(buf *bytes.Buffer, propMap gae.DSPropertyMap, context DSKeyContext) {
- rows := make(sort.StringSlice, 0, len(propMap))
- tmpBuf := &bytes.Buffer{}
- for name, vals := range propMap {
- tmpBuf.Reset()
- cmpbin.WriteString(tmpBuf, name)
- cmpbin.WriteUint(tmpBuf, uint64(len(vals)))
- for _, p := range vals {
- WriteDSProperty(tmpBuf, p, context)
- }
- rows = append(rows, tmpBuf.String())
- }
-
- if WriteDSPropertyMapDeterministic {
- rows.Sort()
- }
-
- cmpbin.WriteUint(buf, uint64(len(propMap)))
- for _, r := range rows {
- buf.WriteString(r)
- }
-}
-
-// ReadDSPropertyMap reads a DSPropertyMap from the buffer. `context` and
-// friends behave the same way that they do for ReadDSKey.
-func ReadDSPropertyMap(buf *bytes.Buffer, context DSKeyContext, appid, namespace string) (propMap gae.DSPropertyMap, err error) {
- numRows := uint64(0)
- if numRows, _, err = cmpbin.ReadUint(buf); err != nil {
- return
- }
- if numRows > ReadDSPropertyMapReasonableLimit {
- err = fmt.Errorf("helper: tried to decode map with huge number of rows %d", numRows)
- return
- }
-
- name, prop := "", gae.DSProperty{}
- propMap = make(gae.DSPropertyMap, numRows)
- for i := uint64(0); i < numRows; i++ {
- if name, _, err = cmpbin.ReadString(buf); err != nil {
- return
- }
-
- numProps := uint64(0)
- if numProps, _, err = cmpbin.ReadUint(buf); err != nil {
- return
- }
- if numProps > ReadDSPropertyMapReasonableLimit {
- err = fmt.Errorf("helper: tried to decode map with huge number of properties %d", numProps)
- return
- }
- props := make([]gae.DSProperty, 0, numProps)
- for j := uint64(0); j < numProps; j++ {
- if prop, err = ReadDSProperty(buf, context, appid, namespace); err != nil {
- return
- }
- props = append(props, prop)
- }
- propMap[name] = props
- }
- return
-}
« no previous file with comments | « helper/internal/protos/datastore/datastore_v3.pb.go ('k') | helper/serialize_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698