mirror of
https://github.com/rclone/rclone.git
synced 2025-08-17 09:01:33 +02:00
Use binary prefixes for size and rate units
Includes adding support for additional size input suffix Mi and MiB, treated equivalent to M. Extends binary suffix output with letter i, e.g. Ki and Mi. Centralizes creation of bit/byte unit strings.
This commit is contained in:
159
fs/sizesuffix.go
159
fs/sizesuffix.go
@ -1,6 +1,6 @@
|
||||
package fs
|
||||
|
||||
// SizeSuffix is parsed by flag with k/M/G suffixes
|
||||
// SizeSuffix is parsed by flag with K/M/G binary suffixes
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@ -17,13 +17,21 @@ type SizeSuffix int64
|
||||
|
||||
// Common multipliers for SizeSuffix
|
||||
const (
|
||||
Byte SizeSuffix = 1 << (iota * 10)
|
||||
KibiByte
|
||||
MebiByte
|
||||
GibiByte
|
||||
TebiByte
|
||||
PebiByte
|
||||
ExbiByte
|
||||
SizeSuffixBase SizeSuffix = 1 << (iota * 10)
|
||||
Kibi
|
||||
Mebi
|
||||
Gibi
|
||||
Tebi
|
||||
Pebi
|
||||
Exbi
|
||||
)
|
||||
const (
|
||||
// SizeSuffixMax is the largest SizeSuffix multiplier
|
||||
SizeSuffixMax = Exbi
|
||||
// SizeSuffixMaxValue is the largest value that can be used to create SizeSuffix
|
||||
SizeSuffixMaxValue = math.MaxInt64
|
||||
// SizeSuffixMinValue is the smallest value that can be used to create SizeSuffix
|
||||
SizeSuffixMinValue = math.MinInt64
|
||||
)
|
||||
|
||||
// Turn SizeSuffix into a string and a suffix
|
||||
@ -35,24 +43,27 @@ func (x SizeSuffix) string() (string, string) {
|
||||
return "off", ""
|
||||
case x == 0:
|
||||
return "0", ""
|
||||
case x < 1<<10:
|
||||
case x < Kibi:
|
||||
scaled = float64(x)
|
||||
suffix = ""
|
||||
case x < 1<<20:
|
||||
scaled = float64(x) / (1 << 10)
|
||||
suffix = "k"
|
||||
case x < 1<<30:
|
||||
scaled = float64(x) / (1 << 20)
|
||||
suffix = "M"
|
||||
case x < 1<<40:
|
||||
scaled = float64(x) / (1 << 30)
|
||||
suffix = "G"
|
||||
case x < 1<<50:
|
||||
scaled = float64(x) / (1 << 40)
|
||||
suffix = "T"
|
||||
case x < Mebi:
|
||||
scaled = float64(x) / float64(Kibi)
|
||||
suffix = "Ki"
|
||||
case x < Gibi:
|
||||
scaled = float64(x) / float64(Mebi)
|
||||
suffix = "Mi"
|
||||
case x < Tebi:
|
||||
scaled = float64(x) / float64(Gibi)
|
||||
suffix = "Gi"
|
||||
case x < Pebi:
|
||||
scaled = float64(x) / float64(Tebi)
|
||||
suffix = "Ti"
|
||||
case x < Exbi:
|
||||
scaled = float64(x) / float64(Pebi)
|
||||
suffix = "Pi"
|
||||
default:
|
||||
scaled = float64(x) / (1 << 50)
|
||||
suffix = "P"
|
||||
scaled = float64(x) / float64(Exbi)
|
||||
suffix = "Ei"
|
||||
}
|
||||
if math.Floor(scaled) == scaled {
|
||||
return fmt.Sprintf("%.0f", scaled), suffix
|
||||
@ -67,12 +78,67 @@ func (x SizeSuffix) String() string {
|
||||
}
|
||||
|
||||
// Unit turns SizeSuffix into a string with a unit
|
||||
func (x SizeSuffix) Unit(unit string) string {
|
||||
func (x SizeSuffix) unit(unit string) string {
|
||||
val, suffix := x.string()
|
||||
if val == "off" {
|
||||
return val
|
||||
}
|
||||
return val + " " + suffix + unit
|
||||
var suffixUnit string
|
||||
if suffix != "" && unit != "" {
|
||||
suffixUnit = suffix + unit
|
||||
} else {
|
||||
suffixUnit = suffix + unit
|
||||
}
|
||||
return val + " " + suffixUnit
|
||||
}
|
||||
|
||||
// BitUnit turns SizeSuffix into a string with bit unit
|
||||
func (x SizeSuffix) BitUnit() string {
|
||||
return x.unit("bit")
|
||||
}
|
||||
|
||||
// BitRateUnit turns SizeSuffix into a string with bit rate unit
|
||||
func (x SizeSuffix) BitRateUnit() string {
|
||||
return x.unit("bit/s")
|
||||
}
|
||||
|
||||
// ByteUnit turns SizeSuffix into a string with byte unit
|
||||
func (x SizeSuffix) ByteUnit() string {
|
||||
return x.unit("Byte")
|
||||
}
|
||||
|
||||
// ByteRateUnit turns SizeSuffix into a string with byte rate unit
|
||||
func (x SizeSuffix) ByteRateUnit() string {
|
||||
return x.unit("Byte/s")
|
||||
}
|
||||
|
||||
// ByteShortUnit turns SizeSuffix into a string with byte unit short form
|
||||
func (x SizeSuffix) ByteShortUnit() string {
|
||||
return x.unit("B")
|
||||
}
|
||||
|
||||
// ByteRateShortUnit turns SizeSuffix into a string with byte rate unit short form
|
||||
func (x SizeSuffix) ByteRateShortUnit() string {
|
||||
return x.unit("B/s")
|
||||
}
|
||||
|
||||
func (x *SizeSuffix) multiplierFromSymbol(s byte) (found bool, multiplier float64) {
|
||||
switch s {
|
||||
case 'k', 'K':
|
||||
return true, float64(Kibi)
|
||||
case 'm', 'M':
|
||||
return true, float64(Mebi)
|
||||
case 'g', 'G':
|
||||
return true, float64(Gibi)
|
||||
case 't', 'T':
|
||||
return true, float64(Tebi)
|
||||
case 'p', 'P':
|
||||
return true, float64(Pebi)
|
||||
case 'e', 'E':
|
||||
return true, float64(Exbi)
|
||||
default:
|
||||
return false, float64(SizeSuffixBase)
|
||||
}
|
||||
}
|
||||
|
||||
// Set a SizeSuffix
|
||||
@ -86,25 +152,42 @@ func (x *SizeSuffix) Set(s string) error {
|
||||
}
|
||||
suffix := s[len(s)-1]
|
||||
suffixLen := 1
|
||||
multiplierFound := false
|
||||
var multiplier float64
|
||||
switch suffix {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.':
|
||||
suffixLen = 0
|
||||
multiplier = 1 << 10
|
||||
multiplier = float64(Kibi)
|
||||
case 'b', 'B':
|
||||
multiplier = 1
|
||||
case 'k', 'K':
|
||||
multiplier = 1 << 10
|
||||
case 'm', 'M':
|
||||
multiplier = 1 << 20
|
||||
case 'g', 'G':
|
||||
multiplier = 1 << 30
|
||||
case 't', 'T':
|
||||
multiplier = 1 << 40
|
||||
case 'p', 'P':
|
||||
multiplier = 1 << 50
|
||||
if len(s) > 2 && s[len(s)-2] == 'i' {
|
||||
suffix = s[len(s)-3]
|
||||
suffixLen = 3
|
||||
if multiplierFound, multiplier = x.multiplierFromSymbol(suffix); !multiplierFound {
|
||||
return errors.Errorf("bad suffix %q", suffix)
|
||||
}
|
||||
// Could also support SI form MB, and treat it equivalent to MiB, but perhaps better to reserve it for CountSuffix?
|
||||
//} else if len(s) > 1 {
|
||||
// suffix = s[len(s)-2]
|
||||
// if multiplierFound, multiplier = x.multiplierFromSymbol(suffix); multiplierFound {
|
||||
// suffixLen = 2
|
||||
// }
|
||||
//}
|
||||
} else {
|
||||
multiplier = float64(SizeSuffixBase)
|
||||
}
|
||||
case 'i', 'I':
|
||||
if len(s) > 1 {
|
||||
suffix = s[len(s)-2]
|
||||
suffixLen = 2
|
||||
multiplierFound, multiplier = x.multiplierFromSymbol(suffix)
|
||||
}
|
||||
if !multiplierFound {
|
||||
return errors.Errorf("bad suffix %q", suffix)
|
||||
}
|
||||
default:
|
||||
return errors.Errorf("bad suffix %q", suffix)
|
||||
if multiplierFound, multiplier = x.multiplierFromSymbol(suffix); !multiplierFound {
|
||||
return errors.Errorf("bad suffix %q", suffix)
|
||||
}
|
||||
}
|
||||
s = s[:len(s)-suffixLen]
|
||||
value, err := strconv.ParseFloat(s, 64)
|
||||
|
Reference in New Issue
Block a user