-
Notifications
You must be signed in to change notification settings - Fork 378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add Version4 factory to configure UUID generation #88
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,12 +4,17 @@ | |
|
||
package uuid | ||
|
||
import "io" | ||
import ( | ||
"crypto/rand" | ||
"io" | ||
) | ||
|
||
// New creates a new random UUID or panics. New is equivalent to | ||
// the expression | ||
// | ||
// uuid.Must(uuid.NewRandom()) | ||
// | ||
// Deprecated: Use *Version4.NewUUID() instead. | ||
func New() UUID { | ||
return Must(NewRandom()) | ||
} | ||
|
@@ -18,6 +23,8 @@ func New() UUID { | |
// NewString is equivalent to the expression | ||
// | ||
// uuid.New().String() | ||
// | ||
// Deprecated: Use *Version4.NewString() instead. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not deprecated. New and NewString are the two most common ways to create a UUID. Version 4 is by far the most common type of UUID due to the issues associated with Version 1 (which are documented in the RFC). |
||
func NewString() string { | ||
return Must(NewRandom()).String() | ||
} | ||
|
@@ -27,49 +34,79 @@ func NewString() string { | |
// The strength of the UUIDs is based on the strength of the crypto/rand | ||
// package. | ||
// | ||
// Uses the randomness pool if it was enabled with EnableRandPool. | ||
// | ||
// A note about uniqueness derived from the UUID Wikipedia entry: | ||
// | ||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being | ||
// hit by a meteorite is estimated to be one chance in 17 billion, that | ||
// means the probability is about 0.00000000006 (6 × 10−11), | ||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a | ||
// year and having one duplicate. | ||
// | ||
// Deprecated: Use *Version4.New() instead. | ||
func NewRandom() (UUID, error) { | ||
if !poolEnabled { | ||
return NewRandomFromReader(rander) | ||
} | ||
return newRandomFromPool() | ||
g := &Version4{Rand: rander} | ||
return g.New() | ||
} | ||
|
||
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader. | ||
// | ||
// Deprecated: Use *Version4.New() instead. | ||
func NewRandomFromReader(r io.Reader) (UUID, error) { | ||
var uuid UUID | ||
_, err := io.ReadFull(r, uuid[:]) | ||
if err != nil { | ||
return Nil, err | ||
g := &Version4{Rand: r} | ||
return g.New() | ||
} | ||
|
||
// A Version4 generates Version 4 UUIDs. | ||
type Version4 struct { | ||
// Rand provides the source of entropy for generation random UUIDs. | ||
// If Rand is nil, crypto/rand.Reader will be used. | ||
// | ||
// The thread-safety of the Version4 is contingent upon that of the Rand. | ||
// | ||
// Clients wishing to sacrifice security for performance should consider | ||
// using a bufio.Reader or similar. | ||
Rand io.Reader | ||
} | ||
|
||
// New generates a new a Version 4 UUID. | ||
// | ||
// The strength/randomness of the UUID is based on the strength of v4.Rand. | ||
// | ||
// A note about uniqueness derived from the UUID Wikipedia entry: | ||
// | ||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being | ||
// hit by a meteorite is estimated to be one chance in 17 billion, that | ||
// means the probability is about 0.00000000006 (6 × 10−11), | ||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a | ||
// year and having one duplicate. | ||
func (v4 *Version4) New() (UUID, error) { | ||
r := v4.Rand | ||
if r == nil { | ||
r = rand.Reader | ||
} | ||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 | ||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 | ||
return uuid, nil | ||
return newV4(r) | ||
} | ||
|
||
func newRandomFromPool() (UUID, error) { | ||
// NewUUID generates a new Version 4 UUID, or panics. | ||
// It is equivalent to: | ||
// uuid.Must(v4.New()) | ||
func (v4 *Version4) NewUUID() UUID { | ||
return Must(v4.New()) | ||
} | ||
|
||
// NewString generates a new Version 4 UUID as a string, or panics. | ||
// It is equivalent to: | ||
// v4.NewUUID().String() | ||
func (v4 *Version4) NewString() string { | ||
return v4.NewUUID().String() | ||
} | ||
|
||
func newV4(r io.Reader) (UUID, error) { | ||
var uuid UUID | ||
poolMu.Lock() | ||
if poolPos == randPoolSize { | ||
_, err := io.ReadFull(rander, pool[:]) | ||
if err != nil { | ||
poolMu.Unlock() | ||
return Nil, err | ||
} | ||
poolPos = 0 | ||
_, err := io.ReadFull(r, uuid[:]) | ||
if err != nil { | ||
return Nil, err | ||
} | ||
copy(uuid[:], pool[poolPos:(poolPos+16)]) | ||
poolPos += 16 | ||
poolMu.Unlock() | ||
|
||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 | ||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 | ||
return uuid, nil | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package uuid | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
) | ||
|
||
func TestVersion4(t *testing.T) { | ||
v4 := &Version4{} | ||
|
||
m := make(map[UUID]bool) | ||
for x := 1; x < 32; x++ { | ||
s := v4.NewUUID() | ||
if m[s] { | ||
t.Errorf("NewUUID returned duplicated UUID %s", s) | ||
} | ||
m[s] = true | ||
uuid, err := Parse(s.String()) | ||
if err != nil { | ||
t.Errorf("NewUUID.String() returned %q which does not decode", s) | ||
continue | ||
} | ||
if v := uuid.Version(); v != 4 { | ||
t.Errorf("Random UUID of version %s", v) | ||
} | ||
if uuid.Variant() != RFC4122 { | ||
t.Errorf("Random UUID is variant %d", uuid.Variant()) | ||
} | ||
} | ||
} | ||
|
||
func TestVersion4Rand(t *testing.T) { | ||
v4 := &Version4{ | ||
Rand: bytes.NewReader([]byte{ | ||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, | ||
}), | ||
} | ||
|
||
uuid := v4.NewString() | ||
if uuid != "00010203-0405-4607-8809-0a0b0c0d0e0f" { | ||
t.Errorf("NewString returned unexpected v4 UUID: %q", uuid) | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I especially object to this and the deprecation of
NewRandom
etc. - if the library is going to provide ctor sugar, it should at least provide the most common one as the shortest!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, "deprecation" ultimately means little in the face of semantic versioning, unless and until v2 of this library rolls around. I can alter the comment to instead suggest considering using
*Version4.NewUUID()
if that would make you feel better.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not deprecated. New and NewString are the two most common ways to create a UUID. Version 4 is by far the most common type of UUID due to the issues associated with Version 1 (which are documented in the RFC).