diff --git a/decor/counters.go b/decor/counters.go index 0022fc0..f4c9764 100644 --- a/decor/counters.go +++ b/decor/counters.go @@ -2,24 +2,6 @@ import ( "fmt" - "io" - "strconv" - "strings" -) - -const ( - _ = iota - KiB = 1 << (iota * 10) - MiB - GiB - TiB -) - -const ( - KB = 1000 - MB = KB * 1000 - GB = MB * 1000 - TB = GB * 1000 ) const ( @@ -27,114 +9,6 @@ UnitKiB UnitKB ) - -type CounterKiB int64 - -func (c CounterKiB) Format(st fmt.State, verb rune) { - var prec int - switch verb { - case 'd': - case 's': - prec = -1 - default: - if p, ok := st.Precision(); ok { - prec = p - } else { - prec = 6 - } - } - - var res, unit string - switch { - case c >= TiB: - unit = "TiB" - res = strconv.FormatFloat(float64(c)/TiB, 'f', prec, 64) - case c >= GiB: - unit = "GiB" - res = strconv.FormatFloat(float64(c)/GiB, 'f', prec, 64) - case c >= MiB: - unit = "MiB" - res = strconv.FormatFloat(float64(c)/MiB, 'f', prec, 64) - case c >= KiB: - unit = "KiB" - res = strconv.FormatFloat(float64(c)/KiB, 'f', prec, 64) - default: - unit = "b" - res = strconv.FormatInt(int64(c), 10) - } - - if st.Flag(' ') { - res += " " - } - res += unit - - if w, ok := st.Width(); ok { - if len(res) < w { - pad := strings.Repeat(" ", w-len(res)) - if st.Flag('-') { - res += pad - } else { - res = pad + res - } - } - } - - io.WriteString(st, res) -} - -type CounterKB int64 - -func (c CounterKB) Format(st fmt.State, verb rune) { - var prec int - switch verb { - case 'd': - case 's': - prec = -1 - default: - if p, ok := st.Precision(); ok { - prec = p - } else { - prec = 6 - } - } - - var res, unit string - switch { - case c >= TB: - unit = "TB" - res = strconv.FormatFloat(float64(c)/TB, 'f', prec, 64) - case c >= GB: - unit = "GB" - res = strconv.FormatFloat(float64(c)/GB, 'f', prec, 64) - case c >= MB: - unit = "MB" - res = strconv.FormatFloat(float64(c)/MB, 'f', prec, 64) - case c >= KB: - unit = "kB" - res = strconv.FormatFloat(float64(c)/KB, 'f', prec, 64) - default: - unit = "b" - res = strconv.FormatInt(int64(c), 10) - } - - if st.Flag(' ') { - res += " " - } - res += unit - - if w, ok := st.Width(); ok { - if len(res) < w { - pad := strings.Repeat(" ", w-len(res)) - if st.Flag('-') { - res += pad - } else { - res = pad + res - } - } - } - - io.WriteString(st, res) -} // CountersNoUnit is a wrapper around Counters with no unit param. func CountersNoUnit(pairFmt string, wcc ...WC) Decorator { @@ -191,17 +65,17 @@ return d.FormatMsg(*d.completeMsg) } - var str string + var res string switch d.unit { case UnitKiB: - str = fmt.Sprintf(d.pairFmt, CounterKiB(st.Current), CounterKiB(st.Total)) + res = fmt.Sprintf(d.pairFmt, SizeB1024(st.Current), SizeB1024(st.Total)) case UnitKB: - str = fmt.Sprintf(d.pairFmt, CounterKB(st.Current), CounterKB(st.Total)) + res = fmt.Sprintf(d.pairFmt, SizeB1000(st.Current), SizeB1000(st.Total)) default: - str = fmt.Sprintf(d.pairFmt, st.Current, st.Total) + res = fmt.Sprintf(d.pairFmt, st.Current, st.Total) } - return d.FormatMsg(str) + return d.FormatMsg(res) } func (d *countersDecorator) OnCompleteMessage(msg string) { diff --git a/decor/counters_test.go b/decor/counters_test.go deleted file mode 100644 index 01e7915..0000000 --- a/decor/counters_test.go +++ /dev/null @@ -1,142 +0,0 @@ -package decor - -import ( - "fmt" - "testing" -) - -func TestCounterKiB(t *testing.T) { - cases := map[string]struct { - value int64 - verb string - expected string - }{ - "verb %f": {12345678, "%f", "11.773756MiB"}, - "verb %.0f": {12345678, "%.0f", "12MiB"}, - "verb %.1f": {12345678, "%.1f", "11.8MiB"}, - "verb %.2f": {12345678, "%.2f", "11.77MiB"}, - "verb %.3f": {12345678, "%.3f", "11.774MiB"}, - - "verb % f": {12345678, "% f", "11.773756 MiB"}, - "verb % .0f": {12345678, "% .0f", "12 MiB"}, - "verb % .1f": {12345678, "% .1f", "11.8 MiB"}, - "verb % .2f": {12345678, "% .2f", "11.77 MiB"}, - "verb % .3f": {12345678, "% .3f", "11.774 MiB"}, - - "verb %8.f": {12345678, "%8.f", " 12MiB"}, - "verb %8.0f": {12345678, "%8.0f", " 12MiB"}, - "verb %8.1f": {12345678, "%8.1f", " 11.8MiB"}, - "verb %8.2f": {12345678, "%8.2f", "11.77MiB"}, - "verb %8.3f": {12345678, "%8.3f", "11.774MiB"}, - - "verb % 8.f": {12345678, "% 8.f", " 12 MiB"}, - "verb % 8.0f": {12345678, "% 8.0f", " 12 MiB"}, - "verb % 8.1f": {12345678, "% 8.1f", "11.8 MiB"}, - - "verb %-8.f": {12345678, "%-8.f", "12MiB "}, - "verb %-8.0f": {12345678, "%-8.0f", "12MiB "}, - "verb %-8.1f": {12345678, "%-8.1f", "11.8MiB "}, - "verb %-8.2f": {12345678, "%8.2f", "11.77MiB"}, - "verb %-8.3f": {12345678, "%8.3f", "11.774MiB"}, - - "verb % -8.f": {12345678, "% -8.f", "12 MiB "}, - "verb % -8.0f": {12345678, "% -8.0f", "12 MiB "}, - "verb % -8.1f": {12345678, "% -8.1f", "11.8 MiB"}, - - "1000 %f": {1000, "%f", "1000b"}, - "1000 %d": {1000, "%d", "1000b"}, - "1000 %s": {1000, "%s", "1000b"}, - "1024 %f": {1024, "%f", "1.000000KiB"}, - "1024 %d": {1024, "%d", "1KiB"}, - "1024 %.1f": {1024, "%.1f", "1.0KiB"}, - "1024 %s": {1024, "%s", "1KiB"}, - "3*MiB+140KiB %f": {3*MiB + 140*KiB, "%f", "3.136719MiB"}, - "3*MiB+140KiB %d": {3*MiB + 140*KiB, "%d", "3MiB"}, - "3*MiB+140KiB %.1f": {3*MiB + 140*KiB, "%.1f", "3.1MiB"}, - "3*MiB+140KiB %s": {3*MiB + 140*KiB, "%s", "3.13671875MiB"}, - "2*GiB %f": {2 * GiB, "%f", "2.000000GiB"}, - "2*GiB %d": {2 * GiB, "%d", "2GiB"}, - "2*GiB %.1f": {2 * GiB, "%.1f", "2.0GiB"}, - "2*GiB %s": {2 * GiB, "%s", "2GiB"}, - "4*TiB %f": {4 * TiB, "%f", "4.000000TiB"}, - "4*TiB %d": {4 * TiB, "%d", "4TiB"}, - "4*TiB %.1f": {4 * TiB, "%.1f", "4.0TiB"}, - "4*TiB %s": {4 * TiB, "%s", "4TiB"}, - } - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - got := fmt.Sprintf(tc.verb, CounterKiB(tc.value)) - if got != tc.expected { - t.Fatalf("expected: %q, got: %q\n", tc.expected, got) - } - }) - } -} - -func TestCounterKB(t *testing.T) { - cases := map[string]struct { - value int64 - verb string - expected string - }{ - "verb %f": {12345678, "%f", "12.345678MB"}, - "verb %.0f": {12345678, "%.0f", "12MB"}, - "verb %.1f": {12345678, "%.1f", "12.3MB"}, - "verb %.2f": {12345678, "%.2f", "12.35MB"}, - "verb %.3f": {12345678, "%.3f", "12.346MB"}, - - "verb % f": {12345678, "% f", "12.345678 MB"}, - "verb % .0f": {12345678, "% .0f", "12 MB"}, - "verb % .1f": {12345678, "% .1f", "12.3 MB"}, - "verb % .2f": {12345678, "% .2f", "12.35 MB"}, - "verb % .3f": {12345678, "% .3f", "12.346 MB"}, - - "verb %8.f": {12345678, "%8.f", " 12MB"}, - "verb %8.0f": {12345678, "%8.0f", " 12MB"}, - "verb %8.1f": {12345678, "%8.1f", " 12.3MB"}, - "verb %8.2f": {12345678, "%8.2f", " 12.35MB"}, - "verb %8.3f": {12345678, "%8.3f", "12.346MB"}, - - "verb % 8.f": {12345678, "% 8.f", " 12 MB"}, - "verb % 8.0f": {12345678, "% 8.0f", " 12 MB"}, - "verb % 8.1f": {12345678, "% 8.1f", " 12.3 MB"}, - - "verb %-8.f": {12345678, "%-8.f", "12MB "}, - "verb %-8.0f": {12345678, "%-8.0f", "12MB "}, - "verb %-8.1f": {12345678, "%-8.1f", "12.3MB "}, - "verb %-8.2f": {12345678, "%8.2f", " 12.35MB"}, - "verb %-8.3f": {12345678, "%8.3f", "12.346MB"}, - - "verb % -8.f": {12345678, "% -8.f", "12 MB "}, - "verb % -8.0f": {12345678, "% -8.0f", "12 MB "}, - "verb % -8.1f": {12345678, "% -8.1f", "12.3 MB "}, - - "1000 %f": {1000, "%f", "1.000000kB"}, - "1000 %d": {1000, "%d", "1kB"}, - "1000 %s": {1000, "%s", "1kB"}, - "1024 %f": {1024, "%f", "1.024000kB"}, - "1024 %d": {1024, "%d", "1kB"}, - "1024 %.1f": {1024, "%.1f", "1.0kB"}, - "1024 %s": {1024, "%s", "1.024kB"}, - "3*MB+140*KB %f": {3*MB + 140*KB, "%f", "3.140000MB"}, - "3*MB+140*KB %d": {3*MB + 140*KB, "%d", "3MB"}, - "3*MB+140*KB %.1f": {3*MB + 140*KB, "%.1f", "3.1MB"}, - "3*MB+140*KB %s": {3*MB + 140*KB, "%s", "3.14MB"}, - "2*GB %f": {2 * GB, "%f", "2.000000GB"}, - "2*GB %d": {2 * GB, "%d", "2GB"}, - "2*GB %.1f": {2 * GB, "%.1f", "2.0GB"}, - "2*GB %s": {2 * GB, "%s", "2GB"}, - "4*TB %f": {4 * TB, "%f", "4.000000TB"}, - "4*TB %d": {4 * TB, "%d", "4TB"}, - "4*TB %.1f": {4 * TB, "%.1f", "4.0TB"}, - "4*TB %s": {4 * TB, "%s", "4TB"}, - } - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - got := fmt.Sprintf(tc.verb, CounterKB(tc.value)) - if got != tc.expected { - t.Fatalf("expected: %q, got: %q\n", tc.expected, got) - } - }) - } -} diff --git a/decor/size_type.go b/decor/size_type.go new file mode 100644 index 0000000..a450c6c --- /dev/null +++ b/decor/size_type.go @@ -0,0 +1,143 @@ +package decor + +import ( + "fmt" + "io" + "math" + "strconv" + "strings" +) + +const ( + _ib SizeB1024 = iota + _iKiB SizeB1024 = 1 << (iota * 10) + _iMiB + _iGiB + _iTiB +) + +//go:generate stringer -type=SizeB1024 -trimprefix=_i +type SizeB1024 int64 + +func (self SizeB1024) Format(st fmt.State, verb rune) { + var prec int + switch verb { + case 'd': + case 's': + prec = -1 + default: + if p, ok := st.Precision(); ok { + prec = p + } else { + prec = 6 + } + } + + var b strings.Builder + var unit SizeB1024 + switch { + case self < _iKiB: + unit = _ib + b.WriteString(strconv.FormatFloat(float64(self), 'f', prec, 64)) + case self < _iMiB: + unit = _iKiB + b.WriteString(strconv.FormatFloat(float64(self)/float64(_iKiB), 'f', prec, 64)) + case self < _iGiB: + unit = _iMiB + b.WriteString(strconv.FormatFloat(float64(self)/float64(_iMiB), 'f', prec, 64)) + case self < _iTiB: + unit = _iGiB + b.WriteString(strconv.FormatFloat(float64(self)/float64(_iGiB), 'f', prec, 64)) + case self <= math.MaxInt64: + unit = _iTiB + b.WriteString(strconv.FormatFloat(float64(self)/float64(_iTiB), 'f', prec, 64)) + } + + if st.Flag(' ') { + b.WriteString(" ") + } + b.WriteString(unit.String()) + + if w, ok := st.Width(); ok { + if l := b.Len(); l < w { + pad := strings.Repeat(" ", w-l) + if st.Flag('-') { + b.WriteString(pad) + } else { + tmp := b.String() + b.Reset() + b.WriteString(pad) + b.WriteString(tmp) + } + } + } + + io.WriteString(st, b.String()) +} + +const ( + _b SizeB1000 = 0 + _KB SizeB1000 = 1000 + _MB SizeB1000 = _KB * 1000 + _GB SizeB1000 = _MB * 1000 + _TB SizeB1000 = _GB * 1000 +) + +//go:generate stringer -type=SizeB1000 -trimprefix=_ +type SizeB1000 int64 + +func (self SizeB1000) Format(st fmt.State, verb rune) { + var prec int + switch verb { + case 'd': + case 's': + prec = -1 + default: + if p, ok := st.Precision(); ok { + prec = p + } else { + prec = 6 + } + } + + var b strings.Builder + var unit SizeB1000 + switch { + case self < _KB: + unit = _b + b.WriteString(strconv.FormatFloat(float64(self), 'f', prec, 64)) + case self < _MB: + unit = _KB + b.WriteString(strconv.FormatFloat(float64(self)/float64(_KB), 'f', prec, 64)) + case self < _GB: + unit = _MB + b.WriteString(strconv.FormatFloat(float64(self)/float64(_MB), 'f', prec, 64)) + case self < _TB: + unit = _GB + b.WriteString(strconv.FormatFloat(float64(self)/float64(_GB), 'f', prec, 64)) + case self <= math.MaxInt64: + unit = _TB + b.WriteString(strconv.FormatFloat(float64(self)/float64(_TB), 'f', prec, 64)) + } + + if st.Flag(' ') { + b.WriteString(" ") + } + b.WriteString(unit.String()) + + if w, ok := st.Width(); ok { + if l := b.Len(); l < w { + pad := strings.Repeat(" ", w-l) + if st.Flag('-') { + b.WriteString(pad) + } else { + tmp := b.String() + b.Reset() + b.WriteString(pad) + b.WriteString(tmp) + } + } + } + + io.WriteString(st, b.String()) +} diff --git a/decor/size_type_test.go b/decor/size_type_test.go new file mode 100644 index 0000000..2bae4a6 --- /dev/null +++ b/decor/size_type_test.go @@ -0,0 +1,142 @@ +package decor + +import ( + "fmt" + "testing" +) + +func TestB1024(t *testing.T) { + cases := map[string]struct { + value int64 + verb string + expected string + }{ + "verb %f": {12345678, "%f", "11.773756MiB"}, + "verb %.0f": {12345678, "%.0f", "12MiB"}, + "verb %.1f": {12345678, "%.1f", "11.8MiB"}, + "verb %.2f": {12345678, "%.2f", "11.77MiB"}, + "verb %.3f": {12345678, "%.3f", "11.774MiB"}, + + "verb % f": {12345678, "% f", "11.773756 MiB"}, + "verb % .0f": {12345678, "% .0f", "12 MiB"}, + "verb % .1f": {12345678, "% .1f", "11.8 MiB"}, + "verb % .2f": {12345678, "% .2f", "11.77 MiB"}, + "verb % .3f": {12345678, "% .3f", "11.774 MiB"}, + + "verb %8.f": {12345678, "%8.f", " 12MiB"}, + "verb %8.0f": {12345678, "%8.0f", " 12MiB"}, + "verb %8.1f": {12345678, "%8.1f", " 11.8MiB"}, + "verb %8.2f": {12345678, "%8.2f", "11.77MiB"}, + "verb %8.3f": {12345678, "%8.3f", "11.774MiB"}, + + "verb % 8.f": {12345678, "% 8.f", " 12 MiB"}, + "verb % 8.0f": {12345678, "% 8.0f", " 12 MiB"}, + "verb % 8.1f": {12345678, "% 8.1f", "11.8 MiB"}, + + "verb %-8.f": {12345678, "%-8.f", "12MiB "}, + "verb %-8.0f": {12345678, "%-8.0f", "12MiB "}, + "verb %-8.1f": {12345678, "%-8.1f", "11.8MiB "}, + "verb %-8.2f": {12345678, "%8.2f", "11.77MiB"}, + "verb %-8.3f": {12345678, "%8.3f", "11.774MiB"}, + + "verb % -8.f": {12345678, "% -8.f", "12 MiB "}, + "verb % -8.0f": {12345678, "% -8.0f", "12 MiB "}, + "verb % -8.1f": {12345678, "% -8.1f", "11.8 MiB"}, + + "1000 %f": {1000, "%f", "1000.000000b"}, + "1000 %d": {1000, "%d", "1000b"}, + "1000 %s": {1000, "%s", "1000b"}, + "1024 %f": {1024, "%f", "1.000000KiB"}, + "1024 %d": {1024, "%d", "1KiB"}, + "1024 %.1f": {1024, "%.1f", "1.0KiB"}, + "1024 %s": {1024, "%s", "1KiB"}, + "3*MiB+140KiB %f": {3*int64(_iMiB) + 140*int64(_iKiB), "%f", "3.136719MiB"}, + "3*MiB+140KiB %d": {3*int64(_iMiB) + 140*int64(_iKiB), "%d", "3MiB"}, + "3*MiB+140KiB %.1f": {3*int64(_iMiB) + 140*int64(_iKiB), "%.1f", "3.1MiB"}, + "3*MiB+140KiB %s": {3*int64(_iMiB) + 140*int64(_iKiB), "%s", "3.13671875MiB"}, + "2*GiB %f": {2 * int64(_iGiB), "%f", "2.000000GiB"}, + "2*GiB %d": {2 * int64(_iGiB), "%d", "2GiB"}, + "2*GiB %.1f": {2 * int64(_iGiB), "%.1f", "2.0GiB"}, + "2*GiB %s": {2 * int64(_iGiB), "%s", "2GiB"}, + "4*TiB %f": {4 * int64(_iTiB), "%f", "4.000000TiB"}, + "4*TiB %d": {4 * int64(_iTiB), "%d", "4TiB"}, + "4*TiB %.1f": {4 * int64(_iTiB), "%.1f", "4.0TiB"}, + "4*TiB %s": {4 * int64(_iTiB), "%s", "4TiB"}, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got := fmt.Sprintf(tc.verb, SizeB1024(tc.value)) + if got != tc.expected { + t.Fatalf("expected: %q, got: %q\n", tc.expected, got) + } + }) + } +} + +func TestB1000(t *testing.T) { + cases := map[string]struct { + value int64 + verb string + expected string + }{ + "verb %f": {12345678, "%f", "12.345678MB"}, + "verb %.0f": {12345678, "%.0f", "12MB"}, + "verb %.1f": {12345678, "%.1f", "12.3MB"}, + "verb %.2f": {12345678, "%.2f", "12.35MB"}, + "verb %.3f": {12345678, "%.3f", "12.346MB"}, + + "verb % f": {12345678, "% f", "12.345678 MB"}, + "verb % .0f": {12345678, "% .0f", "12 MB"}, + "verb % .1f": {12345678, "% .1f", "12.3 MB"}, + "verb % .2f": {12345678, "% .2f", "12.35 MB"}, + "verb % .3f": {12345678, "% .3f", "12.346 MB"}, + + "verb %8.f": {12345678, "%8.f", " 12MB"}, + "verb %8.0f": {12345678, "%8.0f", " 12MB"}, + "verb %8.1f": {12345678, "%8.1f", " 12.3MB"}, + "verb %8.2f": {12345678, "%8.2f", " 12.35MB"}, + "verb %8.3f": {12345678, "%8.3f", "12.346MB"}, + + "verb % 8.f": {12345678, "% 8.f", " 12 MB"}, + "verb % 8.0f": {12345678, "% 8.0f", " 12 MB"}, + "verb % 8.1f": {12345678, "% 8.1f", " 12.3 MB"}, + + "verb %-8.f": {12345678, "%-8.f", "12MB "}, + "verb %-8.0f": {12345678, "%-8.0f", "12MB "}, + "verb %-8.1f": {12345678, "%-8.1f", "12.3MB "}, + "verb %-8.2f": {12345678, "%8.2f", " 12.35MB"}, + "verb %-8.3f": {12345678, "%8.3f", "12.346MB"}, + + "verb % -8.f": {12345678, "% -8.f", "12 MB "}, + "verb % -8.0f": {12345678, "% -8.0f", "12 MB "}, + "verb % -8.1f": {12345678, "% -8.1f", "12.3 MB "}, + + "1000 %f": {1000, "%f", "1.000000KB"}, + "1000 %d": {1000, "%d", "1KB"}, + "1000 %s": {1000, "%s", "1KB"}, + "1024 %f": {1024, "%f", "1.024000KB"}, + "1024 %d": {1024, "%d", "1KB"}, + "1024 %.1f": {1024, "%.1f", "1.0KB"}, + "1024 %s": {1024, "%s", "1.024KB"}, + "3*MB+140*KB %f": {3*int64(_MB) + 140*int64(_KB), "%f", "3.140000MB"}, + "3*MB+140*KB %d": {3*int64(_MB) + 140*int64(_KB), "%d", "3MB"}, + "3*MB+140*KB %.1f": {3*int64(_MB) + 140*int64(_KB), "%.1f", "3.1MB"}, + "3*MB+140*KB %s": {3*int64(_MB) + 140*int64(_KB), "%s", "3.14MB"}, + "2*GB %f": {2 * int64(_GB), "%f", "2.000000GB"}, + "2*GB %d": {2 * int64(_GB), "%d", "2GB"}, + "2*GB %.1f": {2 * int64(_GB), "%.1f", "2.0GB"}, + "2*GB %s": {2 * int64(_GB), "%s", "2GB"}, + "4*TB %f": {4 * int64(_TB), "%f", "4.000000TB"}, + "4*TB %d": {4 * int64(_TB), "%d", "4TB"}, + "4*TB %.1f": {4 * int64(_TB), "%.1f", "4.0TB"}, + "4*TB %s": {4 * int64(_TB), "%s", "4TB"}, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got := fmt.Sprintf(tc.verb, SizeB1000(tc.value)) + if got != tc.expected { + t.Fatalf("expected: %q, got: %q\n", tc.expected, got) + } + }) + } +} diff --git a/decor/sizeb1000_string.go b/decor/sizeb1000_string.go new file mode 100644 index 0000000..0207a57 --- /dev/null +++ b/decor/sizeb1000_string.go @@ -0,0 +1,41 @@ +// Code generated by "stringer -type=SizeB1000 -trimprefix=_"; DO NOT EDIT. + +package decor + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[_b-0] + _ = x[_KB-1000] + _ = x[_MB-1000000] + _ = x[_GB-1000000000] + _ = x[_TB-1000000000000] +} + +const ( + _SizeB1000_name_0 = "b" + _SizeB1000_name_1 = "KB" + _SizeB1000_name_2 = "MB" + _SizeB1000_name_3 = "GB" + _SizeB1000_name_4 = "TB" +) + +func (i SizeB1000) String() string { + switch { + case i == 0: + return _SizeB1000_name_0 + case i == 1000: + return _SizeB1000_name_1 + case i == 1000000: + return _SizeB1000_name_2 + case i == 1000000000: + return _SizeB1000_name_3 + case i == 1000000000000: + return _SizeB1000_name_4 + default: + return "SizeB1000(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/decor/sizeb1024_string.go b/decor/sizeb1024_string.go new file mode 100644 index 0000000..8538236 --- /dev/null +++ b/decor/sizeb1024_string.go @@ -0,0 +1,41 @@ +// Code generated by "stringer -type=SizeB1024 -trimprefix=_i"; DO NOT EDIT. + +package decor + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[_ib-0] + _ = x[_iKiB-1024] + _ = x[_iMiB-1048576] + _ = x[_iGiB-1073741824] + _ = x[_iTiB-1099511627776] +} + +const ( + _SizeB1024_name_0 = "b" + _SizeB1024_name_1 = "KiB" + _SizeB1024_name_2 = "MiB" + _SizeB1024_name_3 = "GiB" + _SizeB1024_name_4 = "TiB" +) + +func (i SizeB1024) String() string { + switch { + case i == 0: + return _SizeB1024_name_0 + case i == 1024: + return _SizeB1024_name_1 + case i == 1048576: + return _SizeB1024_name_2 + case i == 1073741824: + return _SizeB1024_name_3 + case i == 1099511627776: + return _SizeB1024_name_4 + default: + return "SizeB1024(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/decor/speed.go b/decor/speed.go index 21b687d..679c683 100644 --- a/decor/speed.go +++ b/decor/speed.go @@ -2,122 +2,11 @@ import ( "fmt" - "io" "math" - "strconv" - "strings" "time" "github.com/VividCortex/ewma" ) - -type SpeedKiB float64 - -func (s SpeedKiB) Format(st fmt.State, verb rune) { - var prec int - switch verb { - case 'd': - case 's': - prec = -1 - default: - if p, ok := st.Precision(); ok { - prec = p - } else { - prec = 6 - } - } - - var res, unit string - switch { - case s >= TiB: - unit = "TiB/s" - res = strconv.FormatFloat(float64(s)/TiB, 'f', prec, 64) - case s >= GiB: - unit = "GiB/s" - res = strconv.FormatFloat(float64(s)/GiB, 'f', prec, 64) - case s >= MiB: - unit = "MiB/s" - res = strconv.FormatFloat(float64(s)/MiB, 'f', prec, 64) - case s >= KiB: - unit = "KiB/s" - res = strconv.FormatFloat(float64(s)/KiB, 'f', prec, 64) - default: - unit = "b/s" - res = strconv.FormatInt(int64(s), 10) - } - - if st.Flag(' ') { - res += " " - } - res += unit - - if w, ok := st.Width(); ok { - if len(res) < w { - pad := strings.Repeat(" ", w-len(res)) - if st.Flag('-') { - res += pad - } else { - res = pad + res - } - } - } - - io.WriteString(st, res) -} - -type SpeedKB float64 - -func (s SpeedKB) Format(st fmt.State, verb rune) { - var prec int - switch verb { - case 'd': - case 's': - prec = -1 - default: - if p, ok := st.Precision(); ok { - prec = p - } else { - prec = 6 - } - } - - var res, unit string - switch { - case s >= TB: - unit = "TB/s" - res = strconv.FormatFloat(float64(s)/TB, 'f', prec, 64) - case s >= GB: - unit = "GB/s" - res = strconv.FormatFloat(float64(s)/GB, 'f', prec, 64) - case s >= MB: - unit = "MB/s" - res = strconv.FormatFloat(float64(s)/MB, 'f', prec, 64) - case s >= KB: - unit = "kB/s" - res = strconv.FormatFloat(float64(s)/KB, 'f', prec, 64) - default: - unit = "b/s" - res = strconv.FormatInt(int64(s), 10) - } - - if st.Flag(' ') { - res += " " - } - res += unit - - if w, ok := st.Width(); ok { - if len(res) < w { - pad := strings.Repeat(" ", w-len(res)) - if st.Flag(int('-')) { - res += pad - } else { - res = pad + res - } - } - } - - io.WriteString(st, res) -} // EwmaSpeed exponential-weighted-moving-average based speed decorator. // Note that it's necessary to supply bar.Incr* methods with incremental @@ -151,6 +40,10 @@ wc = widthConf } wc.Init() + switch unit { + case UnitKiB, UnitKB: + fmt += "/s" + } d := &movingAverageSpeed{ WC: wc, unit: unit, @@ -178,11 +71,12 @@ } speed := d.average.Value() + switch d.unit { case UnitKiB: - d.msg = fmt.Sprintf(d.fmt, SpeedKiB(speed)) + d.msg = fmt.Sprintf(d.fmt, SizeB1024(math.Round(speed))) case UnitKB: - d.msg = fmt.Sprintf(d.fmt, SpeedKB(speed)) + d.msg = fmt.Sprintf(d.fmt, SizeB1000(math.Round(speed))) default: d.msg = fmt.Sprintf(d.fmt, speed) } @@ -236,11 +130,15 @@ wc = widthConf } wc.Init() + switch unit { + case UnitKiB, UnitKB: + fmt += "/s" + } d := &averageSpeed{ WC: wc, unit: unit, + startTime: startTime, fmt: fmt, - startTime: startTime, } return d } @@ -248,8 +146,8 @@ type averageSpeed struct { WC unit int + startTime time.Time fmt string - startTime time.Time msg string completeMsg *string } @@ -267,9 +165,9 @@ switch d.unit { case UnitKiB: - d.msg = fmt.Sprintf(d.fmt, SpeedKiB(speed)) + d.msg = fmt.Sprintf(d.fmt, SizeB1024(math.Round(speed))) case UnitKB: - d.msg = fmt.Sprintf(d.fmt, SpeedKB(speed)) + d.msg = fmt.Sprintf(d.fmt, SizeB1000(math.Round(speed))) default: d.msg = fmt.Sprintf(d.fmt, speed) } diff --git a/decor/speed_test.go b/decor/speed_test.go index 82c7c6e..1f8a69f 100644 --- a/decor/speed_test.go +++ b/decor/speed_test.go @@ -1,141 +1,245 @@ package decor import ( - "fmt" "testing" + "time" ) -func TestSpeedKiB(t *testing.T) { - cases := map[string]struct { - value int64 - verb string +func TestSpeedKiBDecor(t *testing.T) { + cases := []struct { + name string + fmt string + unit int + current int64 + elapsed time.Duration expected string }{ - "verb %f": {12345678, "%f", "11.773756MiB/s"}, - "verb %.0f": {12345678, "%.0f", "12MiB/s"}, - "verb %.1f": {12345678, "%.1f", "11.8MiB/s"}, - "verb %.2f": {12345678, "%.2f", "11.77MiB/s"}, - "verb %.3f": {12345678, "%.3f", "11.774MiB/s"}, - - "verb % f": {12345678, "% f", "11.773756 MiB/s"}, - "verb % .0f": {12345678, "% .0f", "12 MiB/s"}, - "verb % .1f": {12345678, "% .1f", "11.8 MiB/s"}, - "verb % .2f": {12345678, "% .2f", "11.77 MiB/s"}, - "verb % .3f": {12345678, "% .3f", "11.774 MiB/s"}, - - "verb %10.f": {12345678, "%10.f", " 12MiB/s"}, - "verb %10.0f": {12345678, "%10.0f", " 12MiB/s"}, - "verb %10.1f": {12345678, "%10.1f", " 11.8MiB/s"}, - "verb %10.2f": {12345678, "%10.2f", "11.77MiB/s"}, - "verb %10.3f": {12345678, "%10.3f", "11.774MiB/s"}, - - "verb % 10.f": {12345678, "% 10.f", " 12 MiB/s"}, - "verb % 10.0f": {12345678, "% 10.0f", " 12 MiB/s"}, - "verb % 10.1f": {12345678, "% 10.1f", "11.8 MiB/s"}, - - "verb %-10.f": {12345678, "%-10.f", "12MiB/s "}, - "verb %-10.0f": {12345678, "%-10.0f", "12MiB/s "}, - "verb %-10.1f": {12345678, "%-10.1f", "11.8MiB/s "}, - "verb %-10.2f": {12345678, "%10.2f", "11.77MiB/s"}, - "verb %-10.3f": {12345678, "%10.3f", "11.774MiB/s"}, - - "verb % -10.f": {12345678, "% -10.f", "12 MiB/s "}, - "verb % -10.0f": {12345678, "% -10.0f", "12 MiB/s "}, - "verb % -10.1f": {12345678, "% -10.1f", "11.8 MiB/s"}, - - "1000 %f": {1000, "%f", "1000b/s"}, - "1000 %d": {1000, "%d", "1000b/s"}, - "1000 %s": {1000, "%s", "1000b/s"}, - "1024 %f": {1024, "%f", "1.000000KiB/s"}, - "1024 %d": {1024, "%d", "1KiB/s"}, - "1024 %.1f": {1024, "%.1f", "1.0KiB/s"}, - "1024 %s": {1024, "%s", "1KiB/s"}, - "3*MiB/s+140KiB/s %f": {3*MiB + 140*KiB, "%f", "3.136719MiB/s"}, - "3*MiB/s+140KiB/s %d": {3*MiB + 140*KiB, "%d", "3MiB/s"}, - "3*MiB/s+140KiB/s %.1f": {3*MiB + 140*KiB, "%.1f", "3.1MiB/s"}, - "3*MiB/s+140KiB/s %s": {3*MiB + 140*KiB, "%s", "3.13671875MiB/s"}, - "2*GiB/s %f": {2 * GiB, "%f", "2.000000GiB/s"}, - "2*GiB/s %d": {2 * GiB, "%d", "2GiB/s"}, - "2*GiB/s %.1f": {2 * GiB, "%.1f", "2.0GiB/s"}, - "2*GiB/s %s": {2 * GiB, "%s", "2GiB/s"}, - "4*TiB/s %f": {4 * TiB, "%f", "4.000000TiB/s"}, - "4*TiB/s %d": {4 * TiB, "%d", "4TiB/s"}, - "4*TiB/s %.1f": {4 * TiB, "%.1f", "4.0TiB/s"}, - "4*TiB/s %s": {4 * TiB, "%s", "4TiB/s"}, - } - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - got := fmt.Sprintf(tc.verb, SpeedKiB(tc.value)) - if got != tc.expected { - t.Fatalf("expected: %q, got: %q\n", tc.expected, got) + { + name: "UnitKiB:%d:0b", + unit: UnitKiB, + fmt: "%d", + current: 0, + elapsed: time.Second, + expected: "0b/s", + }, + { + name: "UnitKiB:% .2f:0b", + unit: UnitKiB, + fmt: "% .2f", + current: 0, + elapsed: time.Second, + expected: "0.00 b/s", + }, + { + name: "UnitKiB:%d:1b", + unit: UnitKiB, + fmt: "%d", + current: 1, + elapsed: time.Second, + expected: "1b/s", + }, + { + name: "UnitKiB:% .2f:1b", + unit: UnitKiB, + fmt: "% .2f", + current: 1, + elapsed: time.Second, + expected: "1.00 b/s", + }, + { + name: "UnitKiB:%d:KiB", + unit: UnitKiB, + fmt: "%d", + current: 2 * int64(_iKiB), + elapsed: 1 * time.Second, + expected: "2KiB/s", + }, + { + name: "UnitKiB:% .f:KiB", + unit: UnitKiB, + fmt: "% .2f", + current: 2 * int64(_iKiB), + elapsed: 1 * time.Second, + expected: "2.00 KiB/s", + }, + { + name: "UnitKiB:%d:MiB", + unit: UnitKiB, + fmt: "%d", + current: 2 * int64(_iMiB), + elapsed: 1 * time.Second, + expected: "2MiB/s", + }, + { + name: "UnitKiB:% .2f:MiB", + unit: UnitKiB, + fmt: "% .2f", + current: 2 * int64(_iMiB), + elapsed: 1 * time.Second, + expected: "2.00 MiB/s", + }, + { + name: "UnitKiB:%d:GiB", + unit: UnitKiB, + fmt: "%d", + current: 2 * int64(_iGiB), + elapsed: 1 * time.Second, + expected: "2GiB/s", + }, + { + name: "UnitKiB:% .2f:GiB", + unit: UnitKiB, + fmt: "% .2f", + current: 2 * int64(_iGiB), + elapsed: 1 * time.Second, + expected: "2.00 GiB/s", + }, + { + name: "UnitKiB:%d:TiB", + unit: UnitKiB, + fmt: "%d", + current: 2 * int64(_iTiB), + elapsed: 1 * time.Second, + expected: "2TiB/s", + }, + { + name: "UnitKiB:% .2f:TiB", + unit: UnitKiB, + fmt: "% .2f", + current: 2 * int64(_iTiB), + elapsed: 1 * time.Second, + expected: "2.00 TiB/s", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + decor := NewAverageSpeed(tc.unit, tc.fmt, time.Now().Add(-tc.elapsed)) + stat := &Statistics{ + Current: tc.current, + } + res := decor.Decor(stat) + if res != tc.expected { + t.Fatalf("expected: %q, got: %q\n", tc.expected, res) } }) } } -func TestSpeedKB(t *testing.T) { - cases := map[string]struct { - value int64 - verb string +func TestSpeedKBDecor(t *testing.T) { + cases := []struct { + name string + fmt string + unit int + current int64 + elapsed time.Duration expected string }{ - "verb %f": {12345678, "%f", "12.345678MB/s"}, - "verb %.0f": {12345678, "%.0f", "12MB/s"}, - "verb %.1f": {12345678, "%.1f", "12.3MB/s"}, - "verb %.2f": {12345678, "%.2f", "12.35MB/s"}, - "verb %.3f": {12345678, "%.3f", "12.346MB/s"}, - - "verb % f": {12345678, "% f", "12.345678 MB/s"}, - "verb % .0f": {12345678, "% .0f", "12 MB/s"}, - "verb % .1f": {12345678, "% .1f", "12.3 MB/s"}, - "verb % .2f": {12345678, "% .2f", "12.35 MB/s"}, - "verb % .3f": {12345678, "% .3f", "12.346 MB/s"}, - - "verb %10.f": {12345678, "%10.f", " 12MB/s"}, - "verb %10.0f": {12345678, "%10.0f", " 12MB/s"}, - "verb %10.1f": {12345678, "%10.1f", " 12.3MB/s"}, - "verb %10.2f": {12345678, "%10.2f", " 12.35MB/s"}, - "verb %10.3f": {12345678, "%10.3f", "12.346MB/s"}, - - "verb % 10.f": {12345678, "% 10.f", " 12 MB/s"}, - "verb % 10.0f": {12345678, "% 10.0f", " 12 MB/s"}, - "verb % 10.1f": {12345678, "% 10.1f", " 12.3 MB/s"}, - - "verb %-10.f": {12345678, "%-10.f", "12MB/s "}, - "verb %-10.0f": {12345678, "%-10.0f", "12MB/s "}, - "verb %-10.1f": {12345678, "%-10.1f", "12.3MB/s "}, - "verb %-10.2f": {12345678, "%10.2f", " 12.35MB/s"}, - "verb %-10.3f": {12345678, "%10.3f", "12.346MB/s"}, - - "verb % -10.f": {12345678, "% -10.f", "12 MB/s "}, - "verb % -10.0f": {12345678, "% -10.0f", "12 MB/s "}, - "verb % -10.1f": {12345678, "% -10.1f", "12.3 MB/s "}, - - "1000 %f": {1000, "%f", "1.000000kB/s"}, - "1000 %d": {1000, "%d", "1kB/s"}, - "1000 %s": {1000, "%s", "1kB/s"}, - "1024 %f": {1024, "%f", "1.024000kB/s"}, - "1024 %d": {1024, "%d", "1kB/s"}, - "1024 %.1f": {1024, "%.1f", "1.0kB/s"}, - "1024 %s": {1024, "%s", "1.024kB/s"}, - "3*MB/s+140*KB/s %f": {3*MB + 140*KB, "%f", "3.140000MB/s"}, - "3*MB/s+140*KB/s %d": {3*MB + 140*KB, "%d", "3MB/s"}, - "3*MB/s+140*KB/s %.1f": {3*MB + 140*KB, "%.1f", "3.1MB/s"}, - "3*MB/s+140*KB/s %s": {3*MB + 140*KB, "%s", "3.14MB/s"}, - "2*GB/s %f": {2 * GB, "%f", "2.000000GB/s"}, - "2*GB/s %d": {2 * GB, "%d", "2GB/s"}, - "2*GB/s %.1f": {2 * GB, "%.1f", "2.0GB/s"}, - "2*GB/s %s": {2 * GB, "%s", "2GB/s"}, - "4*TB/s %f": {4 * TB, "%f", "4.000000TB/s"}, - "4*TB/s %d": {4 * TB, "%d", "4TB/s"}, - "4*TB/s %.1f": {4 * TB, "%.1f", "4.0TB/s"}, - "4*TB/s %s": {4 * TB, "%s", "4TB/s"}, - } - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - got := fmt.Sprintf(tc.verb, SpeedKB(tc.value)) - if got != tc.expected { - t.Fatalf("expected: %q, got: %q\n", tc.expected, got) + { + name: "UnitKB:%d:0b", + unit: UnitKB, + fmt: "%d", + current: 0, + elapsed: time.Second, + expected: "0b/s", + }, + { + name: "UnitKB:% .2f:0b", + unit: UnitKB, + fmt: "% .2f", + current: 0, + elapsed: time.Second, + expected: "0.00 b/s", + }, + { + name: "UnitKB:%d:1b", + unit: UnitKB, + fmt: "%d", + current: 1, + elapsed: time.Second, + expected: "1b/s", + }, + { + name: "UnitKB:% .2f:1b", + unit: UnitKB, + fmt: "% .2f", + current: 1, + elapsed: time.Second, + expected: "1.00 b/s", + }, + { + name: "UnitKB:%d:KB", + unit: UnitKB, + fmt: "%d", + current: 2 * int64(_KB), + elapsed: 1 * time.Second, + expected: "2KB/s", + }, + { + name: "UnitKB:% .f:KB", + unit: UnitKB, + fmt: "% .2f", + current: 2 * int64(_KB), + elapsed: 1 * time.Second, + expected: "2.00 KB/s", + }, + { + name: "UnitKB:%d:MB", + unit: UnitKB, + fmt: "%d", + current: 2 * int64(_MB), + elapsed: 1 * time.Second, + expected: "2MB/s", + }, + { + name: "UnitKB:% .2f:MB", + unit: UnitKB, + fmt: "% .2f", + current: 2 * int64(_MB), + elapsed: 1 * time.Second, + expected: "2.00 MB/s", + }, + { + name: "UnitKB:%d:GB", + unit: UnitKB, + fmt: "%d", + current: 2 * int64(_GB), + elapsed: 1 * time.Second, + expected: "2GB/s", + }, + { + name: "UnitKB:% .2f:GB", + unit: UnitKB, + fmt: "% .2f", + current: 2 * int64(_GB), + elapsed: 1 * time.Second, + expected: "2.00 GB/s", + }, + { + name: "UnitKB:%d:TB", + unit: UnitKB, + fmt: "%d", + current: 2 * int64(_TB), + elapsed: 1 * time.Second, + expected: "2TB/s", + }, + { + name: "UnitKB:% .2f:TB", + unit: UnitKB, + fmt: "% .2f", + current: 2 * int64(_TB), + elapsed: 1 * time.Second, + expected: "2.00 TB/s", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + decor := NewAverageSpeed(tc.unit, tc.fmt, time.Now().Add(-tc.elapsed)) + stat := &Statistics{ + Current: tc.current, + } + res := decor.Decor(stat) + if res != tc.expected { + t.Fatalf("expected: %q, got: %q\n", tc.expected, res) } }) }