Skip to content
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

unify import paths under /v4 #62

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,30 @@ content of the license.

## Recommended Package Version

We recommend using v2.0.0+ of this package, as versions prior to 2.0.0 were
created before our fork of the original package and have some known
deficiencies.
For new users, we recommend using v4.0.0+ of this package, under the
import path `github.com/gofrs/uuid/v4`. For users who need a replacement
for `satori/go.uuid` at v1.2.0, we recommend v2.1.0 under the import path
`github.com/gofrs/uuid`. Versions prior to 2.0.0 were created before our fork
of the original package and have some known deficiencies, so we recommend
against using them.

Versions prior to v4.0.0 may exhibit issues with import paths, as described
in more detail by [#61](https://github.com/gofrs/uuid/issues/61).

The v4.0.0 release fixes [#61](https://github.com/gofrs/uuid/issues/61),
and unifies import paths under `github.com/gofrs/uuid/v4`. Here is what
this means for users:

If you are using modules, importing `github.com/gofrs/uuid/v3` will
resolve to v3.1.2 with `+incompatible`. Importing `github.com/gofrs/uuid`
with modules will also resolve to v3.1.2. Existing code will continue to
work. To resolve the `+incompatible` issue, upgrade to v4.0.0+, under the
new unified import path: `github.com/gofrs/uuid/v4`.

If you are not using modules, or if you are using a version of Go without
"minimal module awareness" (these versions are 1.9.7+, 1.10.3+ and 1.11+),
importing `github.com/gofrs/uuid` will resolve to at most v3.1.2, while
importing `github.com/gofrs/uuid/v4` will give you access to v4.0.0+.

## Installation

Expand All @@ -50,7 +71,7 @@ If you are unable to make use of a dependency manager with your project, you can
use the `go get` command to download it directly:

```Shell
$ go get github.com/gofrs/uuid
$ go get github.com/gofrs/uuid/v4
```

## Requirements
Expand All @@ -62,15 +83,15 @@ Go 1.2+, but support for these older versions is not actively maintained.
## Usage

Here is a quick overview of how to use this package. For more detailed
documentation, please see the [GoDoc Page](http://godoc.org/github.com/gofrs/uuid).
documentation, please see the [GoDoc Page](http://godoc.org/github.com/gofrs/uuid/v4).

```go
package main

import (
"log"

"github.com/gofrs/uuid"
"github.com/gofrs/uuid/v4"
)

// Create a Version 4 UUID, panicking on error.
Expand Down
1 change: 0 additions & 1 deletion go.mod

This file was deleted.

212 changes: 212 additions & 0 deletions v4/codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
//
// 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.

package uuid

import (
"bytes"
"encoding/hex"
"fmt"
)

// FromBytes returns a UUID generated from the raw byte slice input.
// It will return an error if the slice isn't 16 bytes long.
func FromBytes(input []byte) (UUID, error) {
u := UUID{}
err := u.UnmarshalBinary(input)
return u, err
}

// FromBytesOrNil returns a UUID generated from the raw byte slice input.
// Same behavior as FromBytes(), but returns uuid.Nil instead of an error.
func FromBytesOrNil(input []byte) UUID {
uuid, err := FromBytes(input)
if err != nil {
return Nil
}
return uuid
}

// FromString returns a UUID parsed from the input string.
// Input is expected in a form accepted by UnmarshalText.
func FromString(input string) (UUID, error) {
u := UUID{}
err := u.UnmarshalText([]byte(input))
return u, err
}

// FromStringOrNil returns a UUID parsed from the input string.
// Same behavior as FromString(), but returns uuid.Nil instead of an error.
func FromStringOrNil(input string) UUID {
uuid, err := FromString(input)
if err != nil {
return Nil
}
return uuid
}

// MarshalText implements the encoding.TextMarshaler interface.
// The encoding is the same as returned by the String() method.
func (u UUID) MarshalText() ([]byte, error) {
return []byte(u.String()), nil
}

// UnmarshalText implements the encoding.TextUnmarshaler interface.
// Following formats are supported:
//
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
// "6ba7b8109dad11d180b400c04fd430c8"
// "{6ba7b8109dad11d180b400c04fd430c8}",
// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8"
//
// ABNF for supported UUID text representation follows:
//
// URN := 'urn'
// UUID-NID := 'uuid'
//
// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
// 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
//
// hexoct := hexdig hexdig
// 2hexoct := hexoct hexoct
// 4hexoct := 2hexoct 2hexoct
// 6hexoct := 4hexoct 2hexoct
// 12hexoct := 6hexoct 6hexoct
//
// hashlike := 12hexoct
// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
//
// plain := canonical | hashlike
// uuid := canonical | hashlike | braced | urn
//
// braced := '{' plain '}' | '{' hashlike '}'
// urn := URN ':' UUID-NID ':' plain
//
func (u *UUID) UnmarshalText(text []byte) error {
switch len(text) {
case 32:
return u.decodeHashLike(text)
case 34, 38:
return u.decodeBraced(text)
case 36:
return u.decodeCanonical(text)
case 41, 45:
return u.decodeURN(text)
default:
return fmt.Errorf("uuid: incorrect UUID length: %s", text)
}
}

// decodeCanonical decodes UUID strings that are formatted as defined in RFC-4122 (section 3):
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
func (u *UUID) decodeCanonical(t []byte) error {
if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' {
return fmt.Errorf("uuid: incorrect UUID format %s", t)
}

src := t
dst := u[:]

for i, byteGroup := range byteGroups {
if i > 0 {
src = src[1:] // skip dash
}
_, err := hex.Decode(dst[:byteGroup/2], src[:byteGroup])
if err != nil {
return err
}
src = src[byteGroup:]
dst = dst[byteGroup/2:]
}

return nil
}

// decodeHashLike decodes UUID strings that are using the following format:
// "6ba7b8109dad11d180b400c04fd430c8".
func (u *UUID) decodeHashLike(t []byte) error {
src := t[:]
dst := u[:]

_, err := hex.Decode(dst, src)
return err
}

// decodeBraced decodes UUID strings that are using the following formats:
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}"
// "{6ba7b8109dad11d180b400c04fd430c8}".
func (u *UUID) decodeBraced(t []byte) error {
l := len(t)

if t[0] != '{' || t[l-1] != '}' {
return fmt.Errorf("uuid: incorrect UUID format %s", t)
}

return u.decodePlain(t[1 : l-1])
}

// decodeURN decodes UUID strings that are using the following formats:
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8".
func (u *UUID) decodeURN(t []byte) error {
total := len(t)

urnUUIDPrefix := t[:9]

if !bytes.Equal(urnUUIDPrefix, urnPrefix) {
return fmt.Errorf("uuid: incorrect UUID format: %s", t)
}

return u.decodePlain(t[9:total])
}

// decodePlain decodes UUID strings that are using the following formats:
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format
// "6ba7b8109dad11d180b400c04fd430c8".
func (u *UUID) decodePlain(t []byte) error {
switch len(t) {
case 32:
return u.decodeHashLike(t)
case 36:
return u.decodeCanonical(t)
default:
return fmt.Errorf("uuid: incorrrect UUID length: %s", t)
}
}

// MarshalBinary implements the encoding.BinaryMarshaler interface.
func (u UUID) MarshalBinary() ([]byte, error) {
return u.Bytes(), nil
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
// It will return an error if the slice isn't 16 bytes long.
func (u *UUID) UnmarshalBinary(data []byte) error {
if len(data) != Size {
return fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
}
copy(u[:], data)

return nil
}
Loading