summaryrefslogtreecommitdiff
path: root/vendor/github.com/rs
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-22 17:35:49 -0600
committermo khan <mo@mokhan.ca>2025-07-22 17:35:49 -0600
commit20ef0d92694465ac86b550df139e8366a0a2b4fa (patch)
tree3f14589e1ce6eb9306a3af31c3a1f9e1af5ed637 /vendor/github.com/rs
parent44e0d272c040cdc53a98b9f1dc58ae7da67752e6 (diff)
feat: connect to spicedb
Diffstat (limited to 'vendor/github.com/rs')
-rw-r--r--vendor/github.com/rs/xid/.appveyor.yml27
-rw-r--r--vendor/github.com/rs/xid/.gitignore3
-rw-r--r--vendor/github.com/rs/xid/.golangci.yml5
-rw-r--r--vendor/github.com/rs/xid/.travis.yml8
-rw-r--r--vendor/github.com/rs/xid/LICENSE19
-rw-r--r--vendor/github.com/rs/xid/README.md121
-rw-r--r--vendor/github.com/rs/xid/error.go11
-rw-r--r--vendor/github.com/rs/xid/hostid_darwin.go34
-rw-r--r--vendor/github.com/rs/xid/hostid_fallback.go9
-rw-r--r--vendor/github.com/rs/xid/hostid_freebsd.go9
-rw-r--r--vendor/github.com/rs/xid/hostid_linux.go13
-rw-r--r--vendor/github.com/rs/xid/hostid_windows.go50
-rw-r--r--vendor/github.com/rs/xid/id.go390
-rw-r--r--vendor/github.com/rs/zerolog/diode/diode.go114
-rw-r--r--vendor/github.com/rs/zerolog/diode/internal/diodes/README1
-rw-r--r--vendor/github.com/rs/zerolog/diode/internal/diodes/many_to_one.go130
-rw-r--r--vendor/github.com/rs/zerolog/diode/internal/diodes/one_to_one.go129
-rw-r--r--vendor/github.com/rs/zerolog/diode/internal/diodes/poller.go80
-rw-r--r--vendor/github.com/rs/zerolog/diode/internal/diodes/waiter.go88
-rw-r--r--vendor/github.com/rs/zerolog/log/log.go131
20 files changed, 1372 insertions, 0 deletions
diff --git a/vendor/github.com/rs/xid/.appveyor.yml b/vendor/github.com/rs/xid/.appveyor.yml
new file mode 100644
index 0000000..c73bb33
--- /dev/null
+++ b/vendor/github.com/rs/xid/.appveyor.yml
@@ -0,0 +1,27 @@
+version: 1.0.0.{build}
+
+platform: x64
+
+branches:
+ only:
+ - master
+
+clone_folder: c:\gopath\src\github.com\rs\xid
+
+environment:
+ GOPATH: c:\gopath
+
+install:
+ - echo %PATH%
+ - echo %GOPATH%
+ - set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
+ - go version
+ - go env
+ - go get -t .
+
+build_script:
+ - go build
+
+test_script:
+ - go test
+
diff --git a/vendor/github.com/rs/xid/.gitignore b/vendor/github.com/rs/xid/.gitignore
new file mode 100644
index 0000000..81be927
--- /dev/null
+++ b/vendor/github.com/rs/xid/.gitignore
@@ -0,0 +1,3 @@
+/.idea
+/.vscode
+.DS_Store \ No newline at end of file
diff --git a/vendor/github.com/rs/xid/.golangci.yml b/vendor/github.com/rs/xid/.golangci.yml
new file mode 100644
index 0000000..7929600
--- /dev/null
+++ b/vendor/github.com/rs/xid/.golangci.yml
@@ -0,0 +1,5 @@
+run:
+ tests: false
+
+output:
+ sort-results: true
diff --git a/vendor/github.com/rs/xid/.travis.yml b/vendor/github.com/rs/xid/.travis.yml
new file mode 100644
index 0000000..b37da15
--- /dev/null
+++ b/vendor/github.com/rs/xid/.travis.yml
@@ -0,0 +1,8 @@
+language: go
+go:
+- "1.9"
+- "1.10"
+- "master"
+matrix:
+ allow_failures:
+ - go: "master"
diff --git a/vendor/github.com/rs/xid/LICENSE b/vendor/github.com/rs/xid/LICENSE
new file mode 100644
index 0000000..47c5e9d
--- /dev/null
+++ b/vendor/github.com/rs/xid/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 Olivier Poitrey <rs@dailymotion.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/rs/xid/README.md b/vendor/github.com/rs/xid/README.md
new file mode 100644
index 0000000..1bf45bd
--- /dev/null
+++ b/vendor/github.com/rs/xid/README.md
@@ -0,0 +1,121 @@
+# Globally Unique ID Generator
+
+[![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/xid) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/xid/master/LICENSE) [![Build Status](https://travis-ci.org/rs/xid.svg?branch=master)](https://travis-ci.org/rs/xid) [![Coverage](http://gocover.io/_badge/github.com/rs/xid)](http://gocover.io/github.com/rs/xid)
+
+Package xid is a globally unique id generator library, ready to safely be used directly in your server code.
+
+Xid uses the Mongo Object ID algorithm to generate globally unique ids with a different serialization ([base32hex](https://datatracker.ietf.org/doc/html/rfc4648#page-10)) to make it shorter when transported as a string:
+https://docs.mongodb.org/manual/reference/object-id/
+
+- 4-byte value representing the seconds since the Unix epoch,
+- 3-byte machine identifier,
+- 2-byte process id, and
+- 3-byte counter, starting with a random value.
+
+The binary representation of the id is compatible with Mongo 12 bytes Object IDs.
+The string representation is using [base32hex](https://datatracker.ietf.org/doc/html/rfc4648#page-10) (w/o padding) for better space efficiency
+when stored in that form (20 bytes). The hex variant of base32 is used to retain the
+sortable property of the id.
+
+Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an
+issue when transported as a string between various systems. Base36 wasn't retained either
+because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned)
+and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long,
+all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`).
+
+UUIDs are 16 bytes (128 bits) and 36 chars as string representation. Twitter Snowflake
+ids are 8 bytes (64 bits) but require machine/data-center configuration and/or central
+generator servers. xid stands in between with 12 bytes (96 bits) and a more compact
+URL-safe string representation (20 chars). No configuration or central generator server
+is required so it can be used directly in server's code.
+
+| Name | Binary Size | String Size | Features
+|-------------|-------------|----------------|----------------
+| [UUID] | 16 bytes | 36 chars | configuration free, not sortable
+| [shortuuid] | 16 bytes | 22 chars | configuration free, not sortable
+| [Snowflake] | 8 bytes | up to 20 chars | needs machine/DC configuration, needs central server, sortable
+| [MongoID] | 12 bytes | 24 chars | configuration free, sortable
+| xid | 12 bytes | 20 chars | configuration free, sortable
+
+[UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier
+[shortuuid]: https://github.com/stochastic-technologies/shortuuid
+[Snowflake]: https://blog.twitter.com/2010/announcing-snowflake
+[MongoID]: https://docs.mongodb.org/manual/reference/object-id/
+
+Features:
+
+- Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake
+- Base32 hex encoded by default (20 chars when transported as printable string, still sortable)
+- Non configured, you don't need set a unique machine and/or data center id
+- K-ordered
+- Embedded time with 1 second precision
+- Unicity guaranteed for 16,777,216 (24 bits) unique ids per second and per host/process
+- Lock-free (i.e.: unlike UUIDv1 and v2)
+
+Best used with [zerolog](https://github.com/rs/zerolog)'s
+[RequestIDHandler](https://godoc.org/github.com/rs/zerolog/hlog#RequestIDHandler).
+
+Notes:
+
+- Xid is dependent on the system time, a monotonic counter and so is not cryptographically secure. If unpredictability of IDs is important, you should not use Xids. It is worth noting that most other UUID-like implementations are also not cryptographically secure. You should use libraries that rely on cryptographically secure sources (like /dev/urandom on unix, crypto/rand in golang), if you want a truly random ID generator.
+
+References:
+
+- http://www.slideshare.net/davegardnerisme/unique-id-generation-in-distributed-systems
+- https://en.wikipedia.org/wiki/Universally_unique_identifier
+- https://blog.twitter.com/2010/announcing-snowflake
+- Python port by [Graham Abbott](https://github.com/graham): https://github.com/graham/python_xid
+- Scala port by [Egor Kolotaev](https://github.com/kolotaev): https://github.com/kolotaev/ride
+- Rust port by [Jérôme Renard](https://github.com/jeromer/): https://github.com/jeromer/libxid
+- Ruby port by [Valar](https://github.com/valarpirai/): https://github.com/valarpirai/ruby_xid
+- Java port by [0xShamil](https://github.com/0xShamil/): https://github.com/0xShamil/java-xid
+- Dart port by [Peter Bwire](https://github.com/pitabwire): https://pub.dev/packages/xid
+- PostgreSQL port by [Rasmus Holm](https://github.com/crholm): https://github.com/modfin/pg-xid
+- Swift port by [Uditha Atukorala](https://github.com/uatuko): https://github.com/uatuko/swift-xid
+- C++ port by [Uditha Atukorala](https://github.com/uatuko): https://github.com/uatuko/libxid
+- Typescript & Javascript port by [Yiwen AI](https://github.com/yiwen-ai): https://github.com/yiwen-ai/xid-ts
+- Gleam port by [Alexandre Del Vecchio](https://github.com/defgenx): https://github.com/defgenx/gxid
+
+## Install
+
+ go get github.com/rs/xid
+
+## Usage
+
+```go
+guid := xid.New()
+
+println(guid.String())
+// Output: 9m4e2mr0ui3e8a215n4g
+```
+
+Get `xid` embedded info:
+
+```go
+guid.Machine()
+guid.Pid()
+guid.Time()
+guid.Counter()
+```
+
+## Benchmark
+
+Benchmark against Go [Maxim Bublis](https://github.com/satori)'s [UUID](https://github.com/satori/go.uuid).
+
+```
+BenchmarkXID 20000000 91.1 ns/op 32 B/op 1 allocs/op
+BenchmarkXID-2 20000000 55.9 ns/op 32 B/op 1 allocs/op
+BenchmarkXID-4 50000000 32.3 ns/op 32 B/op 1 allocs/op
+BenchmarkUUIDv1 10000000 204 ns/op 48 B/op 1 allocs/op
+BenchmarkUUIDv1-2 10000000 160 ns/op 48 B/op 1 allocs/op
+BenchmarkUUIDv1-4 10000000 195 ns/op 48 B/op 1 allocs/op
+BenchmarkUUIDv4 1000000 1503 ns/op 64 B/op 2 allocs/op
+BenchmarkUUIDv4-2 1000000 1427 ns/op 64 B/op 2 allocs/op
+BenchmarkUUIDv4-4 1000000 1452 ns/op 64 B/op 2 allocs/op
+```
+
+Note: UUIDv1 requires a global lock, hence the performance degradation as we add more CPUs.
+
+## Licenses
+
+All source code is licensed under the [MIT License](https://raw.github.com/rs/xid/master/LICENSE).
diff --git a/vendor/github.com/rs/xid/error.go b/vendor/github.com/rs/xid/error.go
new file mode 100644
index 0000000..ea25374
--- /dev/null
+++ b/vendor/github.com/rs/xid/error.go
@@ -0,0 +1,11 @@
+package xid
+
+const (
+ // ErrInvalidID is returned when trying to unmarshal an invalid ID.
+ ErrInvalidID strErr = "xid: invalid ID"
+)
+
+// strErr allows declaring errors as constants.
+type strErr string
+
+func (err strErr) Error() string { return string(err) }
diff --git a/vendor/github.com/rs/xid/hostid_darwin.go b/vendor/github.com/rs/xid/hostid_darwin.go
new file mode 100644
index 0000000..1735156
--- /dev/null
+++ b/vendor/github.com/rs/xid/hostid_darwin.go
@@ -0,0 +1,34 @@
+// +build darwin
+
+package xid
+
+import (
+ "errors"
+ "os/exec"
+ "strings"
+)
+
+func readPlatformMachineID() (string, error) {
+ ioreg, err := exec.LookPath("ioreg")
+ if err != nil {
+ return "", err
+ }
+
+ cmd := exec.Command(ioreg, "-rd1", "-c", "IOPlatformExpertDevice")
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return "", err
+ }
+
+ for _, line := range strings.Split(string(out), "\n") {
+ if strings.Contains(line, "IOPlatformUUID") {
+ parts := strings.SplitAfter(line, `" = "`)
+ if len(parts) == 2 {
+ uuid := strings.TrimRight(parts[1], `"`)
+ return strings.ToLower(uuid), nil
+ }
+ }
+ }
+
+ return "", errors.New("cannot find host id")
+}
diff --git a/vendor/github.com/rs/xid/hostid_fallback.go b/vendor/github.com/rs/xid/hostid_fallback.go
new file mode 100644
index 0000000..7fbd3c0
--- /dev/null
+++ b/vendor/github.com/rs/xid/hostid_fallback.go
@@ -0,0 +1,9 @@
+// +build !darwin,!linux,!freebsd,!windows
+
+package xid
+
+import "errors"
+
+func readPlatformMachineID() (string, error) {
+ return "", errors.New("not implemented")
+}
diff --git a/vendor/github.com/rs/xid/hostid_freebsd.go b/vendor/github.com/rs/xid/hostid_freebsd.go
new file mode 100644
index 0000000..be25a03
--- /dev/null
+++ b/vendor/github.com/rs/xid/hostid_freebsd.go
@@ -0,0 +1,9 @@
+// +build freebsd
+
+package xid
+
+import "syscall"
+
+func readPlatformMachineID() (string, error) {
+ return syscall.Sysctl("kern.hostuuid")
+}
diff --git a/vendor/github.com/rs/xid/hostid_linux.go b/vendor/github.com/rs/xid/hostid_linux.go
new file mode 100644
index 0000000..837b204
--- /dev/null
+++ b/vendor/github.com/rs/xid/hostid_linux.go
@@ -0,0 +1,13 @@
+// +build linux
+
+package xid
+
+import "io/ioutil"
+
+func readPlatformMachineID() (string, error) {
+ b, err := ioutil.ReadFile("/etc/machine-id")
+ if err != nil || len(b) == 0 {
+ b, err = ioutil.ReadFile("/sys/class/dmi/id/product_uuid")
+ }
+ return string(b), err
+}
diff --git a/vendor/github.com/rs/xid/hostid_windows.go b/vendor/github.com/rs/xid/hostid_windows.go
new file mode 100644
index 0000000..a4d98ab
--- /dev/null
+++ b/vendor/github.com/rs/xid/hostid_windows.go
@@ -0,0 +1,50 @@
+// +build windows
+
+package xid
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+func readPlatformMachineID() (string, error) {
+ // source: https://github.com/shirou/gopsutil/blob/master/host/host_syscall.go
+ var h syscall.Handle
+
+ regKeyCryptoPtr, err := syscall.UTF16PtrFromString(`SOFTWARE\Microsoft\Cryptography`)
+ if err != nil {
+ return "", fmt.Errorf(`error reading registry key "SOFTWARE\Microsoft\Cryptography": %w`, err)
+ }
+
+ err = syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, regKeyCryptoPtr, 0, syscall.KEY_READ|syscall.KEY_WOW64_64KEY, &h)
+ if err != nil {
+ return "", err
+ }
+ defer func() { _ = syscall.RegCloseKey(h) }()
+
+ const syscallRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16
+ const uuidLen = 36
+
+ var regBuf [syscallRegBufLen]uint16
+ bufLen := uint32(syscallRegBufLen)
+ var valType uint32
+
+ mGuidPtr, err := syscall.UTF16PtrFromString(`MachineGuid`)
+ if err != nil {
+ return "", fmt.Errorf("error reading machine GUID: %w", err)
+ }
+
+ err = syscall.RegQueryValueEx(h, mGuidPtr, nil, &valType, (*byte)(unsafe.Pointer(&regBuf[0])), &bufLen)
+ if err != nil {
+ return "", fmt.Errorf("error parsing ")
+ }
+
+ hostID := syscall.UTF16ToString(regBuf[:])
+ hostIDLen := len(hostID)
+ if hostIDLen != uuidLen {
+ return "", fmt.Errorf("HostID incorrect: %q\n", hostID)
+ }
+
+ return hostID, nil
+}
diff --git a/vendor/github.com/rs/xid/id.go b/vendor/github.com/rs/xid/id.go
new file mode 100644
index 0000000..e88984d
--- /dev/null
+++ b/vendor/github.com/rs/xid/id.go
@@ -0,0 +1,390 @@
+// Package xid is a globally unique id generator suited for web scale
+//
+// Xid is using Mongo Object ID algorithm to generate globally unique ids:
+// https://docs.mongodb.org/manual/reference/object-id/
+//
+// - 4-byte value representing the seconds since the Unix epoch,
+// - 3-byte machine identifier,
+// - 2-byte process id, and
+// - 3-byte counter, starting with a random value.
+//
+// The binary representation of the id is compatible with Mongo 12 bytes Object IDs.
+// The string representation is using base32 hex (w/o padding) for better space efficiency
+// when stored in that form (20 bytes). The hex variant of base32 is used to retain the
+// sortable property of the id.
+//
+// Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an
+// issue when transported as a string between various systems. Base36 wasn't retained either
+// because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned)
+// and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long,
+// all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`).
+//
+// UUID is 16 bytes (128 bits), snowflake is 8 bytes (64 bits), xid stands in between
+// with 12 bytes with a more compact string representation ready for the web and no
+// required configuration or central generation server.
+//
+// Features:
+//
+// - Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake
+// - Base32 hex encoded by default (16 bytes storage when transported as printable string)
+// - Non configured, you don't need set a unique machine and/or data center id
+// - K-ordered
+// - Embedded time with 1 second precision
+// - Unicity guaranteed for 16,777,216 (24 bits) unique ids per second and per host/process
+//
+// Best used with xlog's RequestIDHandler (https://godoc.org/github.com/rs/xlog#RequestIDHandler).
+//
+// References:
+//
+// - http://www.slideshare.net/davegardnerisme/unique-id-generation-in-distributed-systems
+// - https://en.wikipedia.org/wiki/Universally_unique_identifier
+// - https://blog.twitter.com/2010/announcing-snowflake
+package xid
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "crypto/rand"
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "hash/crc32"
+ "io/ioutil"
+ "os"
+ "sort"
+ "sync/atomic"
+ "time"
+)
+
+// Code inspired from mgo/bson ObjectId
+
+// ID represents a unique request id
+type ID [rawLen]byte
+
+const (
+ encodedLen = 20 // string encoded len
+ rawLen = 12 // binary raw len
+
+ // encoding stores a custom version of the base32 encoding with lower case
+ // letters.
+ encoding = "0123456789abcdefghijklmnopqrstuv"
+)
+
+var (
+ // objectIDCounter is atomically incremented when generating a new ObjectId. It's
+ // used as the counter part of an id. This id is initialized with a random value.
+ objectIDCounter = randInt()
+
+ // machineID is generated once and used in subsequent calls to the New* functions.
+ machineID = readMachineID()
+
+ // pid stores the current process id
+ pid = os.Getpid()
+
+ nilID ID
+
+ // dec is the decoding map for base32 encoding
+ dec [256]byte
+)
+
+func init() {
+ for i := 0; i < len(dec); i++ {
+ dec[i] = 0xFF
+ }
+ for i := 0; i < len(encoding); i++ {
+ dec[encoding[i]] = byte(i)
+ }
+
+ // If /proc/self/cpuset exists and is not /, we can assume that we are in a
+ // form of container and use the content of cpuset xor-ed with the PID in
+ // order get a reasonable machine global unique PID.
+ b, err := ioutil.ReadFile("/proc/self/cpuset")
+ if err == nil && len(b) > 1 {
+ pid ^= int(crc32.ChecksumIEEE(b))
+ }
+}
+
+// readMachineID generates a machine ID, derived from a platform-specific machine ID
+// value, or else the machine's hostname, or else a randomly-generated number.
+// It panics if all of these methods fail.
+func readMachineID() []byte {
+ id := make([]byte, 3)
+ hid, err := readPlatformMachineID()
+ if err != nil || len(hid) == 0 {
+ hid, err = os.Hostname()
+ }
+ if err == nil && len(hid) != 0 {
+ hw := sha256.New()
+ hw.Write([]byte(hid))
+ copy(id, hw.Sum(nil))
+ } else {
+ // Fallback to rand number if machine id can't be gathered
+ if _, randErr := rand.Reader.Read(id); randErr != nil {
+ panic(fmt.Errorf("xid: cannot get hostname nor generate a random number: %v; %v", err, randErr))
+ }
+ }
+ return id
+}
+
+// randInt generates a random uint32
+func randInt() uint32 {
+ b := make([]byte, 3)
+ if _, err := rand.Reader.Read(b); err != nil {
+ panic(fmt.Errorf("xid: cannot generate random number: %v;", err))
+ }
+ return uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])
+}
+
+// New generates a globally unique ID
+func New() ID {
+ return NewWithTime(time.Now())
+}
+
+// NewWithTime generates a globally unique ID with the passed in time
+func NewWithTime(t time.Time) ID {
+ var id ID
+ // Timestamp, 4 bytes, big endian
+ binary.BigEndian.PutUint32(id[:], uint32(t.Unix()))
+ // Machine ID, 3 bytes
+ id[4] = machineID[0]
+ id[5] = machineID[1]
+ id[6] = machineID[2]
+ // Pid, 2 bytes, specs don't specify endianness, but we use big endian.
+ id[7] = byte(pid >> 8)
+ id[8] = byte(pid)
+ // Increment, 3 bytes, big endian
+ i := atomic.AddUint32(&objectIDCounter, 1)
+ id[9] = byte(i >> 16)
+ id[10] = byte(i >> 8)
+ id[11] = byte(i)
+ return id
+}
+
+// FromString reads an ID from its string representation
+func FromString(id string) (ID, error) {
+ i := &ID{}
+ err := i.UnmarshalText([]byte(id))
+ return *i, err
+}
+
+// String returns a base32 hex lowercased with no padding representation of the id (char set is 0-9, a-v).
+func (id ID) String() string {
+ text := make([]byte, encodedLen)
+ encode(text, id[:])
+ return string(text)
+}
+
+// Encode encodes the id using base32 encoding, writing 20 bytes to dst and return it.
+func (id ID) Encode(dst []byte) []byte {
+ encode(dst, id[:])
+ return dst
+}
+
+// MarshalText implements encoding/text TextMarshaler interface
+func (id ID) MarshalText() ([]byte, error) {
+ text := make([]byte, encodedLen)
+ encode(text, id[:])
+ return text, nil
+}
+
+// MarshalJSON implements encoding/json Marshaler interface
+func (id ID) MarshalJSON() ([]byte, error) {
+ if id.IsNil() {
+ return []byte("null"), nil
+ }
+ text := make([]byte, encodedLen+2)
+ encode(text[1:encodedLen+1], id[:])
+ text[0], text[encodedLen+1] = '"', '"'
+ return text, nil
+}
+
+// encode by unrolling the stdlib base32 algorithm + removing all safe checks
+func encode(dst, id []byte) {
+ _ = dst[19]
+ _ = id[11]
+
+ dst[19] = encoding[(id[11]<<4)&0x1F]
+ dst[18] = encoding[(id[11]>>1)&0x1F]
+ dst[17] = encoding[(id[11]>>6)|(id[10]<<2)&0x1F]
+ dst[16] = encoding[id[10]>>3]
+ dst[15] = encoding[id[9]&0x1F]
+ dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F]
+ dst[13] = encoding[(id[8]>>2)&0x1F]
+ dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F]
+ dst[11] = encoding[(id[7]>>4)|(id[6]<<4)&0x1F]
+ dst[10] = encoding[(id[6]>>1)&0x1F]
+ dst[9] = encoding[(id[6]>>6)|(id[5]<<2)&0x1F]
+ dst[8] = encoding[id[5]>>3]
+ dst[7] = encoding[id[4]&0x1F]
+ dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F]
+ dst[5] = encoding[(id[3]>>2)&0x1F]
+ dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F]
+ dst[3] = encoding[(id[2]>>4)|(id[1]<<4)&0x1F]
+ dst[2] = encoding[(id[1]>>1)&0x1F]
+ dst[1] = encoding[(id[1]>>6)|(id[0]<<2)&0x1F]
+ dst[0] = encoding[id[0]>>3]
+}
+
+// UnmarshalText implements encoding/text TextUnmarshaler interface
+func (id *ID) UnmarshalText(text []byte) error {
+ if len(text) != encodedLen {
+ return ErrInvalidID
+ }
+ for _, c := range text {
+ if dec[c] == 0xFF {
+ return ErrInvalidID
+ }
+ }
+ if !decode(id, text) {
+ *id = nilID
+ return ErrInvalidID
+ }
+ return nil
+}
+
+// UnmarshalJSON implements encoding/json Unmarshaler interface
+func (id *ID) UnmarshalJSON(b []byte) error {
+ s := string(b)
+ if s == "null" {
+ *id = nilID
+ return nil
+ }
+ // Check the slice length to prevent panic on passing it to UnmarshalText()
+ if len(b) < 2 {
+ return ErrInvalidID
+ }
+ return id.UnmarshalText(b[1 : len(b)-1])
+}
+
+// decode by unrolling the stdlib base32 algorithm + customized safe check.
+func decode(id *ID, src []byte) bool {
+ _ = src[19]
+ _ = id[11]
+
+ id[11] = dec[src[17]]<<6 | dec[src[18]]<<1 | dec[src[19]]>>4
+ // check the last byte
+ if encoding[(id[11]<<4)&0x1F] != src[19] {
+ return false
+ }
+ id[10] = dec[src[16]]<<3 | dec[src[17]]>>2
+ id[9] = dec[src[14]]<<5 | dec[src[15]]
+ id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3
+ id[7] = dec[src[11]]<<4 | dec[src[12]]>>1
+ id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4
+ id[5] = dec[src[8]]<<3 | dec[src[9]]>>2
+ id[4] = dec[src[6]]<<5 | dec[src[7]]
+ id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3
+ id[2] = dec[src[3]]<<4 | dec[src[4]]>>1
+ id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4
+ id[0] = dec[src[0]]<<3 | dec[src[1]]>>2
+ return true
+}
+
+// Time returns the timestamp part of the id.
+// It's a runtime error to call this method with an invalid id.
+func (id ID) Time() time.Time {
+ // First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch.
+ secs := int64(binary.BigEndian.Uint32(id[0:4]))
+ return time.Unix(secs, 0)
+}
+
+// Machine returns the 3-byte machine id part of the id.
+// It's a runtime error to call this method with an invalid id.
+func (id ID) Machine() []byte {
+ return id[4:7]
+}
+
+// Pid returns the process id part of the id.
+// It's a runtime error to call this method with an invalid id.
+func (id ID) Pid() uint16 {
+ return binary.BigEndian.Uint16(id[7:9])
+}
+
+// Counter returns the incrementing value part of the id.
+// It's a runtime error to call this method with an invalid id.
+func (id ID) Counter() int32 {
+ b := id[9:12]
+ // Counter is stored as big-endian 3-byte value
+ return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
+}
+
+// Value implements the driver.Valuer interface.
+func (id ID) Value() (driver.Value, error) {
+ if id.IsNil() {
+ return nil, nil
+ }
+ b, err := id.MarshalText()
+ return string(b), err
+}
+
+// Scan implements the sql.Scanner interface.
+func (id *ID) Scan(value interface{}) (err error) {
+ switch val := value.(type) {
+ case string:
+ return id.UnmarshalText([]byte(val))
+ case []byte:
+ return id.UnmarshalText(val)
+ case nil:
+ *id = nilID
+ return nil
+ default:
+ return fmt.Errorf("xid: scanning unsupported type: %T", value)
+ }
+}
+
+// IsNil Returns true if this is a "nil" ID
+func (id ID) IsNil() bool {
+ return id == nilID
+}
+
+// Alias of IsNil
+func (id ID) IsZero() bool {
+ return id.IsNil()
+}
+
+// NilID returns a zero value for `xid.ID`.
+func NilID() ID {
+ return nilID
+}
+
+// Bytes returns the byte array representation of `ID`
+func (id ID) Bytes() []byte {
+ return id[:]
+}
+
+// FromBytes convert the byte array representation of `ID` back to `ID`
+func FromBytes(b []byte) (ID, error) {
+ var id ID
+ if len(b) != rawLen {
+ return id, ErrInvalidID
+ }
+ copy(id[:], b)
+ return id, nil
+}
+
+// Compare returns an integer comparing two IDs. It behaves just like `bytes.Compare`.
+// The result will be 0 if two IDs are identical, -1 if current id is less than the other one,
+// and 1 if current id is greater than the other.
+func (id ID) Compare(other ID) int {
+ return bytes.Compare(id[:], other[:])
+}
+
+type sorter []ID
+
+func (s sorter) Len() int {
+ return len(s)
+}
+
+func (s sorter) Less(i, j int) bool {
+ return s[i].Compare(s[j]) < 0
+}
+
+func (s sorter) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+// Sort sorts an array of IDs inplace.
+// It works by wrapping `[]ID` and use `sort.Sort`.
+func Sort(ids []ID) {
+ sort.Sort(sorter(ids))
+}
diff --git a/vendor/github.com/rs/zerolog/diode/diode.go b/vendor/github.com/rs/zerolog/diode/diode.go
new file mode 100644
index 0000000..45a8910
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/diode/diode.go
@@ -0,0 +1,114 @@
+// Package diode provides a thread-safe, lock-free, non-blocking io.Writer
+// wrapper.
+package diode
+
+import (
+ "context"
+ "io"
+ "sync"
+ "time"
+
+ "github.com/rs/zerolog/diode/internal/diodes"
+)
+
+var bufPool = &sync.Pool{
+ New: func() interface{} {
+ return make([]byte, 0, 500)
+ },
+}
+
+type Alerter func(missed int)
+
+type diodeFetcher interface {
+ diodes.Diode
+ Next() diodes.GenericDataType
+}
+
+// Writer is a io.Writer wrapper that uses a diode to make Write lock-free,
+// non-blocking and thread safe.
+type Writer struct {
+ w io.Writer
+ d diodeFetcher
+ c context.CancelFunc
+ done chan struct{}
+}
+
+// NewWriter creates a writer wrapping w with a many-to-one diode in order to
+// never block log producers and drop events if the writer can't keep up with
+// the flow of data.
+//
+// Use a diode.Writer when
+//
+// wr := diode.NewWriter(w, 1000, 0, func(missed int) {
+// log.Printf("Dropped %d messages", missed)
+// })
+// log := zerolog.New(wr)
+//
+// If pollInterval is greater than 0, a poller is used otherwise a waiter is
+// used.
+//
+// See code.cloudfoundry.org/go-diodes for more info on diode.
+func NewWriter(w io.Writer, size int, pollInterval time.Duration, f Alerter) Writer {
+ ctx, cancel := context.WithCancel(context.Background())
+ dw := Writer{
+ w: w,
+ c: cancel,
+ done: make(chan struct{}),
+ }
+ if f == nil {
+ f = func(int) {}
+ }
+ d := diodes.NewManyToOne(size, diodes.AlertFunc(f))
+ if pollInterval > 0 {
+ dw.d = diodes.NewPoller(d,
+ diodes.WithPollingInterval(pollInterval),
+ diodes.WithPollingContext(ctx))
+ } else {
+ dw.d = diodes.NewWaiter(d,
+ diodes.WithWaiterContext(ctx))
+ }
+ go dw.poll()
+ return dw
+}
+
+func (dw Writer) Write(p []byte) (n int, err error) {
+ // p is pooled in zerolog so we can't hold it passed this call, hence the
+ // copy.
+ p = append(bufPool.Get().([]byte), p...)
+ dw.d.Set(diodes.GenericDataType(&p))
+ return len(p), nil
+}
+
+// Close releases the diode poller and call Close on the wrapped writer if
+// io.Closer is implemented.
+func (dw Writer) Close() error {
+ dw.c()
+ <-dw.done
+ if w, ok := dw.w.(io.Closer); ok {
+ return w.Close()
+ }
+ return nil
+}
+
+func (dw Writer) poll() {
+ defer close(dw.done)
+ for {
+ d := dw.d.Next()
+ if d == nil {
+ return
+ }
+ p := *(*[]byte)(d)
+ dw.w.Write(p)
+
+ // Proper usage of a sync.Pool requires each entry to have approximately
+ // the same memory cost. To obtain this property when the stored type
+ // contains a variably-sized buffer, we add a hard limit on the maximum buffer
+ // to place back in the pool.
+ //
+ // See https://golang.org/issue/23199
+ const maxSize = 1 << 16 // 64KiB
+ if cap(p) <= maxSize {
+ bufPool.Put(p[:0])
+ }
+ }
+}
diff --git a/vendor/github.com/rs/zerolog/diode/internal/diodes/README b/vendor/github.com/rs/zerolog/diode/internal/diodes/README
new file mode 100644
index 0000000..6c4ec5f
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/diode/internal/diodes/README
@@ -0,0 +1 @@
+Copied from https://github.com/cloudfoundry/go-diodes to avoid test dependencies.
diff --git a/vendor/github.com/rs/zerolog/diode/internal/diodes/many_to_one.go b/vendor/github.com/rs/zerolog/diode/internal/diodes/many_to_one.go
new file mode 100644
index 0000000..477eddd
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/diode/internal/diodes/many_to_one.go
@@ -0,0 +1,130 @@
+package diodes
+
+import (
+ "log"
+ "sync/atomic"
+ "unsafe"
+)
+
+// ManyToOne diode is optimal for many writers (go-routines B-n) and a single
+// reader (go-routine A). It is not thread safe for multiple readers.
+type ManyToOne struct {
+ writeIndex uint64
+ readIndex uint64
+ buffer []unsafe.Pointer
+ alerter Alerter
+}
+
+// NewManyToOne creates a new diode (ring buffer). The ManyToOne diode
+// is optimized for many writers (on go-routines B-n) and a single reader
+// (on go-routine A). The alerter is invoked on the read's go-routine. It is
+// called when it notices that the writer go-routine has passed it and wrote
+// over data. A nil can be used to ignore alerts.
+func NewManyToOne(size int, alerter Alerter) *ManyToOne {
+ if alerter == nil {
+ alerter = AlertFunc(func(int) {})
+ }
+
+ d := &ManyToOne{
+ buffer: make([]unsafe.Pointer, size),
+ alerter: alerter,
+ }
+
+ // Start write index at the value before 0
+ // to allow the first write to use AddUint64
+ // and still have a beginning index of 0
+ d.writeIndex = ^d.writeIndex
+ return d
+}
+
+// Set sets the data in the next slot of the ring buffer.
+func (d *ManyToOne) Set(data GenericDataType) {
+ for {
+ writeIndex := atomic.AddUint64(&d.writeIndex, 1)
+ idx := writeIndex % uint64(len(d.buffer))
+ old := atomic.LoadPointer(&d.buffer[idx])
+
+ if old != nil &&
+ (*bucket)(old) != nil &&
+ (*bucket)(old).seq > writeIndex-uint64(len(d.buffer)) {
+ log.Println("Diode set collision: consider using a larger diode")
+ continue
+ }
+
+ newBucket := &bucket{
+ data: data,
+ seq: writeIndex,
+ }
+
+ if !atomic.CompareAndSwapPointer(&d.buffer[idx], old, unsafe.Pointer(newBucket)) {
+ log.Println("Diode set collision: consider using a larger diode")
+ continue
+ }
+
+ return
+ }
+}
+
+// TryNext will attempt to read from the next slot of the ring buffer.
+// If there is no data available, it will return (nil, false).
+func (d *ManyToOne) TryNext() (data GenericDataType, ok bool) {
+ // Read a value from the ring buffer based on the readIndex.
+ idx := d.readIndex % uint64(len(d.buffer))
+ result := (*bucket)(atomic.SwapPointer(&d.buffer[idx], nil))
+
+ // When the result is nil that means the writer has not had the
+ // opportunity to write a value into the diode. This value must be ignored
+ // and the read head must not increment.
+ if result == nil {
+ return nil, false
+ }
+
+ // When the seq value is less than the current read index that means a
+ // value was read from idx that was previously written but since has
+ // been dropped. This value must be ignored and the read head must not
+ // increment.
+ //
+ // The simulation for this scenario assumes the fast forward occurred as
+ // detailed below.
+ //
+ // 5. The reader reads again getting seq 5. It then reads again expecting
+ // seq 6 but gets seq 2. This is a read of a stale value that was
+ // effectively "dropped" so the read fails and the read head stays put.
+ // `| 4 | 5 | 2 | 3 |` r: 7, w: 6
+ //
+ if result.seq < d.readIndex {
+ return nil, false
+ }
+
+ // When the seq value is greater than the current read index that means a
+ // value was read from idx that overwrote the value that was expected to
+ // be at this idx. This happens when the writer has lapped the reader. The
+ // reader needs to catch up to the writer so it moves its write head to
+ // the new seq, effectively dropping the messages that were not read in
+ // between the two values.
+ //
+ // Here is a simulation of this scenario:
+ //
+ // 1. Both the read and write heads start at 0.
+ // `| nil | nil | nil | nil |` r: 0, w: 0
+ // 2. The writer fills the buffer.
+ // `| 0 | 1 | 2 | 3 |` r: 0, w: 4
+ // 3. The writer laps the read head.
+ // `| 4 | 5 | 2 | 3 |` r: 0, w: 6
+ // 4. The reader reads the first value, expecting a seq of 0 but reads 4,
+ // this forces the reader to fast forward to 5.
+ // `| 4 | 5 | 2 | 3 |` r: 5, w: 6
+ //
+ if result.seq > d.readIndex {
+ dropped := result.seq - d.readIndex
+ d.readIndex = result.seq
+ d.alerter.Alert(int(dropped))
+ }
+
+ // Only increment read index if a regular read occurred (where seq was
+ // equal to readIndex) or a value was read that caused a fast forward
+ // (where seq was greater than readIndex).
+ //
+ d.readIndex++
+ return result.data, true
+}
diff --git a/vendor/github.com/rs/zerolog/diode/internal/diodes/one_to_one.go b/vendor/github.com/rs/zerolog/diode/internal/diodes/one_to_one.go
new file mode 100644
index 0000000..6c454eb
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/diode/internal/diodes/one_to_one.go
@@ -0,0 +1,129 @@
+package diodes
+
+import (
+ "sync/atomic"
+ "unsafe"
+)
+
+// GenericDataType is the data type the diodes operate on.
+type GenericDataType unsafe.Pointer
+
+// Alerter is used to report how many values were overwritten since the
+// last write.
+type Alerter interface {
+ Alert(missed int)
+}
+
+// AlertFunc type is an adapter to allow the use of ordinary functions as
+// Alert handlers.
+type AlertFunc func(missed int)
+
+// Alert calls f(missed)
+func (f AlertFunc) Alert(missed int) {
+ f(missed)
+}
+
+type bucket struct {
+ data GenericDataType
+ seq uint64 // seq is the recorded write index at the time of writing
+}
+
+// OneToOne diode is meant to be used by a single reader and a single writer.
+// It is not thread safe if used otherwise.
+type OneToOne struct {
+ writeIndex uint64
+ readIndex uint64
+ buffer []unsafe.Pointer
+ alerter Alerter
+}
+
+// NewOneToOne creates a new diode is meant to be used by a single reader and
+// a single writer. The alerter is invoked on the read's go-routine. It is
+// called when it notices that the writer go-routine has passed it and wrote
+// over data. A nil can be used to ignore alerts.
+func NewOneToOne(size int, alerter Alerter) *OneToOne {
+ if alerter == nil {
+ alerter = AlertFunc(func(int) {})
+ }
+
+ return &OneToOne{
+ buffer: make([]unsafe.Pointer, size),
+ alerter: alerter,
+ }
+}
+
+// Set sets the data in the next slot of the ring buffer.
+func (d *OneToOne) Set(data GenericDataType) {
+ idx := d.writeIndex % uint64(len(d.buffer))
+
+ newBucket := &bucket{
+ data: data,
+ seq: d.writeIndex,
+ }
+ d.writeIndex++
+
+ atomic.StorePointer(&d.buffer[idx], unsafe.Pointer(newBucket))
+}
+
+// TryNext will attempt to read from the next slot of the ring buffer.
+// If there is no data available, it will return (nil, false).
+func (d *OneToOne) TryNext() (data GenericDataType, ok bool) {
+ // Read a value from the ring buffer based on the readIndex.
+ idx := d.readIndex % uint64(len(d.buffer))
+ result := (*bucket)(atomic.SwapPointer(&d.buffer[idx], nil))
+
+ // When the result is nil that means the writer has not had the
+ // opportunity to write a value into the diode. This value must be ignored
+ // and the read head must not increment.
+ if result == nil {
+ return nil, false
+ }
+
+ // When the seq value is less than the current read index that means a
+ // value was read from idx that was previously written but since has
+ // been dropped. This value must be ignored and the read head must not
+ // increment.
+ //
+ // The simulation for this scenario assumes the fast forward occurred as
+ // detailed below.
+ //
+ // 5. The reader reads again getting seq 5. It then reads again expecting
+ // seq 6 but gets seq 2. This is a read of a stale value that was
+ // effectively "dropped" so the read fails and the read head stays put.
+ // `| 4 | 5 | 2 | 3 |` r: 7, w: 6
+ //
+ if result.seq < d.readIndex {
+ return nil, false
+ }
+
+ // When the seq value is greater than the current read index that means a
+ // value was read from idx that overwrote the value that was expected to
+ // be at this idx. This happens when the writer has lapped the reader. The
+ // reader needs to catch up to the writer so it moves its write head to
+ // the new seq, effectively dropping the messages that were not read in
+ // between the two values.
+ //
+ // Here is a simulation of this scenario:
+ //
+ // 1. Both the read and write heads start at 0.
+ // `| nil | nil | nil | nil |` r: 0, w: 0
+ // 2. The writer fills the buffer.
+ // `| 0 | 1 | 2 | 3 |` r: 0, w: 4
+ // 3. The writer laps the read head.
+ // `| 4 | 5 | 2 | 3 |` r: 0, w: 6
+ // 4. The reader reads the first value, expecting a seq of 0 but reads 4,
+ // this forces the reader to fast forward to 5.
+ // `| 4 | 5 | 2 | 3 |` r: 5, w: 6
+ //
+ if result.seq > d.readIndex {
+ dropped := result.seq - d.readIndex
+ d.readIndex = result.seq
+ d.alerter.Alert(int(dropped))
+ }
+
+ // Only increment read index if a regular read occurred (where seq was
+ // equal to readIndex) or a value was read that caused a fast forward
+ // (where seq was greater than readIndex).
+ d.readIndex++
+ return result.data, true
+}
diff --git a/vendor/github.com/rs/zerolog/diode/internal/diodes/poller.go b/vendor/github.com/rs/zerolog/diode/internal/diodes/poller.go
new file mode 100644
index 0000000..dc51fd7
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/diode/internal/diodes/poller.go
@@ -0,0 +1,80 @@
+package diodes
+
+import (
+ "context"
+ "time"
+)
+
+// Diode is any implementation of a diode.
+type Diode interface {
+ Set(GenericDataType)
+ TryNext() (GenericDataType, bool)
+}
+
+// Poller will poll a diode until a value is available.
+type Poller struct {
+ Diode
+ interval time.Duration
+ ctx context.Context
+}
+
+// PollerConfigOption can be used to setup the poller.
+type PollerConfigOption func(*Poller)
+
+// WithPollingInterval sets the interval at which the diode is queried
+// for new data. The default is 10ms.
+func WithPollingInterval(interval time.Duration) PollerConfigOption {
+ return func(c *Poller) {
+ c.interval = interval
+ }
+}
+
+// WithPollingContext sets the context to cancel any retrieval (Next()). It
+// will not change any results for adding data (Set()). Default is
+// context.Background().
+func WithPollingContext(ctx context.Context) PollerConfigOption {
+ return func(c *Poller) {
+ c.ctx = ctx
+ }
+}
+
+// NewPoller returns a new Poller that wraps the given diode.
+func NewPoller(d Diode, opts ...PollerConfigOption) *Poller {
+ p := &Poller{
+ Diode: d,
+ interval: 10 * time.Millisecond,
+ ctx: context.Background(),
+ }
+
+ for _, o := range opts {
+ o(p)
+ }
+
+ return p
+}
+
+// Next polls the diode until data is available or until the context is done.
+// If the context is done, then nil will be returned.
+func (p *Poller) Next() GenericDataType {
+ for {
+ data, ok := p.Diode.TryNext()
+ if !ok {
+ if p.isDone() {
+ return nil
+ }
+
+ time.Sleep(p.interval)
+ continue
+ }
+ return data
+ }
+}
+
+func (p *Poller) isDone() bool {
+ select {
+ case <-p.ctx.Done():
+ return true
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/rs/zerolog/diode/internal/diodes/waiter.go b/vendor/github.com/rs/zerolog/diode/internal/diodes/waiter.go
new file mode 100644
index 0000000..a4a8e97
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/diode/internal/diodes/waiter.go
@@ -0,0 +1,88 @@
+package diodes
+
+import (
+ "context"
+ "sync"
+)
+
+// Waiter will use a conditional mutex to alert the reader to when data is
+// available.
+type Waiter struct {
+ Diode
+ mu sync.Mutex
+ c *sync.Cond
+ ctx context.Context
+}
+
+// WaiterConfigOption can be used to setup the waiter.
+type WaiterConfigOption func(*Waiter)
+
+// WithWaiterContext sets the context to cancel any retrieval (Next()). It
+// will not change any results for adding data (Set()). Default is
+// context.Background().
+func WithWaiterContext(ctx context.Context) WaiterConfigOption {
+ return func(c *Waiter) {
+ c.ctx = ctx
+ }
+}
+
+// NewWaiter returns a new Waiter that wraps the given diode.
+func NewWaiter(d Diode, opts ...WaiterConfigOption) *Waiter {
+ w := new(Waiter)
+ w.Diode = d
+ w.c = sync.NewCond(&w.mu)
+ w.ctx = context.Background()
+
+ for _, opt := range opts {
+ opt(w)
+ }
+
+ go func() {
+ <-w.ctx.Done()
+
+ // Mutex is strictly necessary here to avoid a race in Next() (between
+ // w.isDone() and w.c.Wait()) and w.c.Broadcast() here.
+ w.mu.Lock()
+ w.c.Broadcast()
+ w.mu.Unlock()
+ }()
+
+ return w
+}
+
+// Set invokes the wrapped diode's Set with the given data and uses Broadcast
+// to wake up any readers.
+func (w *Waiter) Set(data GenericDataType) {
+ w.Diode.Set(data)
+ w.c.Broadcast()
+}
+
+// Next returns the next data point on the wrapped diode. If there is not any
+// new data, it will Wait for set to be called or the context to be done.
+// If the context is done, then nil will be returned.
+func (w *Waiter) Next() GenericDataType {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+
+ for {
+ data, ok := w.Diode.TryNext()
+ if !ok {
+ if w.isDone() {
+ return nil
+ }
+
+ w.c.Wait()
+ continue
+ }
+ return data
+ }
+}
+
+func (w *Waiter) isDone() bool {
+ select {
+ case <-w.ctx.Done():
+ return true
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/rs/zerolog/log/log.go b/vendor/github.com/rs/zerolog/log/log.go
new file mode 100644
index 0000000..a96ec50
--- /dev/null
+++ b/vendor/github.com/rs/zerolog/log/log.go
@@ -0,0 +1,131 @@
+// Package log provides a global logger for zerolog.
+package log
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/rs/zerolog"
+)
+
+// Logger is the global logger.
+var Logger = zerolog.New(os.Stderr).With().Timestamp().Logger()
+
+// Output duplicates the global logger and sets w as its output.
+func Output(w io.Writer) zerolog.Logger {
+ return Logger.Output(w)
+}
+
+// With creates a child logger with the field added to its context.
+func With() zerolog.Context {
+ return Logger.With()
+}
+
+// Level creates a child logger with the minimum accepted level set to level.
+func Level(level zerolog.Level) zerolog.Logger {
+ return Logger.Level(level)
+}
+
+// Sample returns a logger with the s sampler.
+func Sample(s zerolog.Sampler) zerolog.Logger {
+ return Logger.Sample(s)
+}
+
+// Hook returns a logger with the h Hook.
+func Hook(h zerolog.Hook) zerolog.Logger {
+ return Logger.Hook(h)
+}
+
+// Err starts a new message with error level with err as a field if not nil or
+// with info level if err is nil.
+//
+// You must call Msg on the returned event in order to send the event.
+func Err(err error) *zerolog.Event {
+ return Logger.Err(err)
+}
+
+// Trace starts a new message with trace level.
+//
+// You must call Msg on the returned event in order to send the event.
+func Trace() *zerolog.Event {
+ return Logger.Trace()
+}
+
+// Debug starts a new message with debug level.
+//
+// You must call Msg on the returned event in order to send the event.
+func Debug() *zerolog.Event {
+ return Logger.Debug()
+}
+
+// Info starts a new message with info level.
+//
+// You must call Msg on the returned event in order to send the event.
+func Info() *zerolog.Event {
+ return Logger.Info()
+}
+
+// Warn starts a new message with warn level.
+//
+// You must call Msg on the returned event in order to send the event.
+func Warn() *zerolog.Event {
+ return Logger.Warn()
+}
+
+// Error starts a new message with error level.
+//
+// You must call Msg on the returned event in order to send the event.
+func Error() *zerolog.Event {
+ return Logger.Error()
+}
+
+// Fatal starts a new message with fatal level. The os.Exit(1) function
+// is called by the Msg method.
+//
+// You must call Msg on the returned event in order to send the event.
+func Fatal() *zerolog.Event {
+ return Logger.Fatal()
+}
+
+// Panic starts a new message with panic level. The message is also sent
+// to the panic function.
+//
+// You must call Msg on the returned event in order to send the event.
+func Panic() *zerolog.Event {
+ return Logger.Panic()
+}
+
+// WithLevel starts a new message with level.
+//
+// You must call Msg on the returned event in order to send the event.
+func WithLevel(level zerolog.Level) *zerolog.Event {
+ return Logger.WithLevel(level)
+}
+
+// Log starts a new message with no level. Setting zerolog.GlobalLevel to
+// zerolog.Disabled will still disable events produced by this method.
+//
+// You must call Msg on the returned event in order to send the event.
+func Log() *zerolog.Event {
+ return Logger.Log()
+}
+
+// Print sends a log event using debug level and no extra field.
+// Arguments are handled in the manner of fmt.Print.
+func Print(v ...interface{}) {
+ Logger.Debug().CallerSkipFrame(1).Msg(fmt.Sprint(v...))
+}
+
+// Printf sends a log event using debug level and no extra field.
+// Arguments are handled in the manner of fmt.Printf.
+func Printf(format string, v ...interface{}) {
+ Logger.Debug().CallerSkipFrame(1).Msgf(format, v...)
+}
+
+// Ctx returns the Logger associated with the ctx. If no logger
+// is associated, a disabled logger is returned.
+func Ctx(ctx context.Context) *zerolog.Logger {
+ return zerolog.Ctx(ctx)
+}