18870: Need to declare NODES as array
[arvados.git] / sdk / go / blockdigest / blockdigest.go
index 0742839720c764788ccae6e505d37640e91655e8..ecb09964ecc50585a3c213a8b3cb1f8642fb5050 100644 (file)
@@ -1,25 +1,47 @@
-/* Stores a Block Locator Digest compactly. Can be used as a map key. */
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
 
+// Package blockdigest stores a Block Locator Digest compactly. Can be used as a map key.
 package blockdigest
 
 import (
        "fmt"
-       "log"
+       "regexp"
        "strconv"
+       "strings"
 )
 
-// Stores a Block Locator Digest compactly, up to 128 bits.
-// Can be used as a map key.
+var LocatorPattern = regexp.MustCompile(
+       "^[0-9a-fA-F]{32}\\+[0-9]+(\\+[A-Z][A-Za-z0-9@_-]*)*$")
+
+// BlockDigest stores a Block Locator Digest compactly, up to 128 bits. Can be
+// used as a map key.
 type BlockDigest struct {
-       h uint64
-       l uint64
+       H uint64
+       L uint64
+}
+
+type DigestWithSize struct {
+       Digest BlockDigest
+       Size   uint32
 }
 
-func (d *BlockDigest) ToString() (s string) {
-       return fmt.Sprintf("%016x%016x", d.h, d.l)
+type BlockLocator struct {
+       Digest BlockDigest
+       Size   int
+       Hints  []string
 }
 
-// Will create a new BlockDigest unless an error is encountered.
+func (d BlockDigest) String() string {
+       return fmt.Sprintf("%016x%016x", d.H, d.L)
+}
+
+func (w DigestWithSize) String() string {
+       return fmt.Sprintf("%s+%d", w.Digest.String(), w.Size)
+}
+
+// FromString creates a new BlockDigest unless an error is encountered.
 func FromString(s string) (dig BlockDigest, err error) {
        if len(s) != 32 {
                err = fmt.Errorf("Block digest should be exactly 32 characters but this one is %d: %s", len(s), s)
@@ -27,11 +49,11 @@ func FromString(s string) (dig BlockDigest, err error) {
        }
 
        var d BlockDigest
-       d.h, err = strconv.ParseUint(s[:16], 16, 64)
+       d.H, err = strconv.ParseUint(s[:16], 16, 64)
        if err != nil {
                return
        }
-       d.l, err = strconv.ParseUint(s[16:], 16, 64)
+       d.L, err = strconv.ParseUint(s[16:], 16, 64)
        if err != nil {
                return
        }
@@ -39,11 +61,33 @@ func FromString(s string) (dig BlockDigest, err error) {
        return
 }
 
-// Will fatal with the error if an error is encountered
-func AssertFromString(s string) BlockDigest {
-       d, err := FromString(s)
-       if err != nil {
-               log.Fatalf("Error creating BlockDigest from %s: %v", s, err)
+func IsBlockLocator(s string) bool {
+       return LocatorPattern.MatchString(s)
+}
+
+func ParseBlockLocator(s string) (b BlockLocator, err error) {
+       if !LocatorPattern.MatchString(s) {
+               err = fmt.Errorf("String \"%s\" does not match BlockLocator pattern "+
+                       "\"%s\".",
+                       s,
+                       LocatorPattern.String())
+       } else {
+               tokens := strings.Split(s, "+")
+               var blockSize int64
+               var blockDigest BlockDigest
+               // We expect both of the following to succeed since LocatorPattern
+               // restricts the strings appropriately.
+               blockDigest, err = FromString(tokens[0])
+               if err != nil {
+                       return
+               }
+               blockSize, err = strconv.ParseInt(tokens[1], 10, 0)
+               if err != nil {
+                       return
+               }
+               b.Digest = blockDigest
+               b.Size = int(blockSize)
+               b.Hints = tokens[2:]
        }
-       return d
+       return
 }