go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/uuid/parse.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package uuid 9 10 import "errors" 11 12 // Error Classes 13 const ( 14 ErrParseInvalidUUIDInput = "parse uuid: existing uuid is invalid" 15 ErrParseInvalidLength = "parse uuid: input is an invalid length" 16 ErrParseIllegalCharacter = "parse uuid: illegal character" 17 ) 18 19 // MustParse parses a uuid and will panic if there is an error. 20 func MustParse(corpus string) (uuid UUID) { 21 if err := ParseInto(&uuid, corpus); err != nil { 22 panic(err) 23 } 24 return 25 } 26 27 // Parse parses a uuidv4 from a given string. 28 // valid forms are: 29 // - {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 30 // - xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 31 // - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 32 func Parse(corpus string) (uuid UUID, err error) { 33 err = ParseInto(&uuid, corpus) 34 return 35 } 36 37 // ParseInto parses into an existing UUID. 38 func ParseInto(uuid *UUID, corpus string) error { 39 corpusLen := len(corpus) 40 if corpusLen == 0 { 41 return nil 42 } 43 if corpusLen%2 == 1 { 44 return errors.New(ErrParseInvalidLength) 45 } 46 47 var data = []byte(corpus) 48 var c byte 49 hex := [2]byte{} 50 var hexChar byte 51 var isHexChar bool 52 var hexIndex, uuidIndex, di int 53 54 for i := 0; i < len(data); i++ { 55 c = data[i] 56 if c == '{' && i == 0 { 57 continue 58 } 59 if c == '{' { 60 return errors.New(ErrParseIllegalCharacter) 61 } 62 if c == '}' && i != len(data)-1 { 63 return errors.New(ErrParseIllegalCharacter) 64 } 65 if c == '}' { 66 continue 67 } 68 69 if c == '-' && !(di == 8 || di == 12 || di == 16 || di == 20) { 70 return errors.New(ErrParseIllegalCharacter) 71 } 72 if c == '-' { 73 continue 74 } 75 76 hexChar, isHexChar = fromHexChar(c) 77 if !isHexChar { 78 return errors.New(ErrParseIllegalCharacter) 79 } 80 81 hex[hexIndex] = hexChar 82 if hexIndex == 1 { 83 if uuidIndex >= 16 { 84 return errors.New(ErrParseInvalidLength) 85 } 86 (*uuid)[uuidIndex] = hex[0]<<4 | hex[1] 87 uuidIndex++ 88 89 hexIndex = 0 90 } else { 91 hexIndex++ 92 } 93 di++ 94 } 95 if uuidIndex != 16 { 96 return errors.New(ErrParseInvalidLength) 97 } 98 return nil 99 } 100 101 func fromHexChar(c byte) (byte, bool) { 102 switch { 103 case '0' <= c && c <= '9': 104 return c - '0', true 105 case 'a' <= c && c <= 'f': 106 return c - 'a' + 10, true 107 case 'A' <= c && c <= 'F': 108 return c - 'A' + 10, true 109 } 110 111 return 0, false 112 }