summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/golang/groupcache/sinks.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/golang/groupcache/sinks.go')
-rw-r--r--vendor/github.com/golang/groupcache/sinks.go322
1 files changed, 322 insertions, 0 deletions
diff --git a/vendor/github.com/golang/groupcache/sinks.go b/vendor/github.com/golang/groupcache/sinks.go
new file mode 100644
index 000000000..cb42b41b4
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/sinks.go
@@ -0,0 +1,322 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package groupcache
+
+import (
+ "errors"
+
+ "github.com/golang/protobuf/proto"
+)
+
+// A Sink receives data from a Get call.
+//
+// Implementation of Getter must call exactly one of the Set methods
+// on success.
+type Sink interface {
+ // SetString sets the value to s.
+ SetString(s string) error
+
+ // SetBytes sets the value to the contents of v.
+ // The caller retains ownership of v.
+ SetBytes(v []byte) error
+
+ // SetProto sets the value to the encoded version of m.
+ // The caller retains ownership of m.
+ SetProto(m proto.Message) error
+
+ // view returns a frozen view of the bytes for caching.
+ view() (ByteView, error)
+}
+
+func cloneBytes(b []byte) []byte {
+ c := make([]byte, len(b))
+ copy(c, b)
+ return c
+}
+
+func setSinkView(s Sink, v ByteView) error {
+ // A viewSetter is a Sink that can also receive its value from
+ // a ByteView. This is a fast path to minimize copies when the
+ // item was already cached locally in memory (where it's
+ // cached as a ByteView)
+ type viewSetter interface {
+ setView(v ByteView) error
+ }
+ if vs, ok := s.(viewSetter); ok {
+ return vs.setView(v)
+ }
+ if v.b != nil {
+ return s.SetBytes(v.b)
+ }
+ return s.SetString(v.s)
+}
+
+// StringSink returns a Sink that populates the provided string pointer.
+func StringSink(sp *string) Sink {
+ return &stringSink{sp: sp}
+}
+
+type stringSink struct {
+ sp *string
+ v ByteView
+ // TODO(bradfitz): track whether any Sets were called.
+}
+
+func (s *stringSink) view() (ByteView, error) {
+ // TODO(bradfitz): return an error if no Set was called
+ return s.v, nil
+}
+
+func (s *stringSink) SetString(v string) error {
+ s.v.b = nil
+ s.v.s = v
+ *s.sp = v
+ return nil
+}
+
+func (s *stringSink) SetBytes(v []byte) error {
+ return s.SetString(string(v))
+}
+
+func (s *stringSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ s.v.b = b
+ *s.sp = string(b)
+ return nil
+}
+
+// ByteViewSink returns a Sink that populates a ByteView.
+func ByteViewSink(dst *ByteView) Sink {
+ if dst == nil {
+ panic("nil dst")
+ }
+ return &byteViewSink{dst: dst}
+}
+
+type byteViewSink struct {
+ dst *ByteView
+
+ // if this code ever ends up tracking that at least one set*
+ // method was called, don't make it an error to call set
+ // methods multiple times. Lorry's payload.go does that, and
+ // it makes sense. The comment at the top of this file about
+ // "exactly one of the Set methods" is overly strict. We
+ // really care about at least once (in a handler), but if
+ // multiple handlers fail (or multiple functions in a program
+ // using a Sink), it's okay to re-use the same one.
+}
+
+func (s *byteViewSink) setView(v ByteView) error {
+ *s.dst = v
+ return nil
+}
+
+func (s *byteViewSink) view() (ByteView, error) {
+ return *s.dst, nil
+}
+
+func (s *byteViewSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ *s.dst = ByteView{b: b}
+ return nil
+}
+
+func (s *byteViewSink) SetBytes(b []byte) error {
+ *s.dst = ByteView{b: cloneBytes(b)}
+ return nil
+}
+
+func (s *byteViewSink) SetString(v string) error {
+ *s.dst = ByteView{s: v}
+ return nil
+}
+
+// ProtoSink returns a sink that unmarshals binary proto values into m.
+func ProtoSink(m proto.Message) Sink {
+ return &protoSink{
+ dst: m,
+ }
+}
+
+type protoSink struct {
+ dst proto.Message // authorative value
+ typ string
+
+ v ByteView // encoded
+}
+
+func (s *protoSink) view() (ByteView, error) {
+ return s.v, nil
+}
+
+func (s *protoSink) SetBytes(b []byte) error {
+ err := proto.Unmarshal(b, s.dst)
+ if err != nil {
+ return err
+ }
+ s.v.b = cloneBytes(b)
+ s.v.s = ""
+ return nil
+}
+
+func (s *protoSink) SetString(v string) error {
+ b := []byte(v)
+ err := proto.Unmarshal(b, s.dst)
+ if err != nil {
+ return err
+ }
+ s.v.b = b
+ s.v.s = ""
+ return nil
+}
+
+func (s *protoSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ // TODO(bradfitz): optimize for same-task case more and write
+ // right through? would need to document ownership rules at
+ // the same time. but then we could just assign *dst = *m
+ // here. This works for now:
+ err = proto.Unmarshal(b, s.dst)
+ if err != nil {
+ return err
+ }
+ s.v.b = b
+ s.v.s = ""
+ return nil
+}
+
+// AllocatingByteSliceSink returns a Sink that allocates
+// a byte slice to hold the received value and assigns
+// it to *dst. The memory is not retained by groupcache.
+func AllocatingByteSliceSink(dst *[]byte) Sink {
+ return &allocBytesSink{dst: dst}
+}
+
+type allocBytesSink struct {
+ dst *[]byte
+ v ByteView
+}
+
+func (s *allocBytesSink) view() (ByteView, error) {
+ return s.v, nil
+}
+
+func (s *allocBytesSink) setView(v ByteView) error {
+ if v.b != nil {
+ *s.dst = cloneBytes(v.b)
+ } else {
+ *s.dst = []byte(v.s)
+ }
+ s.v = v
+ return nil
+}
+
+func (s *allocBytesSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ return s.setBytesOwned(b)
+}
+
+func (s *allocBytesSink) SetBytes(b []byte) error {
+ return s.setBytesOwned(cloneBytes(b))
+}
+
+func (s *allocBytesSink) setBytesOwned(b []byte) error {
+ if s.dst == nil {
+ return errors.New("nil AllocatingByteSliceSink *[]byte dst")
+ }
+ *s.dst = cloneBytes(b) // another copy, protecting the read-only s.v.b view
+ s.v.b = b
+ s.v.s = ""
+ return nil
+}
+
+func (s *allocBytesSink) SetString(v string) error {
+ if s.dst == nil {
+ return errors.New("nil AllocatingByteSliceSink *[]byte dst")
+ }
+ *s.dst = []byte(v)
+ s.v.b = nil
+ s.v.s = v
+ return nil
+}
+
+// TruncatingByteSliceSink returns a Sink that writes up to len(*dst)
+// bytes to *dst. If more bytes are available, they're silently
+// truncated. If fewer bytes are available than len(*dst), *dst
+// is shrunk to fit the number of bytes available.
+func TruncatingByteSliceSink(dst *[]byte) Sink {
+ return &truncBytesSink{dst: dst}
+}
+
+type truncBytesSink struct {
+ dst *[]byte
+ v ByteView
+}
+
+func (s *truncBytesSink) view() (ByteView, error) {
+ return s.v, nil
+}
+
+func (s *truncBytesSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ return s.setBytesOwned(b)
+}
+
+func (s *truncBytesSink) SetBytes(b []byte) error {
+ return s.setBytesOwned(cloneBytes(b))
+}
+
+func (s *truncBytesSink) setBytesOwned(b []byte) error {
+ if s.dst == nil {
+ return errors.New("nil TruncatingByteSliceSink *[]byte dst")
+ }
+ n := copy(*s.dst, b)
+ if n < len(*s.dst) {
+ *s.dst = (*s.dst)[:n]
+ }
+ s.v.b = b
+ s.v.s = ""
+ return nil
+}
+
+func (s *truncBytesSink) SetString(v string) error {
+ if s.dst == nil {
+ return errors.New("nil TruncatingByteSliceSink *[]byte dst")
+ }
+ n := copy(*s.dst, v)
+ if n < len(*s.dst) {
+ *s.dst = (*s.dst)[:n]
+ }
+ s.v.b = nil
+ s.v.s = v
+ return nil
+}