Skip to content

Commit

Permalink
NewEncoder return err instead of panic
Browse files Browse the repository at this point in the history
  • Loading branch information
anatoly-kussul committed Jan 9, 2025
1 parent 8605d12 commit ca85800
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 24 deletions.
26 changes: 13 additions & 13 deletions encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,27 @@ const (
DefaultAlphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
)

type encoder []rune
type BaseNEncoder []rune

// DefaultEncoder is the default encoder uses when generating new UUIDs, and is
// DefaultEncoder is the default BaseNEncoder uses when generating new UUIDs, and is
// based on Base57.
var DefaultEncoder = encoder(DefaultAlphabet)
var DefaultEncoder = BaseNEncoder(DefaultAlphabet)

// NewEncoder creates new encoder with given alphabet
// Remove duplicates and sort it to ensure reproducibility.
func NewEncoder(alphabet string) Encoder {
e := encoder(alphabet)
// NewEncoder creates new BaseNEncoder with given alphabet
// Removes duplicates and sort it to ensure reproducibility.
func NewEncoder(alphabet string) (BaseNEncoder, error) {
e := BaseNEncoder(alphabet)
slices.Sort(e)
e = slices.Compact(e)
if len(e) < 2 {
panic("encoding alphabet must be at least two characters")
return nil, fmt.Errorf("encoding alphabet must be at least two characters")
}
return e
return e, nil
}

// Encode encodes uuid.UUID into a string using the most significant bits (MSB)
// first according to the alphabet.
func (e encoder) Encode(u uuid.UUID) string {
func (e BaseNEncoder) Encode(u uuid.UUID) string {
num := uint128{
binary.BigEndian.Uint64(u[8:]),
binary.BigEndian.Uint64(u[:8]),
Expand All @@ -49,7 +49,7 @@ func (e encoder) Encode(u uuid.UUID) string {

// Decode decodes a string according to the alphabet into a uuid.UUID. If s is
// too short, its most significant bits (MSB) will be padded with 0 (zero).
func (e encoder) Decode(s string) (u uuid.UUID, err error) {
func (e BaseNEncoder) Decode(s string) (u uuid.UUID, err error) {
var n uint128
var index uint64
l := uint64(len(e))
Expand Down Expand Up @@ -107,7 +107,7 @@ func maxPow(b uint64) (d uint64, n int) {
return
}

func (e encoder) encode(num uint128) string {
func (e BaseNEncoder) encode(num uint128) string {
var r, ind uint64
encLen := int(math.Ceil(128 / math.Log2(float64(len(e)))))
maxBytes := utf8.RuneLen(e[len(e)-1])
Expand Down Expand Up @@ -137,7 +137,7 @@ func (e encoder) encode(num uint128) string {

// index returns the index of the first instance of t in the alphabet, or an
// error if t is not present.
func (e encoder) index(t rune) (uint64, error) {
func (e BaseNEncoder) index(t rune) (uint64, error) {
i, j := 0, len(e)
for i < j {
h := int(uint(i+j) >> 1)
Expand Down
5 changes: 4 additions & 1 deletion shortuuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ func NewWithNamespace(name string) string {
// NewWithAlphabet returns a new UUIDv4, encoded with base57 using the
// alternative alphabet abc.
func NewWithAlphabet(abc string) string {
enc := NewEncoder(abc)
enc, err := NewEncoder(abc)
if err != nil {
panic(err)
}
return enc.Encode(uuid.New())
}

Expand Down
20 changes: 10 additions & 10 deletions shortuuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func TestDecodingErrors(t *testing.T) {

func TestNewWithAlphabet(t *testing.T) {
abc := DefaultAlphabet[:len(DefaultAlphabet)-1] + "="
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
u1 := uuid.MustParse("e9ae9ba7-4fb1-4a6d-bbca-5315ed438371")
u2 := enc.Encode(u1)
if u2 != "iZsai==fWebXd5rLRWFB=u" {
Expand All @@ -215,7 +215,7 @@ func TestNewWithAlphabet(t *testing.T) {

func TestNewWithAlphabet_MultipleBytes(t *testing.T) {
abc := DefaultAlphabet[:len(DefaultAlphabet)-2] + "おネ"
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
u1 := uuid.MustParse("e9ae9ba7-4fb1-4a6d-bbca-5315ed438374")
u2 := enc.Encode(u1)
if u2 != "jatbjAAgXfcYe5sMSXGCAお" {
Expand All @@ -225,7 +225,7 @@ func TestNewWithAlphabet_MultipleBytes(t *testing.T) {

func TestNewWithAlphabet_Short(t *testing.T) {
abc := "うえ"
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
u1 := uuid.MustParse("bcee4c4f-cee8-4413-8f10-0f68d75c797b")
exp := "えうええええううえええうえええううえううええうううえううええええええううえええうえええうえううううえうううえうううううえううえええうううええええうううえううううううううええええうええうえうううええうえうえええうえうえええうううええええううえうええええうええ"
u2 := enc.Encode(u1)
Expand All @@ -245,7 +245,7 @@ func TestNewWithAlphabet_Short(t *testing.T) {

func TestAlphabetCustomLen(t *testing.T) {
abc := "21345687654123456"
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
u1 := uuid.MustParse("13ef31aa-934b-4f37-93b3-6e3ef30148e2")
exp := "1348474176355756628268227744454847411355453"
u2 := enc.Encode(u1)
Expand All @@ -265,7 +265,7 @@ func TestAlphabetCustomLen(t *testing.T) {

func TestAlphabet_MB(t *testing.T) {
abc := "うえおなにぬねのウエオナニヌネノ"
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
u1 := uuid.MustParse("13ef31aa-934b-4f37-93b3-6e3ef30148e2")
exp := "えなネノなえオオエなにナにノなのエなナなねネなネノなうえにウネお"
u2 := enc.Encode(u1)
Expand Down Expand Up @@ -303,7 +303,7 @@ func BenchmarkEncoding(b *testing.B) {
func BenchmarkEncodingB57_MB(b *testing.B) {
u := uuid.New()
abc := "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghiうえおなにぬねのウエオナニヌネノ"
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
for i := 0; i < b.N; i++ {
enc.Encode(u)
}
Expand All @@ -312,7 +312,7 @@ func BenchmarkEncodingB57_MB(b *testing.B) {
func BenchmarkEncodingB16(b *testing.B) {
u := uuid.New()
abc := "0123456789abcdef"
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
for i := 0; i < b.N; i++ {
enc.Encode(u)
}
Expand All @@ -321,7 +321,7 @@ func BenchmarkEncodingB16(b *testing.B) {
func BenchmarkEncodingB16_MB(b *testing.B) {
u := uuid.New()
abc := "うえおなにぬねのウエオナニヌネノ"
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
for i := 0; i < b.N; i++ {
enc.Encode(u)
}
Expand All @@ -335,15 +335,15 @@ func BenchmarkDecoding(b *testing.B) {

func BenchmarkDecodingB16(b *testing.B) {
abc := "0123456789abcdef"
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
for i := 0; i < b.N; i++ {
_, _ = enc.Decode("b430e18862a84ec58068d03898d94f5f")
}
}

func BenchmarkDecodingB16_MB(b *testing.B) {
abc := "うえおなにぬねのウエオナニヌネノ"
enc := NewEncoder(abc)
enc, _ := NewEncoder(abc)
for i := 0; i < b.N; i++ {
_, _ = enc.Decode("えなネノなえオオエなにナにノなのエなナなねネなネノなうえにウネお")
}
Expand Down

0 comments on commit ca85800

Please sign in to comment.