diff options
Diffstat (limited to 'lib/go/thrift/uuid.go')
-rw-r--r-- | lib/go/thrift/uuid.go | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/lib/go/thrift/uuid.go b/lib/go/thrift/uuid.go new file mode 100644 index 000000000..ab47331c1 --- /dev/null +++ b/lib/go/thrift/uuid.go @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package thrift + +import ( + "encoding/hex" + "fmt" +) + +// Tuuid is a minimal implementation of UUID for thrift's read/write operations. +// +// This implementation only covers read/write in various thrift protocols. +// If you need to generate/manipulate/etc. an UUID, +// you likely would need a third party UUID library instead. +// +// This type should be directly cast-able with most popular third party UUID +// libraries. +// For example, assuming you are using +// https://pkg.go.dev/github.com/google/uuid to generate a v4 UUID for an +// optional thrift field: +// +// id, err := uuid.NewRandom() +// if err != nil { +// // TODO: handle errors +// } +// myRequest.Uuid = thrift.Pointer(thrift.Tuuid(id)) +type Tuuid [16]byte + +// String generates the canonical form string for an Tuuid. +// +// This string is suitable for writing with TJSONProtocol. +func (u Tuuid) String() string { + var buf [36]byte + hex.Encode(buf[0:], u[:4]) + buf[8] = '-' + hex.Encode(buf[9:], u[4:6]) + buf[13] = '-' + hex.Encode(buf[14:], u[6:8]) + buf[18] = '-' + hex.Encode(buf[19:], u[8:10]) + buf[23] = '-' + hex.Encode(buf[24:], u[10:]) + return string(buf[:]) +} + +func hexToDec(b byte) (byte, bool) { + switch { + case b >= '0' && b <= '9': + return b - '0', true + case b >= 'a' && b <= 'f': + return b - 'a' + 10, true + case b >= 'A' && b <= 'F': + return b - 'A' + 10, true + default: + return 0, false + } +} + +func hexToByte(b1, b2 byte) (b byte, ok bool) { + b1, ok = hexToDec(b1) + if !ok { + return 0, ok + } + b2, ok = hexToDec(b2) + if !ok { + return 0, ok + } + return b1<<4 + b2, true +} + +// ParseTuuid parses a canonical form UUID string into Tuuid. +// +// Note that this function only supports case insensitive canonical form +// (8-4-4-4-12/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx), +// and rejects any other forms. +// For a more flexible UUID string parser, +// please use third party UUID libraries. +// +// This function is suitable for reading with TJSONProtocol. +func ParseTuuid(s string) (u Tuuid, err error) { + if len(s) != 36 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return u, fmt.Errorf("malformed Tuuid string: %q", s) + } + var ok bool + for i, j := range []int{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34, + } { + u[i], ok = hexToByte(s[j], s[j+1]) + if !ok { + return u, fmt.Errorf("malformed Tuuid string: %q", s) + } + } + return u, nil +} + +// Must is a sugar to be used in places that error handling is impossible (for +// example, global variable declarations) and also errors are not in general +// expected. +// +// This is an example to use Must with ParseTuuid to declare a global special +// uuid: +// +// var NameSpaceDNSUUID = thrift.Must(thrift.ParseTuuid("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) +func Must[T any](v T, err error) T { + if err != nil { + panic(err) + } + return v +} |