refactoring: use Any
Vladimir Bauer
6 years ago
| 42 | 42 | // pairFmt="% d / % d" output: "1 MB / 12 MB" |
| 43 | 43 | // |
| 44 | 44 | func Counters(unit int, pairFmt string, wcc ...WC) Decorator { |
| 45 | var wc WC | |
| 46 | for _, widthConf := range wcc { | |
| 47 | wc = widthConf | |
| 48 | } | |
| 49 | d := &countersDecorator{ | |
| 50 | WC: wc.Init(), | |
| 51 | producer: chooseSizeProducer(unit, pairFmt), | |
| 52 | } | |
| 53 | return d | |
| 54 | } | |
| 55 | ||
| 56 | type countersDecorator struct { | |
| 57 | WC | |
| 58 | producer func(*Statistics) string | |
| 59 | } | |
| 60 | ||
| 61 | func (d *countersDecorator) Decor(st *Statistics) string { | |
| 62 | return d.FormatMsg(d.producer(st)) | |
| 45 | return Any(chooseSizeProducer(unit, pairFmt), wcc...) | |
| 63 | 46 | } |
| 64 | 47 | |
| 65 | 48 | func chooseSizeProducer(unit int, format string) func(*Statistics) string { |
| 68 | 51 | } |
| 69 | 52 | switch unit { |
| 70 | 53 | case UnitKiB: |
| 71 | return func(st *Statistics) string { | |
| 72 | return fmt.Sprintf(format, SizeB1024(st.Current), SizeB1024(st.Total)) | |
| 54 | return func(s *Statistics) string { | |
| 55 | return fmt.Sprintf(format, SizeB1024(s.Current), SizeB1024(s.Total)) | |
| 73 | 56 | } |
| 74 | 57 | case UnitKB: |
| 75 | return func(st *Statistics) string { | |
| 76 | return fmt.Sprintf(format, SizeB1000(st.Current), SizeB1000(st.Total)) | |
| 58 | return func(s *Statistics) string { | |
| 59 | return fmt.Sprintf(format, SizeB1000(s.Current), SizeB1000(s.Total)) | |
| 77 | 60 | } |
| 78 | 61 | default: |
| 79 | return func(st *Statistics) string { | |
| 80 | return fmt.Sprintf(format, st.Current, st.Total) | |
| 62 | return func(s *Statistics) string { | |
| 63 | return fmt.Sprintf(format, s.Current, s.Total) | |
| 81 | 64 | } |
| 82 | 65 | } |
| 83 | 66 | } |
| 8 | 8 | // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] |
| 9 | 9 | // |
| 10 | 10 | // `wcc` optional WC config |
| 11 | // | |
| 11 | 12 | func Elapsed(style TimeStyle, wcc ...WC) Decorator { |
| 12 | 13 | return NewElapsed(style, time.Now(), wcc...) |
| 13 | 14 | } |
| 19 | 20 | // `startTime` start time |
| 20 | 21 | // |
| 21 | 22 | // `wcc` optional WC config |
| 23 | // | |
| 22 | 24 | func NewElapsed(style TimeStyle, startTime time.Time, wcc ...WC) Decorator { |
| 23 | var wc WC | |
| 24 | for _, widthConf := range wcc { | |
| 25 | wc = widthConf | |
| 25 | var msg string | |
| 26 | producer := chooseTimeProducer(style) | |
| 27 | f := func(s *Statistics) string { | |
| 28 | if !s.Completed { | |
| 29 | msg = producer(time.Since(startTime)) | |
| 30 | } | |
| 31 | return msg | |
| 26 | 32 | } |
| 27 | d := &elapsedDecorator{ | |
| 28 | WC: wc.Init(), | |
| 29 | startTime: startTime, | |
| 30 | producer: chooseTimeProducer(style), | |
| 31 | } | |
| 32 | return d | |
| 33 | return Any(f, wcc...) | |
| 33 | 34 | } |
| 34 | ||
| 35 | type elapsedDecorator struct { | |
| 36 | WC | |
| 37 | startTime time.Time | |
| 38 | producer func(time.Duration) string | |
| 39 | msg string | |
| 40 | } | |
| 41 | ||
| 42 | func (d *elapsedDecorator) Decor(st *Statistics) string { | |
| 43 | if !st.Completed { | |
| 44 | d.msg = d.producer(time.Since(d.startTime)) | |
| 45 | } | |
| 46 | return d.FormatMsg(d.msg) | |
| 47 | } | |
| 44 | 44 | // `normalizer` available implementations are [FixedIntervalTimeNormalizer|MaxTolerateTimeNormalizer] |
| 45 | 45 | // |
| 46 | 46 | // `wcc` optional WC config |
| 47 | // | |
| 47 | 48 | func MovingAverageETA(style TimeStyle, average MovingAverage, normalizer TimeNormalizer, wcc ...WC) Decorator { |
| 48 | var wc WC | |
| 49 | for _, widthConf := range wcc { | |
| 50 | wc = widthConf | |
| 51 | } | |
| 52 | 49 | d := &movingAverageETA{ |
| 53 | WC: wc.Init(), | |
| 50 | WC: initWC(wcc...), | |
| 54 | 51 | average: average, |
| 55 | 52 | normalizer: normalizer, |
| 56 | 53 | producer: chooseTimeProducer(style), |
| 65 | 62 | producer func(time.Duration) string |
| 66 | 63 | } |
| 67 | 64 | |
| 68 | func (d *movingAverageETA) Decor(st *Statistics) string { | |
| 65 | func (d *movingAverageETA) Decor(s *Statistics) string { | |
| 69 | 66 | v := math.Round(d.average.Value()) |
| 70 | remaining := time.Duration((st.Total - st.Current) * int64(v)) | |
| 67 | remaining := time.Duration((s.Total - s.Current) * int64(v)) | |
| 71 | 68 | if d.normalizer != nil { |
| 72 | 69 | remaining = d.normalizer.Normalize(remaining) |
| 73 | 70 | } |
| 91 | 88 | // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] |
| 92 | 89 | // |
| 93 | 90 | // `wcc` optional WC config |
| 91 | // | |
| 94 | 92 | func AverageETA(style TimeStyle, wcc ...WC) Decorator { |
| 95 | 93 | return NewAverageETA(style, time.Now(), nil, wcc...) |
| 96 | 94 | } |
| 104 | 102 | // `normalizer` available implementations are [FixedIntervalTimeNormalizer|MaxTolerateTimeNormalizer] |
| 105 | 103 | // |
| 106 | 104 | // `wcc` optional WC config |
| 105 | // | |
| 107 | 106 | func NewAverageETA(style TimeStyle, startTime time.Time, normalizer TimeNormalizer, wcc ...WC) Decorator { |
| 108 | var wc WC | |
| 109 | for _, widthConf := range wcc { | |
| 110 | wc = widthConf | |
| 111 | } | |
| 112 | 107 | d := &averageETA{ |
| 113 | WC: wc.Init(), | |
| 108 | WC: initWC(wcc...), | |
| 114 | 109 | startTime: startTime, |
| 115 | 110 | normalizer: normalizer, |
| 116 | 111 | producer: chooseTimeProducer(style), |
| 125 | 120 | producer func(time.Duration) string |
| 126 | 121 | } |
| 127 | 122 | |
| 128 | func (d *averageETA) Decor(st *Statistics) string { | |
| 123 | func (d *averageETA) Decor(s *Statistics) string { | |
| 129 | 124 | var remaining time.Duration |
| 130 | if st.Current != 0 { | |
| 131 | durPerItem := float64(time.Since(d.startTime)) / float64(st.Current) | |
| 125 | if s.Current != 0 { | |
| 126 | durPerItem := float64(time.Since(d.startTime)) / float64(s.Current) | |
| 132 | 127 | durPerItem = math.Round(durPerItem) |
| 133 | remaining = time.Duration((st.Total - st.Current) * int64(durPerItem)) | |
| 128 | remaining = time.Duration((s.Total - s.Current) * int64(durPerItem)) | |
| 134 | 129 | if d.normalizer != nil { |
| 135 | 130 | remaining = d.normalizer.Normalize(remaining) |
| 136 | 131 | } |
| 63 | 63 | return d.Decorator |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | func (d *mergeDecorator) Decor(st *Statistics) string { | |
| 67 | msg := d.Decorator.Decor(st) | |
| 66 | func (d *mergeDecorator) Decor(s *Statistics) string { | |
| 67 | msg := d.Decorator.Decor(s) | |
| 68 | 68 | msgLen := utf8.RuneCountInString(msg) |
| 69 | 69 | if (d.wc.C & DextraSpace) != 0 { |
| 70 | 70 | msgLen++ |
| 100 | 100 | WC |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | func (d *placeHolderDecorator) Decor(_ *Statistics) string { | |
| 103 | func (d *placeHolderDecorator) Decor(*Statistics) string { | |
| 104 | 104 | return "" |
| 105 | 105 | } |
| 0 | 0 | package decor |
| 1 | 1 | |
| 2 | // Name returns name decorator. | |
| 2 | // Name decorator displays text that is set once and can't be changed | |
| 3 | // during decorator's lifetime. | |
| 3 | 4 | // |
| 4 | // `name` string to display | |
| 5 | // `str` string to display | |
| 5 | 6 | // |
| 6 | 7 | // `wcc` optional WC config |
| 7 | func Name(name string, wcc ...WC) Decorator { | |
| 8 | var wc WC | |
| 9 | for _, widthConf := range wcc { | |
| 10 | wc = widthConf | |
| 11 | } | |
| 12 | d := &nameDecorator{ | |
| 13 | WC: wc.Init(), | |
| 14 | msg: name, | |
| 15 | } | |
| 16 | return d | |
| 8 | // | |
| 9 | func Name(str string, wcc ...WC) Decorator { | |
| 10 | return Any(func(*Statistics) string { return str }, wcc...) | |
| 17 | 11 | } |
| 18 | ||
| 19 | type nameDecorator struct { | |
| 20 | WC | |
| 21 | msg string | |
| 22 | } | |
| 23 | ||
| 24 | func (d *nameDecorator) Decor(st *Statistics) string { | |
| 25 | return d.FormatMsg(d.msg) | |
| 26 | } |
| 22 | 22 | msg string |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | func (d *onCompleteWrapper) Decor(st *Statistics) string { | |
| 26 | if st.Completed { | |
| 25 | func (d *onCompleteWrapper) Decor(s *Statistics) string { | |
| 26 | if s.Completed { | |
| 27 | 27 | wc := d.GetConf() |
| 28 | 28 | return wc.FormatMsg(d.msg) |
| 29 | 29 | } |
| 30 | return d.Decorator.Decor(st) | |
| 30 | return d.Decorator.Decor(s) | |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | func (d *onCompleteWrapper) Base() Decorator { |
| 36 | 36 | return NewPercentage("% d", wcc...) |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | // NewPercentage percentage decorator with custom fmt string. | |
| 39 | // NewPercentage percentage decorator with custom format string. | |
| 40 | 40 | // |
| 41 | // fmt examples: | |
| 41 | // format examples: | |
| 42 | 42 | // |
| 43 | // fmt="%.1f" output: "1.0%" | |
| 44 | // fmt="% .1f" output: "1.0 %" | |
| 45 | // fmt="%d" output: "1%" | |
| 46 | // fmt="% d" output: "1 %" | |
| 43 | // format="%.1f" output: "1.0%" | |
| 44 | // format="% .1f" output: "1.0 %" | |
| 45 | // format="%d" output: "1%" | |
| 46 | // format="% d" output: "1 %" | |
| 47 | 47 | // |
| 48 | func NewPercentage(fmt string, wcc ...WC) Decorator { | |
| 49 | var wc WC | |
| 50 | for _, widthConf := range wcc { | |
| 51 | wc = widthConf | |
| 48 | func NewPercentage(format string, wcc ...WC) Decorator { | |
| 49 | if format == "" { | |
| 50 | format = "% d" | |
| 52 | 51 | } |
| 53 | if fmt == "" { | |
| 54 | fmt = "% d" | |
| 52 | f := func(s *Statistics) string { | |
| 53 | p := internal.Percentage(s.Total, s.Current, 100) | |
| 54 | return fmt.Sprintf(format, percentageType(p)) | |
| 55 | 55 | } |
| 56 | d := &percentageDecorator{ | |
| 57 | WC: wc.Init(), | |
| 58 | fmt: fmt, | |
| 59 | } | |
| 60 | return d | |
| 56 | return Any(f, wcc...) | |
| 61 | 57 | } |
| 62 | ||
| 63 | type percentageDecorator struct { | |
| 64 | WC | |
| 65 | fmt string | |
| 66 | } | |
| 67 | ||
| 68 | func (d *percentageDecorator) Decor(st *Statistics) string { | |
| 69 | p := internal.Percentage(st.Total, st.Current, 100) | |
| 70 | return d.FormatMsg(fmt.Sprintf(d.fmt, percentageType(p))) | |
| 71 | } |
| 51 | 51 | // unit=UnitKB, format="% .1f" output: "1.0 MB/s" |
| 52 | 52 | // |
| 53 | 53 | func MovingAverageSpeed(unit int, format string, average MovingAverage, wcc ...WC) Decorator { |
| 54 | var wc WC | |
| 55 | for _, widthConf := range wcc { | |
| 56 | wc = widthConf | |
| 57 | } | |
| 58 | 54 | if format == "" { |
| 59 | 55 | format = "%.0f" |
| 60 | 56 | } |
| 61 | 57 | d := &movingAverageSpeed{ |
| 62 | WC: wc.Init(), | |
| 58 | WC: initWC(wcc...), | |
| 63 | 59 | average: average, |
| 64 | 60 | producer: chooseSpeedProducer(unit, format), |
| 65 | 61 | } |
| 73 | 69 | msg string |
| 74 | 70 | } |
| 75 | 71 | |
| 76 | func (d *movingAverageSpeed) Decor(st *Statistics) string { | |
| 77 | if !st.Completed { | |
| 72 | func (d *movingAverageSpeed) Decor(s *Statistics) string { | |
| 73 | if !s.Completed { | |
| 78 | 74 | var speed float64 |
| 79 | 75 | if v := d.average.Value(); v > 0 { |
| 80 | 76 | speed = 1 / v |
| 121 | 117 | // unit=UnitKB, format="% .1f" output: "1.0 MB/s" |
| 122 | 118 | // |
| 123 | 119 | func NewAverageSpeed(unit int, format string, startTime time.Time, wcc ...WC) Decorator { |
| 124 | var wc WC | |
| 125 | for _, widthConf := range wcc { | |
| 126 | wc = widthConf | |
| 127 | } | |
| 128 | 120 | if format == "" { |
| 129 | 121 | format = "%.0f" |
| 130 | 122 | } |
| 131 | 123 | d := &averageSpeed{ |
| 132 | WC: wc.Init(), | |
| 124 | WC: initWC(wcc...), | |
| 133 | 125 | startTime: startTime, |
| 134 | 126 | producer: chooseSpeedProducer(unit, format), |
| 135 | 127 | } |
| 143 | 135 | msg string |
| 144 | 136 | } |
| 145 | 137 | |
| 146 | func (d *averageSpeed) Decor(st *Statistics) string { | |
| 147 | if !st.Completed { | |
| 148 | speed := float64(st.Current) / float64(time.Since(d.startTime)) | |
| 138 | func (d *averageSpeed) Decor(s *Statistics) string { | |
| 139 | if !s.Completed { | |
| 140 | speed := float64(s.Current) / float64(time.Since(d.startTime)) | |
| 149 | 141 | d.msg = d.producer(speed * 1e9) |
| 150 | 142 | } |
| 151 | 143 | |
| 7 | 7 | // |
| 8 | 8 | // `wcc` optional WC config |
| 9 | 9 | func Spinner(frames []string, wcc ...WC) Decorator { |
| 10 | var wc WC | |
| 11 | for _, widthConf := range wcc { | |
| 12 | wc = widthConf | |
| 13 | } | |
| 14 | 10 | if len(frames) == 0 { |
| 15 | 11 | frames = defaultSpinnerStyle |
| 16 | 12 | } |
| 17 | d := &spinnerDecorator{ | |
| 18 | WC: wc.Init(), | |
| 19 | frames: frames, | |
| 13 | var count uint | |
| 14 | f := func(s *Statistics) string { | |
| 15 | frame := frames[count%uint(len(frames))] | |
| 16 | count++ | |
| 17 | return frame | |
| 20 | 18 | } |
| 21 | return d | |
| 19 | return Any(f, wcc...) | |
| 22 | 20 | } |
| 23 | ||
| 24 | type spinnerDecorator struct { | |
| 25 | WC | |
| 26 | frames []string | |
| 27 | count uint | |
| 28 | } | |
| 29 | ||
| 30 | func (d *spinnerDecorator) Decor(st *Statistics) string { | |
| 31 | frame := d.frames[d.count%uint(len(d.frames))] | |
| 32 | d.count++ | |
| 33 | return d.FormatMsg(frame) | |
| 34 | } |