Merge branch '8931-event-thread-catch-exceptions' closes #8931
[arvados.git] / sdk / go / blockdigest / blockdigest.go
1 // Stores a Block Locator Digest compactly. Can be used as a map key.
2 package blockdigest
3
4 import (
5         "fmt"
6         "regexp"
7         "strconv"
8         "strings"
9 )
10
11 var LocatorPattern = regexp.MustCompile(
12         "^[0-9a-fA-F]{32}\\+[0-9]+(\\+[A-Z][A-Za-z0-9@_-]*)*$")
13
14 // Stores a Block Locator Digest compactly, up to 128 bits.
15 // Can be used as a map key.
16 type BlockDigest struct {
17         H uint64
18         L uint64
19 }
20
21 type DigestWithSize struct {
22         Digest BlockDigest
23         Size   uint32
24 }
25
26 type BlockLocator struct {
27         Digest BlockDigest
28         Size   int
29         Hints  []string
30 }
31
32 func (d BlockDigest) String() string {
33         return fmt.Sprintf("%016x%016x", d.H, d.L)
34 }
35
36 func (w DigestWithSize) String() string {
37         return fmt.Sprintf("%s+%d", w.Digest.String(), w.Size)
38 }
39
40 // Will create a new BlockDigest unless an error is encountered.
41 func FromString(s string) (dig BlockDigest, err error) {
42         if len(s) != 32 {
43                 err = fmt.Errorf("Block digest should be exactly 32 characters but this one is %d: %s", len(s), s)
44                 return
45         }
46
47         var d BlockDigest
48         d.H, err = strconv.ParseUint(s[:16], 16, 64)
49         if err != nil {
50                 return
51         }
52         d.L, err = strconv.ParseUint(s[16:], 16, 64)
53         if err != nil {
54                 return
55         }
56         dig = d
57         return
58 }
59
60 func IsBlockLocator(s string) bool {
61         return LocatorPattern.MatchString(s)
62 }
63
64 func ParseBlockLocator(s string) (b BlockLocator, err error) {
65         if !LocatorPattern.MatchString(s) {
66                 err = fmt.Errorf("String \"%s\" does not match BlockLocator pattern "+
67                         "\"%s\".",
68                         s,
69                         LocatorPattern.String())
70         } else {
71                 tokens := strings.Split(s, "+")
72                 var blockSize int64
73                 var blockDigest BlockDigest
74                 // We expect both of the following to succeed since LocatorPattern
75                 // restricts the strings appropriately.
76                 blockDigest, err = FromString(tokens[0])
77                 if err != nil {
78                         return
79                 }
80                 blockSize, err = strconv.ParseInt(tokens[1], 10, 0)
81                 if err != nil {
82                         return
83                 }
84                 b.Digest = blockDigest
85                 b.Size = int(blockSize)
86                 b.Hints = tokens[2:]
87         }
88         return
89 }