Skip to content

Commit

Permalink
Better Timestamp (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
cristaloleg authored Dec 8, 2023
1 parent 7ed3654 commit 534806c
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 10 deletions.
66 changes: 58 additions & 8 deletions timestamp.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package bson

import (
"encoding/binary"
"encoding"
"encoding/json"
"errors"
"fmt"
"sync/atomic"
"time"
)

var (
_ Marshaler = Timestamp(0)
_ Unmarshaler = new(Timestamp)
)

// Timestamp represents BSON type Timestamp.
type Timestamp int64

Expand All @@ -33,7 +30,7 @@ func NewTimestampWithCounter(t time.Time, c uint32) Timestamp {
}

// String returns a hex string representation of the id.
// Example: Timestamp('64d526fa37931c1e97eea90f').
// Example: Timestamp('4398046513152, 1024').
func (ts Timestamp) String() string {
return fmt.Sprintf(`Timestamp(%d, %d)`, ts, ts>>32)
}
Expand All @@ -48,6 +45,7 @@ func (ts Timestamp) Counter() uint32 {
return uint32(ts)
}

// MarshalBSON implements [Marshaler].
func (ts Timestamp) MarshalBSON() ([]byte, error) {
var b [8]byte
b[0] = byte(ts)
Expand All @@ -61,10 +59,62 @@ func (ts Timestamp) MarshalBSON() ([]byte, error) {
return b[:], nil
}

// UnmarshalBSON implements [Unmarshaler].
func (ts *Timestamp) UnmarshalBSON(b []byte) error {
v := binary.LittleEndian.Uint64(b)
if len(b) < 8 {
return errors.New("not enough bytes for timestamp")
}
v := uint64(b[0]) |
uint64(b[1])<<8 |
uint64(b[2])<<16 |
uint64(b[3])<<24 |
uint64(b[4])<<32 |
uint64(b[5])<<40 |
uint64(b[6])<<48 |
uint64(b[7])<<56
*ts = Timestamp(v)
return nil
}

// MarshalText implements [encoding.TextMarshaler].
func (ts Timestamp) MarshalText() ([]byte, error) {
return ts.MarshalBSON()
}

// UnmarshalText implements [encoding.TextUnmarshaler].
func (ts *Timestamp) UnmarshalText(b []byte) error {
return ts.UnmarshalBSON(b)
}

// MarshalBinary implements [encoding.BinaryMarshaler].
func (ts Timestamp) MarshalBinary() ([]byte, error) {
return ts.MarshalBSON()
}

// UnmarshalBinary implements [encoding.BinaryUnmarshaler].
func (ts *Timestamp) UnmarshalBinary(b []byte) error {
return ts.UnmarshalBSON(b)
}

// MarshalJSON implements [json.Marshaler].
func (ts Timestamp) MarshalJSON() ([]byte, error) {
return ts.MarshalBSON()
}

// UnmarshalJSON implements [json.Unmarshaler].
func (ts *Timestamp) UnmarshalJSON(b []byte) error {
return ts.UnmarshalBSON(b)
}

var timestampCounter atomic.Uint32

var (
_ Marshaler = Timestamp(0)
_ Unmarshaler = new(Timestamp)
_ encoding.TextMarshaler = Timestamp(0)
_ encoding.TextUnmarshaler = new(Timestamp)
_ encoding.BinaryMarshaler = Timestamp(0)
_ encoding.BinaryUnmarshaler = new(Timestamp)
_ json.Marshaler = Timestamp(0)
_ json.Unmarshaler = new(Timestamp)
)
4 changes: 2 additions & 2 deletions timestamp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package bson
import "testing"

func TestTimestamp(t *testing.T) {
ts := Timestamp(4294967298)
ts := Timestamp(4294967298 << 10)

mustEqual(t, ts.String(), "Timestamp(4294967298, 1)")
mustEqual(t, ts.String(), "Timestamp(4398046513152, 1024)")
}

0 comments on commit 534806c

Please sign in to comment.