Add initial well-known types support package.
This is initially only Duration helper funcs;
more will follow.
diff --git a/Makefile b/Makefile
index d24239e..19551a9 100644
--- a/Makefile
+++ b/Makefile
@@ -33,13 +33,11 @@
all: install
install:
- go install ./proto
- go install ./jsonpb
+ go install ./proto ./jsonpb ./types
go install ./protoc-gen-go
test:
- go test ./proto
- go test ./jsonpb
+ go test ./proto ./jsonpb ./types
make -C protoc-gen-go/testdata test
clean:
diff --git a/types/doc.go b/types/doc.go
index efc1d47..ff2810a 100644
--- a/types/doc.go
+++ b/types/doc.go
@@ -1,6 +1,35 @@
-/*
-Package types will contain code for interacting with well-known types.
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2016 The Go Authors. All rights reserved.
+// https://github.com/golang/protobuf
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-For now, it is a placeholder; see its subdirectories for the protos themselves.
+/*
+Package types contains code for interacting with well-known types.
*/
package types
diff --git a/types/duration.go b/types/duration.go
new file mode 100644
index 0000000..40f84f0
--- /dev/null
+++ b/types/duration.go
@@ -0,0 +1,102 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2016 The Go Authors. All rights reserved.
+// https://github.com/golang/protobuf
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package types
+
+// This file implements conversions between google.protobuf.Duration
+// and time.Duration.
+
+import (
+ "errors"
+ "fmt"
+ "time"
+
+ durpb "github.com/golang/protobuf/types/duration"
+)
+
+const (
+ // Range of a durpb.Duration in seconds, as specified in
+ // google/protobuf/duration.proto. This is about 10,000 years in seconds.
+ maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
+ minSeconds = -maxSeconds
+)
+
+// ValidateDuration determines whether the durpb.Duration is valid according to the
+// definition in google/protobuf/duration.proto. A valid durpb.Duration
+// may still be too large to fit into a time.Duration (the range of durpb.Duration
+// is about 10,000 years, and the range of time.Duration is about 290).
+func ValidateDuration(d *durpb.Duration) error {
+ if d == nil {
+ return errors.New("duration: nil Duration")
+ }
+ if d.Seconds < minSeconds || d.Seconds > maxSeconds {
+ return fmt.Errorf("duration: %v: seconds out of range", d)
+ }
+ if d.Nanos <= -1e9 || d.Nanos >= 1e9 {
+ return fmt.Errorf("duration: %v: nanos out of range", d)
+ }
+ // Seconds and Nanos must have the same sign, unless d.Nanos is zero.
+ if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) {
+ return fmt.Errorf("duration: %v: seconds and nanos have different signs", d)
+ }
+ return nil
+}
+
+// DurationFromProto attempts to convert a durpb.Duration to a time.Duration. DurationFromProto
+// returns an error if the durpb.Duration is invalid or is too large to be
+// represented in a time.Duration.
+func DurationFromProto(p *durpb.Duration) (time.Duration, error) {
+ if err := ValidateDuration(p); err != nil {
+ return 0, err
+ }
+ d := time.Duration(p.Seconds) * time.Second
+ if int64(d/time.Second) != p.Seconds {
+ return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
+ }
+ if p.Nanos != 0 {
+ d += time.Duration(p.Nanos)
+ if (d < 0) != (p.Nanos < 0) {
+ return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
+ }
+ }
+ return d, nil
+}
+
+// DurationProto converts a time.Duration to a durpb.Duration.
+func DurationProto(d time.Duration) *durpb.Duration {
+ nanos := d.Nanoseconds()
+ secs := nanos / 1e9
+ nanos -= secs * 1e9
+ return &durpb.Duration{
+ Seconds: secs,
+ Nanos: int32(nanos),
+ }
+}
diff --git a/types/duration_test.go b/types/duration_test.go
new file mode 100644
index 0000000..02462ae
--- /dev/null
+++ b/types/duration_test.go
@@ -0,0 +1,121 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2016 The Go Authors. All rights reserved.
+// https://github.com/golang/protobuf
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package types
+
+import (
+ "math"
+ "testing"
+ "time"
+
+ "github.com/golang/protobuf/proto"
+ durpb "github.com/golang/protobuf/types/duration"
+)
+
+const (
+ minGoSeconds = math.MinInt64 / int64(1e9)
+ maxGoSeconds = math.MaxInt64 / int64(1e9)
+)
+
+var durationTests = []struct {
+ proto *durpb.Duration
+ isValid bool
+ inRange bool
+ dur time.Duration
+}{
+ // The zero duration.
+ {&durpb.Duration{0, 0}, true, true, 0},
+ // Some ordinary non-zero durations.
+ {&durpb.Duration{100, 0}, true, true, 100 * time.Second},
+ {&durpb.Duration{-100, 0}, true, true, -100 * time.Second},
+ {&durpb.Duration{100, 987}, true, true, 100*time.Second + 987},
+ {&durpb.Duration{-100, -987}, true, true, -(100*time.Second + 987)},
+ // The largest duration representable in Go.
+ {&durpb.Duration{maxGoSeconds, int32(math.MaxInt64 - 1e9*maxGoSeconds)}, true, true, math.MaxInt64},
+ // The smallest duration representable in Go.
+ {&durpb.Duration{minGoSeconds, int32(math.MinInt64 - 1e9*minGoSeconds)}, true, true, math.MinInt64},
+ {nil, false, false, 0},
+ {&durpb.Duration{-100, 987}, false, false, 0},
+ {&durpb.Duration{100, -987}, false, false, 0},
+ {&durpb.Duration{math.MinInt64, 0}, false, false, 0},
+ {&durpb.Duration{math.MaxInt64, 0}, false, false, 0},
+ // The largest valid duration.
+ {&durpb.Duration{maxSeconds, 1e9 - 1}, true, false, 0},
+ // The smallest valid duration.
+ {&durpb.Duration{minSeconds, -(1e9 - 1)}, true, false, 0},
+ // The smallest invalid duration above the valid range.
+ {&durpb.Duration{maxSeconds + 1, 0}, false, false, 0},
+ // The largest invalid duration below the valid range.
+ {&durpb.Duration{minSeconds - 1, -(1e9 - 1)}, false, false, 0},
+ // One nanosecond past the largest duration representable in Go.
+ {&durpb.Duration{maxGoSeconds, int32(math.MaxInt64-1e9*maxGoSeconds) + 1}, true, false, 0},
+ // One nanosecond past the smallest duration representable in Go.
+ {&durpb.Duration{minGoSeconds, int32(math.MinInt64-1e9*minGoSeconds) - 1}, true, false, 0},
+ // One second past the largest duration representable in Go.
+ {&durpb.Duration{maxGoSeconds + 1, int32(math.MaxInt64 - 1e9*maxGoSeconds)}, true, false, 0},
+ // One second past the smallest duration representable in Go.
+ {&durpb.Duration{minGoSeconds - 1, int32(math.MinInt64 - 1e9*minGoSeconds)}, true, false, 0},
+}
+
+func TestValidateDuration(t *testing.T) {
+ for _, test := range durationTests {
+ err := ValidateDuration(test.proto)
+ gotValid := (err == nil)
+ if gotValid != test.isValid {
+ t.Errorf("ValidateDuration(%v) = %t, want %t", test.proto, gotValid, test.isValid)
+ }
+ }
+}
+
+func TestDurationFromProto(t *testing.T) {
+ for _, test := range durationTests {
+ got, err := DurationFromProto(test.proto)
+ gotOK := (err == nil)
+ wantOK := test.isValid && test.inRange
+ if gotOK != wantOK {
+ t.Errorf("DurationFromProto(%v) ok = %t, want %t", test.proto, gotOK, wantOK)
+ }
+ if err == nil && got != test.dur {
+ t.Errorf("DurationFromProto(%v) = %v, want %v", test.proto, got, test.dur)
+ }
+ }
+}
+
+func TestDurationProto(t *testing.T) {
+ for _, test := range durationTests {
+ if test.isValid && test.inRange {
+ got := DurationProto(test.dur)
+ if !proto.Equal(got, test.proto) {
+ t.Errorf("DurationProto(%v) = %v, want %v", test.dur, got, test.proto)
+ }
+ }
+ }
+}