package progress import ( "fmt" ) // UnitsNotationPosition determines notation position relative to unit value. type UnitsNotationPosition int // Supported unit positions relative to tracker value; // default: UnitsNotationPositionBefore const ( UnitsNotationPositionBefore UnitsNotationPosition = iota UnitsNotationPositionAfter ) // UnitsFormatter defines a function that prints a value in a specific style. type UnitsFormatter func(value int64) string // Units defines the "type" of the value being tracked by the Tracker. type Units struct { Formatter UnitsFormatter // default: FormatNumber Notation string NotationPosition UnitsNotationPosition // default: UnitsNotationPositionBefore } // Sprint prints the value as defined by the Units. func (tu Units) Sprint(value int64) string { formatter := tu.Formatter if formatter == nil { formatter = FormatNumber } formattedValue := formatter(value) switch tu.NotationPosition { case UnitsNotationPositionAfter: return formattedValue + tu.Notation default: // UnitsNotationPositionBefore return tu.Notation + formattedValue } } var ( // UnitsDefault doesn't define any units. The value will be treated as any // other number. UnitsDefault = Units{ Notation: "", NotationPosition: UnitsNotationPositionBefore, Formatter: FormatNumber, } // UnitsBytes defines the value as a storage unit. Values will be converted // and printed in one of these forms: B, KB, MB, GB, TB, PB UnitsBytes = Units{ Notation: "", NotationPosition: UnitsNotationPositionBefore, Formatter: FormatBytes, } // UnitsCurrencyDollar defines the value as a Dollar amount. Values will be // converted and printed in one of these forms: $x.yz, $x.yzK, $x.yzM, // $x.yzB, $x.yzT UnitsCurrencyDollar = Units{ Notation: "$", NotationPosition: UnitsNotationPositionBefore, Formatter: FormatNumber, } // UnitsCurrencyEuro defines the value as a Euro amount. Values will be // converted and printed in one of these forms: ₠x.yz, ₠x.yzK, ₠x.yzM, // ₠x.yzB, ₠x.yzT UnitsCurrencyEuro = Units{ Notation: "₠", NotationPosition: UnitsNotationPositionBefore, Formatter: FormatNumber, } // UnitsCurrencyPound defines the value as a Pound amount. Values will be // converted and printed in one of these forms: £x.yz, £x.yzK, £x.yzM, // £x.yzB, £x.yzT UnitsCurrencyPound = Units{ Notation: "£", NotationPosition: UnitsNotationPositionBefore, Formatter: FormatNumber, } ) // FormatBytes formats the given value as a "Byte". func FormatBytes(value int64) string { return formatNumber(value, map[int64]string{ 1000000000000000: "PB", 1000000000000: "TB", 1000000000: "GB", 1000000: "MB", 1000: "KB", 0: "B", }) } // FormatNumber formats the given value as a "regular number". func FormatNumber(value int64) string { return formatNumber(value, map[int64]string{ 1000000000000000: "Q", 1000000000000: "T", 1000000000: "B", 1000000: "M", 1000: "K", 0: "", }) } var ( unitScales = []int64{ 1000000000000000, 1000000000000, 1000000000, 1000000, 1000, } ) func formatNumber(value int64, notations map[int64]string) string { for _, unitScale := range unitScales { if value >= unitScale { return fmt.Sprintf("%.2f%s", float64(value)/float64(unitScale), notations[unitScale]) } } return fmt.Sprintf("%d%s", value, notations[0]) }