/
bytes.go
78 lines (67 loc) · 1.53 KB
/
bytes.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package cmd
import (
"errors"
"strconv"
"strings"
"unicode"
)
const (
BYTE = 1 << (10 * iota)
KILOBYTE
MEGABYTE
GIGABYTE
TERABYTE
)
var invalidByteQuantityError = errors.New("byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB")
func ToHumanReadable(bytes uint64) string {
unit := ""
value := float64(bytes)
switch {
case bytes >= TERABYTE:
unit = " TB"
value = value / TERABYTE
case bytes >= GIGABYTE:
unit = " GB"
value = value / GIGABYTE
case bytes >= MEGABYTE:
unit = " MB"
value = value / MEGABYTE
case bytes >= KILOBYTE:
unit = " KB"
value = value / KILOBYTE
case bytes >= BYTE:
unit = " B"
case bytes == 0:
return "0"
}
result := strconv.FormatFloat(value, 'f', 1, 64)
result = strings.TrimSuffix(result, ".0")
return result + unit
}
func FromHumanReadable(s string) (uint64, error) {
s = strings.TrimSpace(s)
s = strings.ToUpper(s)
i := strings.IndexFunc(s, unicode.IsLetter)
if i == -1 {
return 0, invalidByteQuantityError
}
bytesString, multiple := s[:i], s[i:]
bytes, err := strconv.ParseFloat(bytesString, 64)
if err != nil || bytes <= 0 {
return 0, invalidByteQuantityError
}
switch multiple {
case "T", "TB", "TIB":
return uint64(bytes * TERABYTE), nil
case "G", "GB", "GIB":
return uint64(bytes * GIGABYTE), nil
case "M", "MB", "MIB":
return uint64(bytes * MEGABYTE), nil
case "K", "KB", "KIB":
return uint64(bytes * KILOBYTE), nil
case "B":
return uint64(bytes), nil
default:
return 0, invalidByteQuantityError
}
}