1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20package thrift 21 22import ( 23 "encoding/hex" 24 "fmt" 25) 26 27// Tuuid is a minimal implementation of UUID for thrift's read/write operations. 28// 29// This implementation only covers read/write in various thrift protocols. 30// If you need to generate/manipulate/etc. an UUID, 31// you likely would need a third party UUID library instead. 32// 33// This type should be directly cast-able with most popular third party UUID 34// libraries. 35// For example, assuming you are using 36// https://pkg.go.dev/github.com/google/uuid to generate a v4 UUID for an 37// optional thrift field: 38// 39// id, err := uuid.NewRandom() 40// if err != nil { 41// // TODO: handle errors 42// } 43// myRequest.Uuid = thrift.Pointer(thrift.Tuuid(id)) 44type Tuuid [16]byte 45 46// String generates the canonical form string for an Tuuid. 47// 48// This string is suitable for writing with TJSONProtocol. 49func (u Tuuid) String() string { 50 var buf [36]byte 51 hex.Encode(buf[0:], u[:4]) 52 buf[8] = '-' 53 hex.Encode(buf[9:], u[4:6]) 54 buf[13] = '-' 55 hex.Encode(buf[14:], u[6:8]) 56 buf[18] = '-' 57 hex.Encode(buf[19:], u[8:10]) 58 buf[23] = '-' 59 hex.Encode(buf[24:], u[10:]) 60 return string(buf[:]) 61} 62 63func hexToDec(b byte) (byte, bool) { 64 switch { 65 case b >= '0' && b <= '9': 66 return b - '0', true 67 case b >= 'a' && b <= 'f': 68 return b - 'a' + 10, true 69 case b >= 'A' && b <= 'F': 70 return b - 'A' + 10, true 71 default: 72 return 0, false 73 } 74} 75 76func hexToByte(b1, b2 byte) (b byte, ok bool) { 77 b1, ok = hexToDec(b1) 78 if !ok { 79 return 0, ok 80 } 81 b2, ok = hexToDec(b2) 82 if !ok { 83 return 0, ok 84 } 85 return b1<<4 + b2, true 86} 87 88// ParseTuuid parses a canonical form UUID string into Tuuid. 89// 90// Note that this function only supports case insensitive canonical form 91// (8-4-4-4-12/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx), 92// and rejects any other forms. 93// For a more flexible UUID string parser, 94// please use third party UUID libraries. 95// 96// This function is suitable for reading with TJSONProtocol. 97func ParseTuuid(s string) (u Tuuid, err error) { 98 if len(s) != 36 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { 99 return u, fmt.Errorf("malformed Tuuid string: %q", s) 100 } 101 var ok bool 102 for i, j := range []int{ 103 0, 2, 4, 6, 104 9, 11, 105 14, 16, 106 19, 21, 107 24, 26, 28, 30, 32, 34, 108 } { 109 u[i], ok = hexToByte(s[j], s[j+1]) 110 if !ok { 111 return u, fmt.Errorf("malformed Tuuid string: %q", s) 112 } 113 } 114 return u, nil 115} 116 117// Must is a sugar to be used in places that error handling is impossible (for 118// example, global variable declarations) and also errors are not in general 119// expected. 120// 121// This is an example to use Must with ParseTuuid to declare a global special 122// uuid: 123// 124// var NameSpaceDNSUUID = thrift.Must(thrift.ParseTuuid("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) 125func Must[T any](v T, err error) T { 126 if err != nil { 127 panic(err) 128 } 129 return v 130} 131