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:
@@ -300,15 +300,13 @@ func (s *StatsInfo) String() string {
|
||||
dateString = ""
|
||||
elapsedTime = time.Since(startTime)
|
||||
elapsedTimeSecondsOnly = elapsedTime.Truncate(time.Second/10) % time.Minute
|
||||
displaySpeed = ts.speed
|
||||
displaySpeedUnit string
|
||||
displaySpeedString string
|
||||
)
|
||||
|
||||
if s.ci.DataRateUnit == "bits" {
|
||||
displaySpeed *= 8
|
||||
displaySpeedUnit = "bit/s"
|
||||
displaySpeedString = fs.SizeSuffix(ts.speed * 8).BitRateUnit()
|
||||
} else {
|
||||
displaySpeedUnit = "Byte/s"
|
||||
displaySpeedString = fs.SizeSuffix(ts.speed).ByteRateUnit()
|
||||
}
|
||||
|
||||
if !s.ci.StatsOneLine {
|
||||
@@ -330,12 +328,12 @@ func (s *StatsInfo) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(buf, "%s%10s / %s, %s, %s, ETA %s%s",
|
||||
_, _ = fmt.Fprintf(buf, "%s%11s / %s, %s, %s, ETA %s%s",
|
||||
dateString,
|
||||
fs.SizeSuffix(s.bytes),
|
||||
fs.SizeSuffix(ts.totalBytes).Unit("Byte"),
|
||||
fs.SizeSuffix(ts.totalBytes).ByteUnit(),
|
||||
percent(s.bytes, ts.totalBytes),
|
||||
fs.SizeSuffix(displaySpeed).Unit(displaySpeedUnit),
|
||||
displaySpeedString,
|
||||
etaString(s.bytes, ts.totalBytes, ts.speed),
|
||||
xfrchkString,
|
||||
)
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestRcBwLimit(t *testing.T) {
|
||||
"bytesPerSecond": int64(1048576),
|
||||
"bytesPerSecondTx": int64(1048576),
|
||||
"bytesPerSecondRx": int64(1048576),
|
||||
"rate": "1M",
|
||||
"rate": "1Mi",
|
||||
}, out)
|
||||
assert.Equal(t, rate.Limit(1048576), TokenBucket.curr[0].Limit())
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestRcBwLimit(t *testing.T) {
|
||||
"bytesPerSecond": int64(1048576),
|
||||
"bytesPerSecondTx": int64(1048576),
|
||||
"bytesPerSecondRx": int64(1048576),
|
||||
"rate": "1M",
|
||||
"rate": "1Mi",
|
||||
}, out)
|
||||
|
||||
// Set
|
||||
@@ -49,7 +49,7 @@ func TestRcBwLimit(t *testing.T) {
|
||||
"bytesPerSecond": int64(10485760),
|
||||
"bytesPerSecondTx": int64(10485760),
|
||||
"bytesPerSecondRx": int64(1048576),
|
||||
"rate": "10M:1M",
|
||||
"rate": "10Mi:1Mi",
|
||||
}, out)
|
||||
assert.Equal(t, rate.Limit(10485760), TokenBucket.curr[0].Limit())
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestRcBwLimit(t *testing.T) {
|
||||
"bytesPerSecond": int64(10485760),
|
||||
"bytesPerSecondTx": int64(10485760),
|
||||
"bytesPerSecondRx": int64(1048576),
|
||||
"rate": "10M:1M",
|
||||
"rate": "10Mi:1Mi",
|
||||
}, out)
|
||||
|
||||
// Reset
|
||||
|
||||
+14
-14
@@ -43,7 +43,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 0, HHMM: 0, Bandwidth: BwPair{Tx: 666 * 1024, Rx: 666 * 1024}},
|
||||
},
|
||||
false,
|
||||
"666k",
|
||||
"666Ki",
|
||||
},
|
||||
{
|
||||
"666:333",
|
||||
@@ -51,7 +51,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 0, HHMM: 0, Bandwidth: BwPair{Tx: 666 * 1024, Rx: 333 * 1024}},
|
||||
},
|
||||
false,
|
||||
"666k:333k",
|
||||
"666Ki:333Ki",
|
||||
},
|
||||
{
|
||||
"10:20,666",
|
||||
@@ -65,7 +65,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 6, HHMM: 1020, Bandwidth: BwPair{Tx: 666 * 1024, Rx: 666 * 1024}},
|
||||
},
|
||||
false,
|
||||
"Sun-10:20,666k Mon-10:20,666k Tue-10:20,666k Wed-10:20,666k Thu-10:20,666k Fri-10:20,666k Sat-10:20,666k",
|
||||
"Sun-10:20,666Ki Mon-10:20,666Ki Tue-10:20,666Ki Wed-10:20,666Ki Thu-10:20,666Ki Fri-10:20,666Ki Sat-10:20,666Ki",
|
||||
},
|
||||
{
|
||||
"10:20,666:333",
|
||||
@@ -79,7 +79,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 6, HHMM: 1020, Bandwidth: BwPair{Tx: 666 * 1024, Rx: 333 * 1024}},
|
||||
},
|
||||
false,
|
||||
"Sun-10:20,666k:333k Mon-10:20,666k:333k Tue-10:20,666k:333k Wed-10:20,666k:333k Thu-10:20,666k:333k Fri-10:20,666k:333k Sat-10:20,666k:333k",
|
||||
"Sun-10:20,666Ki:333Ki Mon-10:20,666Ki:333Ki Tue-10:20,666Ki:333Ki Wed-10:20,666Ki:333Ki Thu-10:20,666Ki:333Ki Fri-10:20,666Ki:333Ki Sat-10:20,666Ki:333Ki",
|
||||
},
|
||||
{
|
||||
"11:00,333 13:40,666 23:50,10M 23:59,off",
|
||||
@@ -114,7 +114,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 6, HHMM: 2359, Bandwidth: BwPair{Tx: -1, Rx: -1}},
|
||||
},
|
||||
false,
|
||||
"Sun-11:00,333k Mon-11:00,333k Tue-11:00,333k Wed-11:00,333k Thu-11:00,333k Fri-11:00,333k Sat-11:00,333k Sun-13:40,666k Mon-13:40,666k Tue-13:40,666k Wed-13:40,666k Thu-13:40,666k Fri-13:40,666k Sat-13:40,666k Sun-23:50,10M Mon-23:50,10M Tue-23:50,10M Wed-23:50,10M Thu-23:50,10M Fri-23:50,10M Sat-23:50,10M Sun-23:59,off Mon-23:59,off Tue-23:59,off Wed-23:59,off Thu-23:59,off Fri-23:59,off Sat-23:59,off",
|
||||
"Sun-11:00,333Ki Mon-11:00,333Ki Tue-11:00,333Ki Wed-11:00,333Ki Thu-11:00,333Ki Fri-11:00,333Ki Sat-11:00,333Ki Sun-13:40,666Ki Mon-13:40,666Ki Tue-13:40,666Ki Wed-13:40,666Ki Thu-13:40,666Ki Fri-13:40,666Ki Sat-13:40,666Ki Sun-23:50,10Mi Mon-23:50,10Mi Tue-23:50,10Mi Wed-23:50,10Mi Thu-23:50,10Mi Fri-23:50,10Mi Sat-23:50,10Mi Sun-23:59,off Mon-23:59,off Tue-23:59,off Wed-23:59,off Thu-23:59,off Fri-23:59,off Sat-23:59,off",
|
||||
},
|
||||
{
|
||||
"11:00,333:666 13:40,666:off 23:50,10M:1M 23:59,off:10M",
|
||||
@@ -149,7 +149,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 6, HHMM: 2359, Bandwidth: BwPair{Tx: -1, Rx: 10 * 1024 * 1024}},
|
||||
},
|
||||
false,
|
||||
"Sun-11:00,333k:666k Mon-11:00,333k:666k Tue-11:00,333k:666k Wed-11:00,333k:666k Thu-11:00,333k:666k Fri-11:00,333k:666k Sat-11:00,333k:666k Sun-13:40,666k:off Mon-13:40,666k:off Tue-13:40,666k:off Wed-13:40,666k:off Thu-13:40,666k:off Fri-13:40,666k:off Sat-13:40,666k:off Sun-23:50,10M:1M Mon-23:50,10M:1M Tue-23:50,10M:1M Wed-23:50,10M:1M Thu-23:50,10M:1M Fri-23:50,10M:1M Sat-23:50,10M:1M Sun-23:59,off:10M Mon-23:59,off:10M Tue-23:59,off:10M Wed-23:59,off:10M Thu-23:59,off:10M Fri-23:59,off:10M Sat-23:59,off:10M",
|
||||
"Sun-11:00,333Ki:666Ki Mon-11:00,333Ki:666Ki Tue-11:00,333Ki:666Ki Wed-11:00,333Ki:666Ki Thu-11:00,333Ki:666Ki Fri-11:00,333Ki:666Ki Sat-11:00,333Ki:666Ki Sun-13:40,666Ki:off Mon-13:40,666Ki:off Tue-13:40,666Ki:off Wed-13:40,666Ki:off Thu-13:40,666Ki:off Fri-13:40,666Ki:off Sat-13:40,666Ki:off Sun-23:50,10Mi:1Mi Mon-23:50,10Mi:1Mi Tue-23:50,10Mi:1Mi Wed-23:50,10Mi:1Mi Thu-23:50,10Mi:1Mi Fri-23:50,10Mi:1Mi Sat-23:50,10Mi:1Mi Sun-23:59,off:10Mi Mon-23:59,off:10Mi Tue-23:59,off:10Mi Wed-23:59,off:10Mi Thu-23:59,off:10Mi Fri-23:59,off:10Mi Sat-23:59,off:10Mi",
|
||||
},
|
||||
{
|
||||
"Mon-11:00,333 Tue-13:40,666:333 Fri-00:00,10M Sat-10:00,off Sun-23:00,666",
|
||||
@@ -161,7 +161,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 0, HHMM: 2300, Bandwidth: BwPair{Tx: 666 * 1024, Rx: 666 * 1024}},
|
||||
},
|
||||
false,
|
||||
"Mon-11:00,333k Tue-13:40,666k:333k Fri-00:00,10M Sat-10:00,off Sun-23:00,666k",
|
||||
"Mon-11:00,333Ki Tue-13:40,666Ki:333Ki Fri-00:00,10Mi Sat-10:00,off Sun-23:00,666Ki",
|
||||
},
|
||||
{
|
||||
"Mon-11:00,333 Tue-13:40,666 Fri-00:00,10M 00:01,off Sun-23:00,666:off",
|
||||
@@ -179,7 +179,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 0, HHMM: 2300, Bandwidth: BwPair{Tx: 666 * 1024, Rx: -1}},
|
||||
},
|
||||
false,
|
||||
"Mon-11:00,333k Tue-13:40,666k Fri-00:00,10M Sun-00:01,off Mon-00:01,off Tue-00:01,off Wed-00:01,off Thu-00:01,off Fri-00:01,off Sat-00:01,off Sun-23:00,666k:off",
|
||||
"Mon-11:00,333Ki Tue-13:40,666Ki Fri-00:00,10Mi Sun-00:01,off Mon-00:01,off Tue-00:01,off Wed-00:01,off Thu-00:01,off Fri-00:01,off Sat-00:01,off Sun-23:00,666Ki:off",
|
||||
},
|
||||
{
|
||||
// from the docs
|
||||
@@ -222,7 +222,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 6, HHMM: 2300, Bandwidth: BwPair{Tx: -1, Rx: -1}},
|
||||
},
|
||||
false,
|
||||
"Sun-08:00,512k Mon-08:00,512k Tue-08:00,512k Wed-08:00,512k Thu-08:00,512k Fri-08:00,512k Sat-08:00,512k Sun-12:00,10M Mon-12:00,10M Tue-12:00,10M Wed-12:00,10M Thu-12:00,10M Fri-12:00,10M Sat-12:00,10M Sun-13:00,512k Mon-13:00,512k Tue-13:00,512k Wed-13:00,512k Thu-13:00,512k Fri-13:00,512k Sat-13:00,512k Sun-18:00,30M Mon-18:00,30M Tue-18:00,30M Wed-18:00,30M Thu-18:00,30M Fri-18:00,30M Sat-18:00,30M Sun-23:00,off Mon-23:00,off Tue-23:00,off Wed-23:00,off Thu-23:00,off Fri-23:00,off Sat-23:00,off",
|
||||
"Sun-08:00,512Ki Mon-08:00,512Ki Tue-08:00,512Ki Wed-08:00,512Ki Thu-08:00,512Ki Fri-08:00,512Ki Sat-08:00,512Ki Sun-12:00,10Mi Mon-12:00,10Mi Tue-12:00,10Mi Wed-12:00,10Mi Thu-12:00,10Mi Fri-12:00,10Mi Sat-12:00,10Mi Sun-13:00,512Ki Mon-13:00,512Ki Tue-13:00,512Ki Wed-13:00,512Ki Thu-13:00,512Ki Fri-13:00,512Ki Sat-13:00,512Ki Sun-18:00,30Mi Mon-18:00,30Mi Tue-18:00,30Mi Wed-18:00,30Mi Thu-18:00,30Mi Fri-18:00,30Mi Sat-18:00,30Mi Sun-23:00,off Mon-23:00,off Tue-23:00,off Wed-23:00,off Thu-23:00,off Fri-23:00,off Sat-23:00,off",
|
||||
},
|
||||
{
|
||||
// from the docs
|
||||
@@ -234,7 +234,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 0, HHMM: 2000, Bandwidth: BwPair{Tx: -1, Rx: -1}},
|
||||
},
|
||||
false,
|
||||
"Mon-00:00,512k Fri-23:59,10M Sat-10:00,1M Sun-20:00,off",
|
||||
"Mon-00:00,512Ki Fri-23:59,10Mi Sat-10:00,1Mi Sun-20:00,off",
|
||||
},
|
||||
{
|
||||
// from the docs
|
||||
@@ -251,7 +251,7 @@ func TestBwTimetableSet(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 0, HHMM: 2000, Bandwidth: BwPair{Tx: -1, Rx: -1}},
|
||||
},
|
||||
false,
|
||||
"Mon-00:00,512k Sun-12:00,1M Mon-12:00,1M Tue-12:00,1M Wed-12:00,1M Thu-12:00,1M Fri-12:00,1M Sat-12:00,1M Sun-20:00,off",
|
||||
"Mon-00:00,512Ki Sun-12:00,1Mi Mon-12:00,1Mi Tue-12:00,1Mi Wed-12:00,1Mi Thu-12:00,1Mi Fri-12:00,1Mi Sat-12:00,1Mi Sun-20:00,off",
|
||||
},
|
||||
} {
|
||||
tt := BwTimetable{}
|
||||
@@ -537,13 +537,13 @@ func TestBwTimetableMarshalJSON(t *testing.T) {
|
||||
BwTimetable{
|
||||
BwTimeSlot{DayOfTheWeek: 0, HHMM: 0, Bandwidth: BwPair{Tx: 666 * 1024, Rx: 666 * 1024}},
|
||||
},
|
||||
`"666k"`,
|
||||
`"666Ki"`,
|
||||
},
|
||||
{
|
||||
BwTimetable{
|
||||
BwTimeSlot{DayOfTheWeek: 0, HHMM: 0, Bandwidth: BwPair{Tx: 666 * 1024, Rx: 333 * 1024}},
|
||||
},
|
||||
`"666k:333k"`,
|
||||
`"666Ki:333Ki"`,
|
||||
},
|
||||
{
|
||||
BwTimetable{
|
||||
@@ -555,7 +555,7 @@ func TestBwTimetableMarshalJSON(t *testing.T) {
|
||||
BwTimeSlot{DayOfTheWeek: 5, HHMM: 1020, Bandwidth: BwPair{Tx: 666 * 1024, Rx: 666 * 1024}},
|
||||
BwTimeSlot{DayOfTheWeek: 6, HHMM: 1020, Bandwidth: BwPair{Tx: 666 * 1024, Rx: 666 * 1024}},
|
||||
},
|
||||
`"Sun-10:20,666k Mon-10:20,666k Tue-10:20,666k Wed-10:20,666k Thu-10:20,666k Fri-10:20,666k Sat-10:20,666k"`,
|
||||
`"Sun-10:20,666Ki Mon-10:20,666Ki Tue-10:20,666Ki Wed-10:20,666Ki Thu-10:20,666Ki Fri-10:20,666Ki Sat-10:20,666Ki"`,
|
||||
},
|
||||
} {
|
||||
got, err := json.Marshal(test.in)
|
||||
|
||||
@@ -97,8 +97,8 @@ func AddFlags(ci *fs.ConfigInfo, flagSet *pflag.FlagSet) {
|
||||
flags.IntVarP(flagSet, &ci.StatsFileNameLength, "stats-file-name-length", "", ci.StatsFileNameLength, "Max file name length in stats. 0 for no limit")
|
||||
flags.FVarP(flagSet, &ci.LogLevel, "log-level", "", "Log level DEBUG|INFO|NOTICE|ERROR")
|
||||
flags.FVarP(flagSet, &ci.StatsLogLevel, "stats-log-level", "", "Log level to show --stats output DEBUG|INFO|NOTICE|ERROR")
|
||||
flags.FVarP(flagSet, &ci.BwLimit, "bwlimit", "", "Bandwidth limit in kByte/s, or use suffix b|k|M|G or a full timetable.")
|
||||
flags.FVarP(flagSet, &ci.BwLimitFile, "bwlimit-file", "", "Bandwidth limit per file in kByte/s, or use suffix b|k|M|G or a full timetable.")
|
||||
flags.FVarP(flagSet, &ci.BwLimit, "bwlimit", "", "Bandwidth limit in KiByte/s, or use suffix B|K|M|G|T|P or a full timetable.")
|
||||
flags.FVarP(flagSet, &ci.BwLimitFile, "bwlimit-file", "", "Bandwidth limit per file in KiByte/s, or use suffix B|K|M|G|T|P or a full timetable.")
|
||||
flags.FVarP(flagSet, &ci.BufferSize, "buffer-size", "", "In memory buffer size when reading files for each --transfer.")
|
||||
flags.FVarP(flagSet, &ci.StreamingUploadCutoff, "streaming-upload-cutoff", "", "Cutoff for switching to chunked upload if file size is unknown. Upload starts after reaching cutoff or when file ends.")
|
||||
flags.FVarP(flagSet, &ci.Dump, "dump", "", "List of items to dump from: "+fs.DumpFlagsList)
|
||||
|
||||
+1
-1
@@ -353,7 +353,7 @@ func ChooseOption(o *fs.Option, name string) string {
|
||||
case bool:
|
||||
what = "boolean value (true or false)"
|
||||
case fs.SizeSuffix:
|
||||
what = "size with suffix k,M,G,T"
|
||||
what = "size with suffix K,M,G,T"
|
||||
case fs.Duration:
|
||||
what = "duration s,m,h,d,w,M,y"
|
||||
case int, int8, int16, int32, int64:
|
||||
|
||||
@@ -41,8 +41,8 @@ func AddFlags(flagSet *pflag.FlagSet) {
|
||||
flags.StringArrayVarP(flagSet, &Opt.FilesFromRaw, "files-from-raw", "", nil, "Read list of source-file names from file without any processing of lines (use - to read from stdin)")
|
||||
flags.FVarP(flagSet, &Opt.MinAge, "min-age", "", "Only transfer files older than this in s or suffix ms|s|m|h|d|w|M|y")
|
||||
flags.FVarP(flagSet, &Opt.MaxAge, "max-age", "", "Only transfer files younger than this in s or suffix ms|s|m|h|d|w|M|y")
|
||||
flags.FVarP(flagSet, &Opt.MinSize, "min-size", "", "Only transfer files bigger than this in k or suffix b|k|M|G")
|
||||
flags.FVarP(flagSet, &Opt.MaxSize, "max-size", "", "Only transfer files smaller than this in k or suffix b|k|M|G")
|
||||
flags.FVarP(flagSet, &Opt.MinSize, "min-size", "", "Only transfer files bigger than this in KiB or suffix B|K|M|G|T|P")
|
||||
flags.FVarP(flagSet, &Opt.MaxSize, "max-size", "", "Only transfer files smaller than this in KiB or suffix B|K|M|G|T|P")
|
||||
flags.BoolVarP(flagSet, &Opt.IgnoreCase, "ignore-case", "", false, "Ignore case in filters (case insensitive)")
|
||||
//cvsExclude = BoolP("cvs-exclude", "C", false, "Exclude files in the same way CVS does")
|
||||
}
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ func TestOption(t *testing.T) {
|
||||
Name: "potato",
|
||||
Value: SizeSuffix(17 << 20),
|
||||
}
|
||||
assert.Equal(t, "17M", d.String())
|
||||
assert.Equal(t, "17Mi", d.String())
|
||||
assert.Equal(t, "SizeSuffix", d.Type())
|
||||
err := d.Set("18M")
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -257,7 +257,7 @@ func TestExecuteJobWithConfig(t *testing.T) {
|
||||
called := false
|
||||
jobFn := func(ctx context.Context, in rc.Params) (rc.Params, error) {
|
||||
ci := fs.GetConfig(ctx)
|
||||
assert.Equal(t, 42*fs.MebiByte, ci.BufferSize)
|
||||
assert.Equal(t, 42*fs.Mebi, ci.BufferSize)
|
||||
called = true
|
||||
return nil, nil
|
||||
}
|
||||
@@ -278,7 +278,7 @@ func TestExecuteJobWithConfig(t *testing.T) {
|
||||
assert.Equal(t, true, called)
|
||||
// Check that wasn't the default
|
||||
ci := fs.GetConfig(ctx)
|
||||
assert.NotEqual(t, 42*fs.MebiByte, ci.BufferSize)
|
||||
assert.NotEqual(t, 42*fs.Mebi, ci.BufferSize)
|
||||
}
|
||||
|
||||
func TestExecuteJobWithFilter(t *testing.T) {
|
||||
|
||||
+121
-38
@@ -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)
|
||||
|
||||
+81
-17
@@ -27,11 +27,11 @@ func TestSizeSuffixString(t *testing.T) {
|
||||
}{
|
||||
{0, "0"},
|
||||
{102, "102"},
|
||||
{1024, "1k"},
|
||||
{1024 * 1024, "1M"},
|
||||
{1024 * 1024 * 1024, "1G"},
|
||||
{10 * 1024 * 1024 * 1024, "10G"},
|
||||
{10.1 * 1024 * 1024 * 1024, "10.100G"},
|
||||
{1024, "1Ki"},
|
||||
{1024 * 1024, "1Mi"},
|
||||
{1024 * 1024 * 1024, "1Gi"},
|
||||
{10 * 1024 * 1024 * 1024, "10Gi"},
|
||||
{10.1 * 1024 * 1024 * 1024, "10.100Gi"},
|
||||
{-1, "off"},
|
||||
{-100, "off"},
|
||||
} {
|
||||
@@ -41,26 +41,73 @@ func TestSizeSuffixString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSizeSuffixUnit(t *testing.T) {
|
||||
func TestSizeSuffixByteShortUnit(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in float64
|
||||
want string
|
||||
}{
|
||||
{0, "0 Bytes"},
|
||||
{102, "102 Bytes"},
|
||||
{1024, "1 kBytes"},
|
||||
{1024 * 1024, "1 MBytes"},
|
||||
{1024 * 1024 * 1024, "1 GBytes"},
|
||||
{10 * 1024 * 1024 * 1024, "10 GBytes"},
|
||||
{10.1 * 1024 * 1024 * 1024, "10.100 GBytes"},
|
||||
{10 * 1024 * 1024 * 1024 * 1024, "10 TBytes"},
|
||||
{10 * 1024 * 1024 * 1024 * 1024 * 1024, "10 PBytes"},
|
||||
{1 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, "1024 PBytes"},
|
||||
{0, "0 B"},
|
||||
{102, "102 B"},
|
||||
{1024, "1 KiB"},
|
||||
{1024 * 1024, "1 MiB"},
|
||||
{1024 * 1024 * 1024, "1 GiB"},
|
||||
{10 * 1024 * 1024 * 1024, "10 GiB"},
|
||||
{10.1 * 1024 * 1024 * 1024, "10.100 GiB"},
|
||||
{10 * 1024 * 1024 * 1024 * 1024, "10 TiB"},
|
||||
{10 * 1024 * 1024 * 1024 * 1024 * 1024, "10 PiB"},
|
||||
{1 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, "1 EiB"},
|
||||
{-1, "off"},
|
||||
{-100, "off"},
|
||||
} {
|
||||
ss := SizeSuffix(test.in)
|
||||
got := ss.Unit("Bytes")
|
||||
got := ss.ByteShortUnit()
|
||||
assert.Equal(t, test.want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSizeSuffixByteUnit(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in float64
|
||||
want string
|
||||
}{
|
||||
{0, "0 Byte"},
|
||||
{102, "102 Byte"},
|
||||
{1024, "1 KiByte"},
|
||||
{1024 * 1024, "1 MiByte"},
|
||||
{1024 * 1024 * 1024, "1 GiByte"},
|
||||
{10 * 1024 * 1024 * 1024, "10 GiByte"},
|
||||
{10.1 * 1024 * 1024 * 1024, "10.100 GiByte"},
|
||||
{10 * 1024 * 1024 * 1024 * 1024, "10 TiByte"},
|
||||
{10 * 1024 * 1024 * 1024 * 1024 * 1024, "10 PiByte"},
|
||||
{1 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, "1 EiByte"},
|
||||
{-1, "off"},
|
||||
{-100, "off"},
|
||||
} {
|
||||
ss := SizeSuffix(test.in)
|
||||
got := ss.ByteUnit()
|
||||
assert.Equal(t, test.want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSizeSuffixBitRateUnit(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in float64
|
||||
want string
|
||||
}{
|
||||
{0, "0 bit/s"},
|
||||
{1024, "1 Kibit/s"},
|
||||
{1024 * 1024, "1 Mibit/s"},
|
||||
{1024 * 1024 * 1024, "1 Gibit/s"},
|
||||
{10 * 1024 * 1024 * 1024, "10 Gibit/s"},
|
||||
{10.1 * 1024 * 1024 * 1024, "10.100 Gibit/s"},
|
||||
{10 * 1024 * 1024 * 1024 * 1024, "10 Tibit/s"},
|
||||
{10 * 1024 * 1024 * 1024 * 1024 * 1024, "10 Pibit/s"},
|
||||
{1 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, "1 Eibit/s"},
|
||||
{-1, "off"},
|
||||
{-100, "off"},
|
||||
} {
|
||||
ss := SizeSuffix(test.in)
|
||||
got := ss.BitRateUnit()
|
||||
assert.Equal(t, test.want, got)
|
||||
}
|
||||
}
|
||||
@@ -77,9 +124,23 @@ func TestSizeSuffixSet(t *testing.T) {
|
||||
{"0.1k", 102, false},
|
||||
{"0.1", 102, false},
|
||||
{"1K", 1024, false},
|
||||
{"1k", 1024, false},
|
||||
//{"1KB", 1024, false},
|
||||
//{"1kB", 1024, false},
|
||||
//{"1kb", 1024, false},
|
||||
{"1KI", 1024, false},
|
||||
{"1Ki", 1024, false},
|
||||
{"1kI", 1024, false},
|
||||
{"1ki", 1024, false},
|
||||
{"1KiB", 1024, false},
|
||||
{"1KiB", 1024, false},
|
||||
{"1kib", 1024, false},
|
||||
{"1", 1024, false},
|
||||
{"2.5", 1024 * 2.5, false},
|
||||
{"1M", 1024 * 1024, false},
|
||||
//{"1MB", 1024 * 1024, false},
|
||||
{"1Mi", 1024 * 1024, false},
|
||||
{"1MiB", 1024 * 1024, false},
|
||||
{"1.g", 1024 * 1024 * 1024, false},
|
||||
{"10G", 10 * 1024 * 1024 * 1024, false},
|
||||
{"10T", 10 * 1024 * 1024 * 1024 * 1024, false},
|
||||
@@ -91,6 +152,9 @@ func TestSizeSuffixSet(t *testing.T) {
|
||||
{"1.q", 0, true},
|
||||
{"1q", 0, true},
|
||||
{"-1K", 0, true},
|
||||
{"1i", 0, true},
|
||||
{"1iB", 0, true},
|
||||
{"1MB", 0, true},
|
||||
} {
|
||||
ss := SizeSuffix(0)
|
||||
err := ss.Set(test.in)
|
||||
|
||||
Reference in New Issue
Block a user