Codebase list golang-github-gofrs-uuid / fresh-releases/main
New upstream release. Debian Janitor 11 months ago
13 changed file(s) with 825 addition(s) and 306 deletion(s). Raw diff Collapse all Expand all
2121
2222 - name: Check out code into the Go module directory
2323 uses: actions/checkout@v2
24
25 - name: Get Coverage
26 run: go get golang.org/x/tools/cmd/cover
2724
2825 - name: Build
2926 run: go build -v ./...
1616 * Version 5, based on SHA-1 hashing of a named value (RFC-4122)
1717
1818 This package also supports experimental Universally Unique Identifier implementations based on a
19 [draft RFC](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03) that updates RFC-4122
19 [draft RFC](https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html) that updates RFC-4122
2020 * Version 6, a k-sortable id based on timestamp, and field-compatible with v1 (draft-peabody-dispatch-new-uuid-format, RFC-4122)
2121 * Version 7, a k-sortable id based on timestamp (draft-peabody-dispatch-new-uuid-format, RFC-4122)
2222
4747 created before our fork of the original package and have some known
4848 deficiencies.
4949
50 ## Installation
51
52 It is recommended to use a package manager like `dep` that understands tagged
53 releases of a package, as well as semantic versioning.
54
55 If you are unable to make use of a dependency manager with your project, you can
56 use the `go get` command to download it directly:
57
58 ```Shell
59 $ go get github.com/gofrs/uuid
60 ```
61
6250 ## Requirements
6351
64 Due to subtests not being supported in older versions of Go, this package is
65 only regularly tested against Go 1.7+. This package may work perfectly fine with
66 Go 1.2+, but support for these older versions is not actively maintained.
67
68 ## Go 1.11 Modules
69
70 As of v3.2.0, this repository no longer adopts Go modules, and v3.2.0 no longer has a `go.mod` file. As a result, v3.2.0 also drops support for the `github.com/gofrs/uuid/v3` import path. Only module-based consumers are impacted. With the v3.2.0 release, _all_ gofrs/uuid consumers should use the `github.com/gofrs/uuid` import path.
71
72 An existing module-based consumer will continue to be able to build using the `github.com/gofrs/uuid/v3` import path using any valid consumer `go.mod` that worked prior to the publishing of v3.2.0, but any module-based consumer should start using the `github.com/gofrs/uuid` import path when possible and _must_ use the `github.com/gofrs/uuid` import path prior to upgrading to v3.2.0.
73
74 Please refer to [Issue #61](https://github.com/gofrs/uuid/issues/61) and [Issue #66](https://github.com/gofrs/uuid/issues/66) for more details.
52 This package requres Go 1.17 or later
7553
7654 ## Usage
7755
11391
11492 * [RFC-4122](https://tools.ietf.org/html/rfc4122)
11593 * [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
116 * [New UUID Formats RFC Draft (Peabody) Rev 03](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03)
94 * [New UUID Formats RFC Draft (Peabody) Rev 04](https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#)
+142
-120
codec.go less more
2121 package uuid
2222
2323 import (
24 "bytes"
25 "encoding/hex"
24 "errors"
2625 "fmt"
2726 )
2827
4443 return uuid
4544 }
4645
46 var errInvalidFormat = errors.New("uuid: invalid UUID format")
47
48 func fromHexChar(c byte) byte {
49 switch {
50 case '0' <= c && c <= '9':
51 return c - '0'
52 case 'a' <= c && c <= 'f':
53 return c - 'a' + 10
54 case 'A' <= c && c <= 'F':
55 return c - 'A' + 10
56 }
57 return 255
58 }
59
60 // Parse parses the UUID stored in the string text. Parsing and supported
61 // formats are the same as UnmarshalText.
62 func (u *UUID) Parse(s string) error {
63 switch len(s) {
64 case 32: // hash
65 case 36: // canonical
66 case 34, 38:
67 if s[0] != '{' || s[len(s)-1] != '}' {
68 return fmt.Errorf("uuid: incorrect UUID format in string %q", s)
69 }
70 s = s[1 : len(s)-1]
71 case 41, 45:
72 if s[:9] != "urn:uuid:" {
73 return fmt.Errorf("uuid: incorrect UUID format in string %q", s[:9])
74 }
75 s = s[9:]
76 default:
77 return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(s), s)
78 }
79 // canonical
80 if len(s) == 36 {
81 if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
82 return fmt.Errorf("uuid: incorrect UUID format in string %q", s)
83 }
84 for i, x := range [16]byte{
85 0, 2, 4, 6,
86 9, 11,
87 14, 16,
88 19, 21,
89 24, 26, 28, 30, 32, 34,
90 } {
91 v1 := fromHexChar(s[x])
92 v2 := fromHexChar(s[x+1])
93 if v1|v2 == 255 {
94 return errInvalidFormat
95 }
96 u[i] = (v1 << 4) | v2
97 }
98 return nil
99 }
100 // hash like
101 for i := 0; i < 32; i += 2 {
102 v1 := fromHexChar(s[i])
103 v2 := fromHexChar(s[i+1])
104 if v1|v2 == 255 {
105 return errInvalidFormat
106 }
107 u[i/2] = (v1 << 4) | v2
108 }
109 return nil
110 }
111
47112 // FromString returns a UUID parsed from the input string.
48113 // Input is expected in a form accepted by UnmarshalText.
49 func FromString(input string) (UUID, error) {
50 u := UUID{}
51 err := u.UnmarshalText([]byte(input))
114 func FromString(text string) (UUID, error) {
115 var u UUID
116 err := u.Parse(text)
52117 return u, err
53118 }
54119
65130 // MarshalText implements the encoding.TextMarshaler interface.
66131 // The encoding is the same as returned by the String() method.
67132 func (u UUID) MarshalText() ([]byte, error) {
68 return []byte(u.String()), nil
133 var buf [36]byte
134 encodeCanonical(buf[:], u)
135 return buf[:], nil
69136 }
70137
71138 // UnmarshalText implements the encoding.TextUnmarshaler interface.
72139 // Following formats are supported:
73140 //
74 // "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
75 // "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
76 // "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
77 // "6ba7b8109dad11d180b400c04fd430c8"
78 // "{6ba7b8109dad11d180b400c04fd430c8}",
79 // "urn:uuid:6ba7b8109dad11d180b400c04fd430c8"
141 // "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
142 // "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
143 // "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
144 // "6ba7b8109dad11d180b400c04fd430c8"
145 // "{6ba7b8109dad11d180b400c04fd430c8}",
146 // "urn:uuid:6ba7b8109dad11d180b400c04fd430c8"
80147 //
81148 // ABNF for supported UUID text representation follows:
82149 //
83 // URN := 'urn'
84 // UUID-NID := 'uuid'
85 //
86 // hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
87 // 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
88 // 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
89 //
90 // hexoct := hexdig hexdig
91 // 2hexoct := hexoct hexoct
92 // 4hexoct := 2hexoct 2hexoct
93 // 6hexoct := 4hexoct 2hexoct
94 // 12hexoct := 6hexoct 6hexoct
95 //
96 // hashlike := 12hexoct
97 // canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
98 //
99 // plain := canonical | hashlike
100 // uuid := canonical | hashlike | braced | urn
101 //
102 // braced := '{' plain '}' | '{' hashlike '}'
103 // urn := URN ':' UUID-NID ':' plain
104 //
105 func (u *UUID) UnmarshalText(text []byte) error {
106 switch len(text) {
107 case 32:
108 return u.decodeHashLike(text)
150 // URN := 'urn'
151 // UUID-NID := 'uuid'
152 //
153 // hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
154 // 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
155 // 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
156 //
157 // hexoct := hexdig hexdig
158 // 2hexoct := hexoct hexoct
159 // 4hexoct := 2hexoct 2hexoct
160 // 6hexoct := 4hexoct 2hexoct
161 // 12hexoct := 6hexoct 6hexoct
162 //
163 // hashlike := 12hexoct
164 // canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
165 //
166 // plain := canonical | hashlike
167 // uuid := canonical | hashlike | braced | urn
168 //
169 // braced := '{' plain '}' | '{' hashlike '}'
170 // urn := URN ':' UUID-NID ':' plain
171 func (u *UUID) UnmarshalText(b []byte) error {
172 switch len(b) {
173 case 32: // hash
174 case 36: // canonical
109175 case 34, 38:
110 return u.decodeBraced(text)
111 case 36:
112 return u.decodeCanonical(text)
176 if b[0] != '{' || b[len(b)-1] != '}' {
177 return fmt.Errorf("uuid: incorrect UUID format in string %q", b)
178 }
179 b = b[1 : len(b)-1]
113180 case 41, 45:
114 return u.decodeURN(text)
181 if string(b[:9]) != "urn:uuid:" {
182 return fmt.Errorf("uuid: incorrect UUID format in string %q", b[:9])
183 }
184 b = b[9:]
115185 default:
116 return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(text), text)
117 }
118 }
119
120 // decodeCanonical decodes UUID strings that are formatted as defined in RFC-4122 (section 3):
121 // "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
122 func (u *UUID) decodeCanonical(t []byte) error {
123 if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' {
124 return fmt.Errorf("uuid: incorrect UUID format in string %q", t)
125 }
126
127 src := t
128 dst := u[:]
129
130 for i, byteGroup := range byteGroups {
131 if i > 0 {
132 src = src[1:] // skip dash
133 }
134 _, err := hex.Decode(dst[:byteGroup/2], src[:byteGroup])
135 if err != nil {
136 return err
137 }
138 src = src[byteGroup:]
139 dst = dst[byteGroup/2:]
140 }
141
186 return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(b), b)
187 }
188 if len(b) == 36 {
189 if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
190 return fmt.Errorf("uuid: incorrect UUID format in string %q", b)
191 }
192 for i, x := range [16]byte{
193 0, 2, 4, 6,
194 9, 11,
195 14, 16,
196 19, 21,
197 24, 26, 28, 30, 32, 34,
198 } {
199 v1 := fromHexChar(b[x])
200 v2 := fromHexChar(b[x+1])
201 if v1|v2 == 255 {
202 return errInvalidFormat
203 }
204 u[i] = (v1 << 4) | v2
205 }
206 return nil
207 }
208 for i := 0; i < 32; i += 2 {
209 v1 := fromHexChar(b[i])
210 v2 := fromHexChar(b[i+1])
211 if v1|v2 == 255 {
212 return errInvalidFormat
213 }
214 u[i/2] = (v1 << 4) | v2
215 }
142216 return nil
143 }
144
145 // decodeHashLike decodes UUID strings that are using the following format:
146 // "6ba7b8109dad11d180b400c04fd430c8".
147 func (u *UUID) decodeHashLike(t []byte) error {
148 src := t[:]
149 dst := u[:]
150
151 _, err := hex.Decode(dst, src)
152 return err
153 }
154
155 // decodeBraced decodes UUID strings that are using the following formats:
156 // "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}"
157 // "{6ba7b8109dad11d180b400c04fd430c8}".
158 func (u *UUID) decodeBraced(t []byte) error {
159 l := len(t)
160
161 if t[0] != '{' || t[l-1] != '}' {
162 return fmt.Errorf("uuid: incorrect UUID format in string %q", t)
163 }
164
165 return u.decodePlain(t[1 : l-1])
166 }
167
168 // decodeURN decodes UUID strings that are using the following formats:
169 // "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
170 // "urn:uuid:6ba7b8109dad11d180b400c04fd430c8".
171 func (u *UUID) decodeURN(t []byte) error {
172 total := len(t)
173
174 urnUUIDPrefix := t[:9]
175
176 if !bytes.Equal(urnUUIDPrefix, urnPrefix) {
177 return fmt.Errorf("uuid: incorrect UUID format in string %q", t)
178 }
179
180 return u.decodePlain(t[9:total])
181 }
182
183 // decodePlain decodes UUID strings that are using the following formats:
184 // "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format
185 // "6ba7b8109dad11d180b400c04fd430c8".
186 func (u *UUID) decodePlain(t []byte) error {
187 switch len(t) {
188 case 32:
189 return u.decodeHashLike(t)
190 case 36:
191 return u.decodeCanonical(t)
192 default:
193 return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(t), t)
194 }
195217 }
196218
197219 // MarshalBinary implements the encoding.BinaryMarshaler interface.
2727 "io/ioutil"
2828 "os"
2929 "path/filepath"
30 "strings"
3031 "testing"
3132 )
3233
8990 }
9091
9192 // Run runs the FromString test in a subtest of t, named by fst.variant.
92 func (fst fromStringTest) Run(t *testing.T) {
93 func (fst fromStringTest) TestFromString(t *testing.T) {
9394 t.Run(fst.variant, func(t *testing.T) {
9495 got, err := FromString(fst.input)
9596 if err != nil {
9798 }
9899 if want := codecTestUUID; got != want {
99100 t.Fatalf("FromString(%q) = %v, want %v", fst.input, got, want)
101 }
102 })
103 }
104
105 func (fst fromStringTest) TestUnmarshalText(t *testing.T) {
106 t.Run(fst.variant, func(t *testing.T) {
107 var u UUID
108 err := u.UnmarshalText([]byte(fst.input))
109 if err != nil {
110 t.Fatalf("UnmarshalText(%q) (%s): %v", fst.input, fst.variant, err)
111 }
112 if want := codecTestData; !bytes.Equal(u[:], want[:]) {
113 t.Fatalf("UnmarshalText(%q) (%s) = %v, want %v", fst.input, fst.variant, u, want)
100114 }
101115 })
102116 }
170184 func TestFromString(t *testing.T) {
171185 t.Run("Valid", func(t *testing.T) {
172186 for _, fst := range fromStringTests {
173 fst.Run(t)
187 fst.TestFromString(t)
174188 }
175189 })
176190 t.Run("Invalid", func(t *testing.T) {
198212 t.Errorf("FromStringOrNil(%q): got %v, want %v", s, got, codecTestUUID)
199213 }
200214 })
215 }
216
217 func TestUnmarshalText(t *testing.T) {
218 t.Run("Valid", func(t *testing.T) {
219 for _, fst := range fromStringTests {
220 fst.TestUnmarshalText(t)
221 }
222 })
223 t.Run("Invalid", func(t *testing.T) {
224 for _, s := range invalidFromStringInputs {
225 var u UUID
226 err := u.UnmarshalText([]byte(s))
227 if err == nil {
228 t.Errorf("FromBytes(%q): want err != nil, got %v", s, u)
229 }
230 }
231 })
232 }
233
234 // Test that UnmarshalText() and Parse() return identical errors
235 func TestUnmarshalTextParseErrors(t *testing.T) {
236 for _, s := range invalidFromStringInputs {
237 var u UUID
238 e1 := u.UnmarshalText([]byte(s))
239 e2 := u.Parse(s)
240 if e1 == nil || e1.Error() != e2.Error() {
241 t.Errorf("%q: errors don't match: UnmarshalText: %v Parse: %v", s, e1, e2)
242 }
243 }
201244 }
202245
203246 func TestMarshalBinary(t *testing.T) {
226269
227270 u := UUID{}
228271
229 if u.decodePlain(arg) == nil {
230 t.Errorf("%v.decodePlain(%q): should return error, but it did not", u, arg)
231 }
272 if u.UnmarshalText(arg) == nil {
273 t.Errorf("%v.UnmarshalText(%q): should return error, but it did not", u, arg)
274 }
275 }
276
277 func TestFromHexChar(t *testing.T) {
278 const hextable = "0123456789abcdef"
279
280 t.Run("Valid", func(t *testing.T) {
281 t.Run("Lower", func(t *testing.T) {
282 for i, c := range []byte(hextable) {
283 x := fromHexChar(c)
284 if int(x) != i {
285 t.Errorf("fromHexChar(%c): got %d want %d", c, x, i)
286 }
287 }
288 })
289 t.Run("Upper", func(t *testing.T) {
290 for i, c := range []byte(strings.ToUpper(hextable)) {
291 x := fromHexChar(c)
292 if int(x) != i {
293 t.Errorf("fromHexChar(%c): got %d want %d", c, x, i)
294 }
295 }
296 })
297 })
298
299 t.Run("Invalid", func(t *testing.T) {
300 skip := make(map[byte]bool)
301 for _, c := range []byte(hextable + strings.ToUpper(hextable)) {
302 skip[c] = true
303 }
304 for i := 0; i < 256; i++ {
305 c := byte(i)
306 if !skip[c] {
307 v := fromHexChar(c)
308 if v != 255 {
309 t.Errorf("fromHexChar(%c): got %d want: %d", c, v, 255)
310 }
311 }
312 }
313 })
232314 }
233315
234316 var stringBenchmarkSink string
263345 })
264346 }
265347
348 func BenchmarkUnmarshalText(b *testing.B) {
349 b.Run("canonical", func(b *testing.B) {
350 text := []byte(Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")).String())
351 u := new(UUID)
352 if err := u.UnmarshalText(text); err != nil {
353 b.Fatal(err)
354 }
355 b.ResetTimer()
356 for i := 0; i < b.N; i++ {
357 _ = u.UnmarshalText(text)
358 }
359 })
360 b.Run("urn", func(b *testing.B) {
361 text := []byte(Must(FromString("urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8")).String())
362 u := new(UUID)
363 if err := u.UnmarshalText(text); err != nil {
364 b.Fatal(err)
365 }
366 b.ResetTimer()
367 for i := 0; i < b.N; i++ {
368 _ = u.UnmarshalText(text)
369 }
370 })
371 b.Run("braced", func(b *testing.B) {
372 text := []byte(Must(FromString("{6ba7b810-9dad-11d1-80b4-00c04fd430c8}")).String())
373 u := new(UUID)
374 if err := u.UnmarshalText(text); err != nil {
375 b.Fatal(err)
376 }
377 b.ResetTimer()
378 for i := 0; i < b.N; i++ {
379 _ = u.UnmarshalText(text)
380 }
381 })
382 }
383
266384 func BenchmarkMarshalBinary(b *testing.B) {
267385 for i := 0; i < b.N; i++ {
268386 codecTestUUID.MarshalBinary()
272390 func BenchmarkMarshalText(b *testing.B) {
273391 for i := 0; i < b.N; i++ {
274392 codecTestUUID.MarshalText()
393 }
394 }
395
396 func BenchmarkParseV4(b *testing.B) {
397 const text = "f52a747a-983f-45f7-90b5-e84d70f470dd"
398 for i := 0; i < b.N; i++ {
399 var u UUID
400 if err := u.Parse(text); err != nil {
401 b.Fatal(err)
402 }
275403 }
276404 }
277405
0 golang-github-gofrs-uuid (5.0.0-1) UNRELEASED; urgency=low
1
2 * New upstream release.
3
4 -- Debian Janitor <janitor@jelmer.uk> Fri, 09 Jun 2023 06:41:37 -0000
5
06 golang-github-gofrs-uuid (4.3.1-1) unstable; urgency=medium
17
28 * New upstream release
1818 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1919 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2020
21 //go:build gofuzz
2122 // +build gofuzz
2223
2324 package uuid
2627 //
2728 // To run:
2829 //
29 // $ go get github.com/dvyukov/go-fuzz/...
30 // $ cd $GOPATH/src/github.com/gofrs/uuid
31 // $ go-fuzz-build github.com/gofrs/uuid
32 // $ go-fuzz -bin=uuid-fuzz.zip -workdir=./testdata
30 // $ go get github.com/dvyukov/go-fuzz/...
31 // $ cd $GOPATH/src/github.com/gofrs/uuid
32 // $ go-fuzz-build github.com/gofrs/uuid
33 // $ go-fuzz -bin=uuid-fuzz.zip -workdir=./testdata
3334 //
3435 // If you make significant changes to FromString / UnmarshalText and add
3536 // new cases to fromStringTests (in codec_test.go), please run
3637 //
37 // $ go test -seed_fuzz_corpus
38 // $ go test -seed_fuzz_corpus
3839 //
3940 // to seed the corpus with the new interesting inputs, then run the fuzzer.
4041 func Fuzz(data []byte) int {
3737 // UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
3838 const epochStart = 122192928000000000
3939
40 type epochFunc func() time.Time
40 // EpochFunc is the function type used to provide the current time.
41 type EpochFunc func() time.Time
4142
4243 // HWAddrFunc is the function type used to provide hardware (MAC) addresses.
4344 type HWAddrFunc func() (net.HardwareAddr, error)
7980 }
8081
8182 // NewV7 returns a k-sortable UUID based on the current millisecond precision
82 // UNIX epoch and 74 bits of pseudorandom data.
83 //
84 // This is implemented based on revision 03 of the Peabody UUID draft, and may
83 // UNIX epoch and 74 bits of pseudorandom data. It supports single-node batch generation (multiple UUIDs in the same timestamp) with a Monotonic Random counter.
84 //
85 // This is implemented based on revision 04 of the Peabody UUID draft, and may
8586 // be subject to change pending further revisions. Until the final specification
8687 // revision is finished, changes required to implement updates to the spec will
8788 // not be considered a breaking change. They will happen as a minor version
118119
119120 rand io.Reader
120121
121 epochFunc epochFunc
122 epochFunc EpochFunc
122123 hwAddrFunc HWAddrFunc
123124 lastTime uint64
124125 clockSequence uint16
125126 hardwareAddr [6]byte
126127 }
128
129 // GenOption is a function type that can be used to configure a Gen generator.
130 type GenOption func(*Gen)
127131
128132 // interface check -- build will fail if *Gen doesn't satisfy Generator
129133 var _ Generator = (*Gen)(nil)
146150 // MAC address being used, you'll need to create a new generator using this
147151 // function.
148152 func NewGenWithHWAF(hwaf HWAddrFunc) *Gen {
149 return &Gen{
153 return NewGenWithOptions(WithHWAddrFunc(hwaf))
154 }
155
156 // NewGenWithOptions returns a new instance of Gen with the options provided.
157 // Most people should use NewGen() or NewGenWithHWAF() instead.
158 //
159 // To customize the generator, you can pass in one or more GenOption functions.
160 // For example:
161 //
162 // gen := NewGenWithOptions(
163 // WithHWAddrFunc(myHWAddrFunc),
164 // WithEpochFunc(myEpochFunc),
165 // WithRandomReader(myRandomReader),
166 // )
167 //
168 // NewGenWithOptions(WithHWAddrFunc(myHWAddrFunc)) is equivalent to calling
169 // NewGenWithHWAF(myHWAddrFunc)
170 // NewGenWithOptions() is equivalent to calling NewGen()
171 func NewGenWithOptions(opts ...GenOption) *Gen {
172 gen := &Gen{
150173 epochFunc: time.Now,
151 hwAddrFunc: hwaf,
174 hwAddrFunc: defaultHWAddrFunc,
152175 rand: rand.Reader,
176 }
177
178 for _, opt := range opts {
179 opt(gen)
180 }
181
182 return gen
183 }
184
185 // WithHWAddrFunc is a GenOption that allows you to provide your own HWAddrFunc
186 // function.
187 // When this option is nil, the defaultHWAddrFunc is used.
188 func WithHWAddrFunc(hwaf HWAddrFunc) GenOption {
189 return func(gen *Gen) {
190 if hwaf == nil {
191 hwaf = defaultHWAddrFunc
192 }
193
194 gen.hwAddrFunc = hwaf
195 }
196 }
197
198 // WithEpochFunc is a GenOption that allows you to provide your own EpochFunc
199 // function.
200 // When this option is nil, time.Now is used.
201 func WithEpochFunc(epochf EpochFunc) GenOption {
202 return func(gen *Gen) {
203 if epochf == nil {
204 epochf = time.Now
205 }
206
207 gen.epochFunc = epochf
208 }
209 }
210
211 // WithRandomReader is a GenOption that allows you to provide your own random
212 // reader.
213 // When this option is nil, the default rand.Reader is used.
214 func WithRandomReader(reader io.Reader) GenOption {
215 return func(gen *Gen) {
216 if reader == nil {
217 reader = rand.Reader
218 }
219
220 gen.rand = reader
153221 }
154222 }
155223
157225 func (g *Gen) NewV1() (UUID, error) {
158226 u := UUID{}
159227
160 timeNow, clockSeq, err := g.getClockSequence()
228 timeNow, clockSeq, err := g.getClockSequence(false)
161229 if err != nil {
162230 return Nil, err
163231 }
224292 return Nil, err
225293 }
226294
227 timeNow, clockSeq, err := g.getClockSequence()
295 timeNow, clockSeq, err := g.getClockSequence(false)
228296 if err != nil {
229297 return Nil, err
230298 }
240308 return u, nil
241309 }
242310
243 // getClockSequence returns the epoch and clock sequence for V1 and V6 UUIDs.
244 func (g *Gen) getClockSequence() (uint64, uint16, error) {
311 // getClockSequence returns the epoch and clock sequence for V1,V6 and V7 UUIDs.
312 //
313 // When useUnixTSMs is false, it uses the Coordinated Universal Time (UTC) as a count of 100-
314 //
315 // nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of Gregorian reform to the Christian calendar).
316 func (g *Gen) getClockSequence(useUnixTSMs bool) (uint64, uint16, error) {
245317 var err error
246318 g.clockSequenceOnce.Do(func() {
247319 buf := make([]byte, 2)
257329 g.storageMutex.Lock()
258330 defer g.storageMutex.Unlock()
259331
260 timeNow := g.getEpoch()
332 var timeNow uint64
333 if useUnixTSMs {
334 timeNow = uint64(g.epochFunc().UnixMilli())
335 } else {
336 timeNow = g.getEpoch()
337 }
261338 // Clock didn't change since last UUID generation.
262339 // Should increase clock sequence.
263340 if timeNow <= g.lastTime {
271348 // NewV7 returns a k-sortable UUID based on the current millisecond precision
272349 // UNIX epoch and 74 bits of pseudorandom data.
273350 //
274 // This is implemented based on revision 03 of the Peabody UUID draft, and may
351 // This is implemented based on revision 04 of the Peabody UUID draft, and may
275352 // be subject to change pending further revisions. Until the final specification
276353 // revision is finished, changes required to implement updates to the spec will
277354 // not be considered a breaking change. They will happen as a minor version
278355 // releases until the spec is final.
279356 func (g *Gen) NewV7() (UUID, error) {
280357 var u UUID
281
282 if _, err := io.ReadFull(g.rand, u[6:]); err != nil {
283 return Nil, err
284 }
285
286 tn := g.epochFunc()
287 ms := uint64(tn.Unix())*1e3 + uint64(tn.Nanosecond())/1e6
288 u[0] = byte(ms >> 40)
358 /* https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#name-uuid-version-7
359 0 1 2 3
360 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
361 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
362 | unix_ts_ms |
363 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
364 | unix_ts_ms | ver | rand_a |
365 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366 |var| rand_b |
367 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368 | rand_b |
369 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
370
371 ms, clockSeq, err := g.getClockSequence(true)
372 if err != nil {
373 return Nil, err
374 }
375 //UUIDv7 features a 48 bit timestamp. First 32bit (4bytes) represents seconds since 1970, followed by 2 bytes for the ms granularity.
376 u[0] = byte(ms >> 40) //1-6 bytes: big-endian unsigned number of Unix epoch timestamp
289377 u[1] = byte(ms >> 32)
290378 u[2] = byte(ms >> 24)
291379 u[3] = byte(ms >> 16)
292380 u[4] = byte(ms >> 8)
293381 u[5] = byte(ms)
294382
383 //support batching by using a monotonic pseudo-random sequence
384 //The 6th byte contains the version and partially rand_a data.
385 //We will lose the most significant bites from the clockSeq (with SetVersion), but it is ok, we need the least significant that contains the counter to ensure the monotonic property
386 binary.BigEndian.PutUint16(u[6:8], clockSeq) // set rand_a with clock seq which is random and monotonic
387
388 //override first 4bits of u[6].
295389 u.SetVersion(V7)
390
391 //set rand_b 64bits of pseudo-random bits (first 2 will be overridden)
392 if _, err = io.ReadFull(g.rand, u[8:16]); err != nil {
393 return Nil, err
394 }
395 //override first 2 bits of byte[8] for the variant
296396 u.SetVariant(VariantRFC4122)
297397
298398 return u, nil
4343
4444 func testNewV1(t *testing.T) {
4545 t.Run("Basic", testNewV1Basic)
46 t.Run("BasicWithOptions", testNewV1BasicWithOptions)
4647 t.Run("DifferentAcrossCalls", testNewV1DifferentAcrossCalls)
4748 t.Run("StaleEpoch", testNewV1StaleEpoch)
4849 t.Run("FaultyRand", testNewV1FaultyRand)
50 t.Run("FaultyRandWithOptions", testNewV1FaultyRandWithOptions)
4951 t.Run("MissingNetwork", testNewV1MissingNetwork)
52 t.Run("MissingNetworkWithOptions", testNewV1MissingNetworkWithOptions)
5053 t.Run("MissingNetworkFaultyRand", testNewV1MissingNetworkFaultyRand)
54 t.Run("MissingNetworkFaultyRandWithOptions", testNewV1MissingNetworkFaultyRandWithOptions)
5155 }
5256
5357 func TestNewGenWithHWAF(t *testing.T) {
8185
8286 func testNewV1Basic(t *testing.T) {
8387 u, err := NewV1()
88 if err != nil {
89 t.Fatal(err)
90 }
91 if got, want := u.Version(), V1; got != want {
92 t.Errorf("generated UUID with version %d, want %d", got, want)
93 }
94 if got, want := u.Variant(), VariantRFC4122; got != want {
95 t.Errorf("generated UUID with variant %d, want %d", got, want)
96 }
97 }
98
99 func testNewV1BasicWithOptions(t *testing.T) {
100 g := NewGenWithOptions(
101 WithHWAddrFunc(nil),
102 WithEpochFunc(nil),
103 WithRandomReader(nil),
104 )
105 u, err := g.NewV1()
84106 if err != nil {
85107 t.Fatal(err)
86108 }
152174 },
153175 rand: rand.Reader,
154176 }
177 _, err := g.NewV1()
178 if err != nil {
179 t.Errorf("did not handle missing network interfaces: %v", err)
180 }
181 }
182
183 func testNewV1MissingNetworkWithOptions(t *testing.T) {
184 g := NewGenWithOptions(
185 WithHWAddrFunc(func() (net.HardwareAddr, error) {
186 return []byte{}, fmt.Errorf("uuid: no hw address found")
187 }),
188 )
155189 _, err := g.NewV1()
156190 if err != nil {
157191 t.Errorf("did not handle missing network interfaces: %v", err)
174208 }
175209 }
176210
211 func testNewV1MissingNetworkFaultyRandWithOptions(t *testing.T) {
212 g := NewGenWithOptions(
213 WithHWAddrFunc(func() (net.HardwareAddr, error) {
214 return []byte{}, fmt.Errorf("uuid: no hw address found")
215 }),
216 WithRandomReader(&faultyReader{
217 readToFail: 1,
218 }),
219 )
220
221 u, err := g.NewV1()
222 if err == nil {
223 t.Errorf("did not error on faulty reader and missing network, got %v", u)
224 }
225 }
226
227 func testNewV1FaultyRandWithOptions(t *testing.T) {
228 g := NewGenWithOptions(WithRandomReader(&faultyReader{
229 readToFail: 0, // fail immediately
230 }),
231 )
232 u, err := g.NewV1()
233 if err == nil {
234 t.Errorf("did not error on faulty reader and missing network, got %v", u)
235 }
236 }
237
177238 func testNewV3(t *testing.T) {
178239 t.Run("Basic", testNewV3Basic)
179240 t.Run("EqualNames", testNewV3EqualNames)
221282 t.Run("Basic", testNewV4Basic)
222283 t.Run("DifferentAcrossCalls", testNewV4DifferentAcrossCalls)
223284 t.Run("FaultyRand", testNewV4FaultyRand)
285 t.Run("FaultyRandWithOptions", testNewV4FaultyRandWithOptions)
224286 t.Run("ShortRandomRead", testNewV4ShortRandomRead)
287 t.Run("ShortRandomReadWithOptions", testNewV4ShortRandomReadWithOptions)
225288 }
226289
227290 func testNewV4Basic(t *testing.T) {
265328 }
266329 }
267330
331 func testNewV4FaultyRandWithOptions(t *testing.T) {
332 g := NewGenWithOptions(
333 WithRandomReader(&faultyReader{
334 readToFail: 0, // fail immediately
335 }),
336 )
337 u, err := g.NewV4()
338 if err == nil {
339 t.Errorf("got %v, nil error", u)
340 }
341 }
342
268343 func testNewV4ShortRandomRead(t *testing.T) {
269344 g := &Gen{
270345 epochFunc: time.Now,
273348 },
274349 rand: bytes.NewReader([]byte{42}),
275350 }
351 u, err := g.NewV4()
352 if err == nil {
353 t.Errorf("got %v, nil error", u)
354 }
355 }
356
357 func testNewV4ShortRandomReadWithOptions(t *testing.T) {
358 g := NewGenWithOptions(
359 WithHWAddrFunc(func() (net.HardwareAddr, error) {
360 return []byte{}, fmt.Errorf("uuid: no hw address found")
361 }),
362 WithRandomReader(&faultyReader{
363 readToFail: 0, // fail immediately
364 }),
365 )
276366 u, err := g.NewV4()
277367 if err == nil {
278368 t.Errorf("got %v, nil error", u)
326416 t.Run("Basic", testNewV6Basic)
327417 t.Run("DifferentAcrossCalls", testNewV6DifferentAcrossCalls)
328418 t.Run("StaleEpoch", testNewV6StaleEpoch)
419 t.Run("StaleEpochWithOptions", testNewV6StaleEpochWithOptions)
329420 t.Run("FaultyRand", testNewV6FaultyRand)
421 t.Run("FaultyRandWithOptions", testNewV6FaultyRandWithOptions)
330422 t.Run("ShortRandomRead", testNewV6ShortRandomRead)
423 t.Run("ShortRandomReadWithOptions", testNewV6ShortRandomReadWithOptions)
331424 t.Run("KSortable", testNewV6KSortable)
332425 }
333426
366459 hwAddrFunc: defaultHWAddrFunc,
367460 rand: rand.Reader,
368461 }
462 u1, err := g.NewV6()
463 if err != nil {
464 t.Fatal(err)
465 }
466 u2, err := g.NewV6()
467 if err != nil {
468 t.Fatal(err)
469 }
470 if u1 == u2 {
471 t.Errorf("generated identical UUIDs across calls: %v", u1)
472 }
473 }
474
475 func testNewV6StaleEpochWithOptions(t *testing.T) {
476 g := NewGenWithOptions(
477 WithEpochFunc(func() time.Time {
478 return time.Unix(0, 0)
479 }),
480 )
369481 u1, err := g.NewV6()
370482 if err != nil {
371483 t.Fatal(err)
415527 })
416528 }
417529
530 func testNewV6FaultyRandWithOptions(t *testing.T) {
531 t.Run("randomData", func(t *testing.T) {
532 g := NewGenWithOptions(
533 WithRandomReader(&faultyReader{
534 readToFail: 0, // fail immediately
535 }),
536 )
537 u, err := g.NewV6()
538 if err == nil {
539 t.Fatalf("got %v, want error", u)
540 }
541 if u != Nil {
542 t.Fatalf("got %v on error, want Nil", u)
543 }
544 })
545
546 t.Run("clockSequence", func(t *testing.T) {
547 g := NewGenWithOptions(
548 WithRandomReader(&faultyReader{
549 readToFail: 1, // fail immediately
550 }),
551 )
552 u, err := g.NewV6()
553 if err == nil {
554 t.Fatalf("got %v, want error", u)
555 }
556 if u != Nil {
557 t.Fatalf("got %v on error, want Nil", u)
558 }
559 })
560 }
561
418562 func testNewV6ShortRandomRead(t *testing.T) {
419563 g := &Gen{
420564 epochFunc: time.Now,
421565 rand: bytes.NewReader([]byte{42}),
422566 }
567 u, err := g.NewV6()
568 if err == nil {
569 t.Errorf("got %v, nil error", u)
570 }
571 }
572
573 func testNewV6ShortRandomReadWithOptions(t *testing.T) {
574 g := NewGenWithOptions(
575 WithRandomReader(bytes.NewReader([]byte{42})),
576 )
423577 u, err := g.NewV6()
424578 if err == nil {
425579 t.Errorf("got %v, nil error", u)
448602
449603 func testNewV7(t *testing.T) {
450604 t.Run("Basic", makeTestNewV7Basic())
605 t.Run("TestVector", makeTestNewV7TestVector())
451606 t.Run("Basic10000000", makeTestNewV7Basic10000000())
452607 t.Run("DifferentAcrossCalls", makeTestNewV7DifferentAcrossCalls())
453608 t.Run("StaleEpoch", makeTestNewV7StaleEpoch())
609 t.Run("StaleEpochWithOptions", makeTestNewV7StaleEpochWithOptions())
454610 t.Run("FaultyRand", makeTestNewV7FaultyRand())
611 t.Run("FaultyRandWithOptions", makeTestNewV7FaultyRandWithOptions())
455612 t.Run("ShortRandomRead", makeTestNewV7ShortRandomRead())
456613 t.Run("KSortable", makeTestNewV7KSortable())
614 t.Run("ClockSequence", makeTestNewV7ClockSequence())
457615 }
458616
459617 func makeTestNewV7Basic() func(t *testing.T) {
467625 }
468626 if got, want := u.Variant(), VariantRFC4122; got != want {
469627 t.Errorf("got variant %d, want %d", got, want)
628 }
629 }
630 }
631
632 // makeTestNewV7TestVector as defined in Draft04
633 func makeTestNewV7TestVector() func(t *testing.T) {
634 return func(t *testing.T) {
635 pRand := make([]byte, 10)
636 //first 2 bytes will be read by clockSeq. First 4 bits will be overridden by Version. The next bits should be 0xCC3(3267)
637 binary.LittleEndian.PutUint16(pRand[:2], uint16(0xCC3))
638 //8bytes will be read for rand_b. First 2 bits will be overridden by Variant
639 binary.LittleEndian.PutUint64(pRand[2:], uint64(0x18C4DC0C0C07398F))
640
641 g := &Gen{
642 epochFunc: func() time.Time {
643 return time.UnixMilli(1645557742000)
644 },
645 rand: bytes.NewReader(pRand),
646 }
647 u, err := g.NewV7()
648 if err != nil {
649 t.Fatal(err)
650 }
651 if got, want := u.Version(), V7; got != want {
652 t.Errorf("got version %d, want %d", got, want)
653 }
654 if got, want := u.Variant(), VariantRFC4122; got != want {
655 t.Errorf("got variant %d, want %d", got, want)
656 }
657 if got, want := u.String()[:15], "017f22e2-79b0-7"; got != want {
658 t.Errorf("got version %q, want %q", got, want)
470659 }
471660 }
472661 }
534723 }
535724 }
536725
726 func makeTestNewV7StaleEpochWithOptions() func(t *testing.T) {
727 return func(t *testing.T) {
728 g := NewGenWithOptions(
729 WithEpochFunc(func() time.Time {
730 return time.Unix(0, 0)
731 }),
732 )
733 u1, err := g.NewV7()
734 if err != nil {
735 t.Fatal(err)
736 }
737 u2, err := g.NewV7()
738 if err != nil {
739 t.Fatal(err)
740 }
741 if u1 == u2 {
742 t.Errorf("generated identical UUIDs across calls: %v", u1)
743 }
744 }
745 }
746
537747 func makeTestNewV7FaultyRand() func(t *testing.T) {
538748 return func(t *testing.T) {
539749 g := &Gen{
540750 epochFunc: time.Now,
541751 rand: &faultyReader{
752 readToFail: 0,
753 },
754 }
755 u, err := g.NewV7()
756 if err == nil {
757 t.Errorf("got %v, nil error for clockSequence", u)
758 }
759
760 g = &Gen{
761 epochFunc: time.Now,
762 rand: &faultyReader{
763 readToFail: 1,
764 },
765 }
766 u, err = g.NewV7()
767 if err == nil {
768 t.Errorf("got %v, nil error rand_b", u)
769 }
770 }
771 }
772
773 func makeTestNewV7FaultyRandWithOptions() func(t *testing.T) {
774 return func(t *testing.T) {
775 g := NewGenWithOptions(
776 WithRandomReader(&faultyReader{
542777 readToFail: 0, // fail immediately
543 },
544 }
778 }),
779 )
545780 u, err := g.NewV7()
546781 if err == nil {
547782 t.Errorf("got %v, nil error", u)
555790 epochFunc: time.Now,
556791 rand: bytes.NewReader([]byte{42}),
557792 }
793 u, err := g.NewV7()
794 if err == nil {
795 t.Errorf("got %v, nil error", u)
796 }
797 }
798 }
799
800 func makeTestNewV7ShortRandomReadWithOptions() func(t *testing.T) {
801 return func(t *testing.T) {
802 g := NewGenWithOptions(
803 WithRandomReader(bytes.NewReader([]byte{42})),
804 )
558805 u, err := g.NewV7()
559806 if err == nil {
560807 t.Errorf("got %v, nil error", u)
583830 }
584831 }
585832
586 func testNewV7ClockSequence(t *testing.T) {
587 if testing.Short() {
588 t.Skip("skipping test in short mode.")
589 }
590
591 g := NewGen()
592
593 // hack to try and reduce race conditions based on when the test starts
594 nsec := time.Now().Nanosecond()
595 sleepDur := int(time.Second) - nsec
596 time.Sleep(time.Duration(sleepDur))
597
598 u1, err := g.NewV7()
599 if err != nil {
600 t.Fatalf("failed to generate V7 UUID #1: %v", err)
601 }
602
603 u2, err := g.NewV7()
604 if err != nil {
605 t.Fatalf("failed to generate V7 UUID #2: %v", err)
606 }
607
608 time.Sleep(time.Millisecond)
609
610 u3, err := g.NewV7()
611 if err != nil {
612 t.Fatalf("failed to generate V7 UUID #3: %v", err)
613 }
614
615 time.Sleep(time.Second)
616
617 u4, err := g.NewV7()
618 if err != nil {
619 t.Fatalf("failed to generate V7 UUID #3: %v", err)
620 }
621
622 s1 := binary.BigEndian.Uint16(u1[6:8]) & 0xfff
623 s2 := binary.BigEndian.Uint16(u2[6:8]) & 0xfff
624 s3 := binary.BigEndian.Uint16(u3[6:8]) & 0xfff
625 s4 := binary.BigEndian.Uint16(u4[6:8]) & 0xfff
626
627 if s1 != 0 {
628 t.Errorf("sequence 1 should be zero, was %d", s1)
629 }
630
631 if s2 != s1+1 {
632 t.Errorf("sequence 2 expected to be one above sequence 1; seq 1: %d, seq 2: %d", s1, s2)
633 }
634
635 if s3 != 0 {
636 t.Errorf("sequence 3 should be zero, was %d", s3)
637 }
638
639 if s4 != 0 {
640 t.Errorf("sequence 4 should be zero, was %d", s4)
833 func makeTestNewV7ClockSequence() func(t *testing.T) {
834 return func(t *testing.T) {
835 if testing.Short() {
836 t.Skip("skipping test in short mode.")
837 }
838
839 g := NewGen()
840 //always return the same TS
841 g.epochFunc = func() time.Time {
842 return time.UnixMilli(1645557742000)
843 }
844 //by being KSortable with the same timestamp, it means the sequence is Not empty, and it is monotonic
845 uuids := make([]UUID, 10)
846 for i := range uuids {
847 u, err := g.NewV7()
848 testErrCheck(t, "NewV7()", "", err)
849 uuids[i] = u
850 }
851
852 for i := 1; i < len(uuids); i++ {
853 p, n := uuids[i-1], uuids[i]
854 isLess := p.String() < n.String()
855 if !isLess {
856 t.Errorf("uuids[%d] (%s) not less than uuids[%d] (%s)", i-1, p, i, n)
857 }
858 }
641859 }
642860 }
643861
0 module github.com/gofrs/uuid/v5
1
2 go 1.19
2121 package uuid
2222
2323 import (
24 "bytes"
24 "database/sql"
2525 "database/sql/driver"
26 "encoding/json"
2726 "fmt"
2827 )
28
29 var _ driver.Valuer = UUID{}
30 var _ sql.Scanner = (*UUID)(nil)
2931
3032 // Value implements the driver.Valuer interface.
3133 func (u UUID) Value() (driver.Value, error) {
4850 return u.UnmarshalText(src)
4951
5052 case string:
51 return u.UnmarshalText([]byte(src))
53 uu, err := FromString(src)
54 *u = uu
55 return err
5256 }
5357
5458 return fmt.Errorf("uuid: cannot convert %T to UUID", src)
8286 return u.UUID.Scan(src)
8387 }
8488
89 var nullJSON = []byte("null")
90
8591 // MarshalJSON marshals the NullUUID as null or the nested UUID
8692 func (u NullUUID) MarshalJSON() ([]byte, error) {
8793 if !u.Valid {
88 return json.Marshal(nil)
94 return nullJSON, nil
8995 }
90
91 return json.Marshal(u.UUID)
96 var buf [38]byte
97 buf[0] = '"'
98 encodeCanonical(buf[1:37], u.UUID)
99 buf[37] = '"'
100 return buf[:], nil
92101 }
93102
94103 // UnmarshalJSON unmarshals a NullUUID
95104 func (u *NullUUID) UnmarshalJSON(b []byte) error {
96 if bytes.Equal(b, []byte("null")) {
105 if string(b) == "null" {
97106 u.UUID, u.Valid = Nil, false
98107 return nil
99108 }
100
101 if err := json.Unmarshal(b, &u.UUID); err != nil {
102 return err
109 if n := len(b); n >= 2 && b[0] == '"' {
110 b = b[1 : n-1]
103111 }
104
105 u.Valid = true
106
107 return nil
112 err := u.UUID.UnmarshalText(b)
113 u.Valid = (err == nil)
114 return err
108115 }
290290 t.Fatalf("u.UUID = %v, want %v", u.UUID, Nil)
291291 }
292292 }
293
293294 func testNullUUIDUnmarshalJSONValid(t *testing.T) {
294295 var u NullUUID
295296
317318 t.Fatal("json.Unmarshal err = <nil>, want error")
318319 }
319320 }
321
322 func BenchmarkNullMarshalJSON(b *testing.B) {
323 b.Run("Valid", func(b *testing.B) {
324 u, err := FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
325 if err != nil {
326 b.Fatal(err)
327 }
328 n := NullUUID{UUID: u, Valid: true}
329 for i := 0; i < b.N; i++ {
330 n.MarshalJSON()
331 }
332 })
333 b.Run("Invalid", func(b *testing.B) {
334 n := NullUUID{Valid: false}
335 for i := 0; i < b.N; i++ {
336 n.MarshalJSON()
337 }
338 })
339 }
340
341 func BenchmarkNullUnmarshalJSON(b *testing.B) {
342 baseUUID, err := FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
343 if err != nil {
344 b.Fatal(err)
345 }
346 data, err := json.Marshal(&baseUUID)
347 if err != nil {
348 b.Fatal(err)
349 }
350
351 b.Run("Valid", func(b *testing.B) {
352 var u NullUUID
353 for i := 0; i < b.N; i++ {
354 u.UnmarshalJSON(data)
355 }
356 })
357 b.Run("Invalid", func(b *testing.B) {
358 invalid := []byte("null")
359 var n NullUUID
360 for i := 0; i < b.N; i++ {
361 n.UnmarshalJSON(invalid)
362 }
363 })
364 }
4343 "encoding/binary"
4444 "encoding/hex"
4545 "fmt"
46 "io"
47 "strings"
4846 "time"
4947 )
5048
131129
132130 return Timestamp(uint64(low) + (uint64(mid) << 12) + (uint64(hi) << 28)), nil
133131 }
134
135 // String parse helpers.
136 var (
137 urnPrefix = []byte("urn:uuid:")
138 byteGroups = []int{8, 4, 4, 4, 12}
139 )
140132
141133 // Nil is the nil UUID, as specified in RFC-4122, that has all 128 bits set to
142134 // zero.
181173 return u[:]
182174 }
183175
176 // encodeCanonical encodes the canonical RFC-4122 form of UUID u into the
177 // first 36 bytes dst.
178 func encodeCanonical(dst []byte, u UUID) {
179 const hextable = "0123456789abcdef"
180 dst[8] = '-'
181 dst[13] = '-'
182 dst[18] = '-'
183 dst[23] = '-'
184 for i, x := range [16]byte{
185 0, 2, 4, 6,
186 9, 11,
187 14, 16,
188 19, 21,
189 24, 26, 28, 30, 32, 34,
190 } {
191 c := u[i]
192 dst[x] = hextable[c>>4]
193 dst[x+1] = hextable[c&0x0f]
194 }
195 }
196
184197 // String returns a canonical RFC-4122 string representation of the UUID:
185198 // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
186199 func (u UUID) String() string {
187 buf := make([]byte, 36)
188
189 hex.Encode(buf[0:8], u[0:4])
190 buf[8] = '-'
191 hex.Encode(buf[9:13], u[4:6])
192 buf[13] = '-'
193 hex.Encode(buf[14:18], u[6:8])
194 buf[18] = '-'
195 hex.Encode(buf[19:23], u[8:10])
196 buf[23] = '-'
197 hex.Encode(buf[24:], u[10:])
198
199 return string(buf)
200 var buf [36]byte
201 encodeCanonical(buf[:], u)
202 return string(buf[:])
200203 }
201204
202205 // Format implements fmt.Formatter for UUID values.
209212 // All other verbs not handled directly by the fmt package (like '%p') are unsupported and will return
210213 // "%!verb(uuid.UUID=value)" as recommended by the fmt package.
211214 func (u UUID) Format(f fmt.State, c rune) {
215 if c == 'v' && f.Flag('#') {
216 fmt.Fprintf(f, "%#v", [Size]byte(u))
217 return
218 }
212219 switch c {
213220 case 'x', 'X':
214 s := hex.EncodeToString(u.Bytes())
221 b := make([]byte, 32)
222 hex.Encode(b, u[:])
215223 if c == 'X' {
216 s = strings.Map(toCapitalHexDigits, s)
224 toUpperHex(b)
217225 }
218 _, _ = io.WriteString(f, s)
219 case 'v':
220 var s string
221 if f.Flag('#') {
222 s = fmt.Sprintf("%#v", [Size]byte(u))
223 } else {
224 s = u.String()
226 _, _ = f.Write(b)
227 case 'v', 's', 'S':
228 b, _ := u.MarshalText()
229 if c == 'S' {
230 toUpperHex(b)
225231 }
226 _, _ = io.WriteString(f, s)
227 case 's', 'S':
228 s := u.String()
229 if c == 'S' {
230 s = strings.Map(toCapitalHexDigits, s)
231 }
232 _, _ = io.WriteString(f, s)
232 _, _ = f.Write(b)
233233 case 'q':
234 _, _ = io.WriteString(f, `"`+u.String()+`"`)
234 b := make([]byte, 38)
235 b[0] = '"'
236 encodeCanonical(b[1:], u)
237 b[37] = '"'
238 _, _ = f.Write(b)
235239 default:
236240 // invalid/unsupported format verb
237241 fmt.Fprintf(f, "%%!%c(uuid.UUID=%s)", c, u.String())
238242 }
239243 }
240244
241 func toCapitalHexDigits(ch rune) rune {
242 // convert a-f hex digits to A-F
243 switch ch {
244 case 'a':
245 return 'A'
246 case 'b':
247 return 'B'
248 case 'c':
249 return 'C'
250 case 'd':
251 return 'D'
252 case 'e':
253 return 'E'
254 case 'f':
255 return 'F'
256 default:
257 return ch
245 func toUpperHex(b []byte) {
246 for i, c := range b {
247 if 'a' <= c && c <= 'f' {
248 b[i] = c - ('a' - 'A')
249 }
258250 }
259251 }
260252
282274 // Must is a helper that wraps a call to a function returning (UUID, error)
283275 // and panics if the error is non-nil. It is intended for use in variable
284276 // initializations such as
285 // var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"))
277 //
278 // var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"))
286279 func Must(u UUID, err error) UUID {
287280 if err != nil {
288281 panic(err)
2323 import (
2424 "bytes"
2525 "fmt"
26 "io"
2627 "testing"
2728 "time"
2829 )
253254 }
254255 }
255256 }
257
258 func BenchmarkFormat(b *testing.B) {
259 var tests = []string{
260 "%s",
261 "%S",
262 "%q",
263 "%x",
264 "%X",
265 "%v",
266 "%+v",
267 "%#v",
268 }
269 for _, x := range tests {
270 b.Run(x[1:], func(b *testing.B) {
271 for i := 0; i < b.N; i++ {
272 fmt.Fprintf(io.Discard, x, &codecTestUUID)
273 }
274 })
275 }
276 }