github.com/blend/go-sdk@v1.20220411.3/uuid/uuid.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package uuid 9 10 import ( 11 "bytes" 12 "database/sql/driver" 13 "encoding/hex" 14 "encoding/json" 15 "fmt" 16 "strings" 17 18 "github.com/blend/go-sdk/ex" 19 ) 20 21 // ErrInvalidScanSource is an error returned by scan. 22 const ( 23 ErrInvalidScanSource ex.Class = "uuid: invalid scan source" 24 ) 25 26 // Zero is the empty UUID. 27 var ( 28 Zero UUID = Empty() 29 ) 30 31 // Empty returns an empty uuid. 32 func Empty() UUID { 33 return UUID(make([]byte, 16)) 34 } 35 36 // UUID represents a unique identifier conforming to the RFC 4122 standard. 37 // UUIDs are a fixed 128bit (16 byte) binary blob. 38 type UUID []byte 39 40 // Equal returns if a uuid is equal to another uuid. 41 func (uuid UUID) Equal(other UUID) bool { 42 return bytes.Equal(uuid[0:], other[0:]) 43 } 44 45 // Compare returns a comparison between the two uuids. 46 func (uuid UUID) Compare(other UUID) int { 47 return bytes.Compare(uuid[0:], other[0:]) 48 } 49 50 // ToFullString returns a "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" hex representation of a uuid. 51 func (uuid UUID) ToFullString() string { 52 if len(uuid) == 0 { 53 return "" 54 } 55 b := []byte(uuid) 56 return fmt.Sprintf( 57 "%08x-%04x-%04x-%04x-%012x", 58 b[:4], b[4:6], b[6:8], b[8:10], b[10:], 59 ) 60 } 61 62 // ToShortString returns a hex representation of the uuid. 63 func (uuid UUID) ToShortString() string { 64 return hex.EncodeToString([]byte(uuid)) 65 } 66 67 // String is an alias for `ToShortString`. 68 func (uuid UUID) String() string { 69 return hex.EncodeToString([]byte(uuid)) 70 } 71 72 // Version returns the version byte of a uuid. 73 func (uuid UUID) Version() byte { 74 return uuid[6] >> 4 75 } 76 77 // Format allows for conditional expansion in printf statements 78 // based on the token and flags used. 79 func (uuid UUID) Format(s fmt.State, verb rune) { 80 switch verb { 81 case 'v': 82 if s.Flag('+') { 83 fmt.Fprint(s, uuid.ToFullString()) 84 return 85 } 86 fmt.Fprint(s, uuid.String()) 87 case 's': 88 fmt.Fprint(s, uuid.String()) 89 case 'q': 90 fmt.Fprintf(s, "%b", uuid.Version()) 91 } 92 } 93 94 // IsZero returns if the uuid is unset. 95 func (uuid UUID) IsZero() bool { 96 if len(uuid) == 0 { 97 return true 98 } 99 return bytes.Equal(uuid, Zero) 100 } 101 102 // IsV4 returns true iff uuid has version number 4, variant number 2, and length 16 bytes 103 func (uuid UUID) IsV4() bool { 104 if len(uuid) != 16 { 105 return false 106 } 107 // check that version number is 4 108 if (uuid[6]&0xf0)^0x40 != 0 { 109 return false 110 } 111 // check that variant is 2 112 return (uuid[8]&0xc0)^0x80 == 0 113 } 114 115 // Marshal implements bytes marshal. 116 func (uuid UUID) Marshal() ([]byte, error) { 117 if len(uuid) == 0 { 118 return nil, nil 119 } 120 return []byte(uuid), nil 121 } 122 123 // MarshalTo marshals the uuid to a buffer. 124 func (uuid UUID) MarshalTo(data []byte) (n int, err error) { 125 if len(uuid) == 0 { 126 return 0, nil 127 } 128 copy(data, uuid) 129 return 16, nil 130 } 131 132 // Unmarshal implements bytes unmarshal. 133 func (uuid *UUID) Unmarshal(data []byte) error { 134 if len(data) == 0 { 135 return nil 136 } 137 var id UUID = Empty() 138 copy(id, data) 139 *uuid = id 140 return nil 141 } 142 143 // Size returns the size of the uuid. 144 func (uuid *UUID) Size() int { 145 if uuid == nil { 146 return 0 147 } 148 if len(*uuid) == 0 { 149 return 0 150 } 151 return 16 152 } 153 154 // MarshalJSON marshals a uuid as json. 155 func (uuid UUID) MarshalJSON() ([]byte, error) { 156 return json.Marshal(uuid.ToFullString()) 157 } 158 159 // UnmarshalJSON unmarshals a uuid from json. 160 func (uuid *UUID) UnmarshalJSON(corpus []byte) error { 161 if len(*uuid) == 0 { 162 (*uuid) = Empty() 163 } 164 raw := strings.TrimSpace(string(corpus)) 165 raw = strings.TrimPrefix(raw, "\"") 166 raw = strings.TrimSuffix(raw, "\"") 167 return ParseExisting(uuid, raw) 168 } 169 170 // MarshalYAML marshals a uuid as yaml. 171 func (uuid UUID) MarshalYAML() (interface{}, error) { 172 return uuid.ToFullString(), nil 173 } 174 175 // UnmarshalYAML unmarshals a uuid from yaml. 176 func (uuid *UUID) UnmarshalYAML(unmarshaler func(interface{}) error) error { 177 if len(*uuid) == 0 { 178 (*uuid) = Empty() 179 } 180 181 var corpus string 182 if err := unmarshaler(&corpus); err != nil { 183 return err 184 } 185 186 raw := strings.TrimSpace(string(corpus)) 187 raw = strings.TrimPrefix(raw, "\"") 188 raw = strings.TrimSuffix(raw, "\"") 189 return ParseExisting(uuid, raw) 190 } 191 192 // Scan scans a uuid from a db value. 193 func (uuid *UUID) Scan(src interface{}) error { 194 if len(*uuid) == 0 { 195 (*uuid) = Empty() 196 } 197 switch v := src.(type) { 198 case string: 199 return ParseExisting(uuid, v) 200 case []byte: 201 return ParseExisting(uuid, string(v)) 202 default: 203 return ex.New(ErrInvalidScanSource, ex.OptMessagef("scan type: %T", src)) 204 } 205 } 206 207 // Value returns a sql driver value. 208 func (uuid UUID) Value() (driver.Value, error) { 209 if uuid == nil || len(uuid) == 0 { 210 return nil, nil 211 } 212 return uuid.String(), nil 213 }