From ca85800b5d483f5128f0669383b811989f919b01 Mon Sep 17 00:00:00 2001 From: Anatoly Kussul Date: Thu, 9 Jan 2025 01:43:56 +0100 Subject: [PATCH] NewEncoder return err instead of panic --- encoder.go | 26 +++++++++++++------------- shortuuid.go | 5 ++++- shortuuid_test.go | 20 ++++++++++---------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/encoder.go b/encoder.go index 8e57238..a1b21db 100644 --- a/encoder.go +++ b/encoder.go @@ -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]), @@ -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)) @@ -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]) @@ -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) diff --git a/shortuuid.go b/shortuuid.go index e542d77..2be6f9f 100644 --- a/shortuuid.go +++ b/shortuuid.go @@ -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()) } diff --git a/shortuuid_test.go b/shortuuid_test.go index 68ceb3c..ff37fca 100644 --- a/shortuuid_test.go +++ b/shortuuid_test.go @@ -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" { @@ -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お" { @@ -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) @@ -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) @@ -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) @@ -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) } @@ -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) } @@ -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) } @@ -335,7 +335,7 @@ 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") } @@ -343,7 +343,7 @@ func BenchmarkDecodingB16(b *testing.B) { func BenchmarkDecodingB16_MB(b *testing.B) { abc := "うえおなにぬねのウエオナニヌネノ" - enc := NewEncoder(abc) + enc, _ := NewEncoder(abc) for i := 0; i < b.N; i++ { _, _ = enc.Decode("えなネノなえオオエなにナにノなのエなナなねネなネノなうえにウネお") }