github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/fs/sizesuffix.go (about)

     1  package fs
     2  
     3  // SizeSuffix is parsed by flag with k/M/G suffixes
     4  import (
     5  	"fmt"
     6  	"math"
     7  	"sort"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  // SizeSuffix is an int64 with a friendly way of printing setting
    15  type SizeSuffix int64
    16  
    17  // Common multipliers for SizeSuffix
    18  const (
    19  	Byte SizeSuffix = 1 << (iota * 10)
    20  	KibiByte
    21  	MebiByte
    22  	GibiByte
    23  	TebiByte
    24  	PebiByte
    25  	ExbiByte
    26  )
    27  
    28  // Turn SizeSuffix into a string and a suffix
    29  func (x SizeSuffix) string() (string, string) {
    30  	scaled := float64(0)
    31  	suffix := ""
    32  	switch {
    33  	case x < 0:
    34  		return "off", ""
    35  	case x == 0:
    36  		return "0", ""
    37  	case x < 1<<10:
    38  		scaled = float64(x)
    39  		suffix = ""
    40  	case x < 1<<20:
    41  		scaled = float64(x) / (1 << 10)
    42  		suffix = "k"
    43  	case x < 1<<30:
    44  		scaled = float64(x) / (1 << 20)
    45  		suffix = "M"
    46  	case x < 1<<40:
    47  		scaled = float64(x) / (1 << 30)
    48  		suffix = "G"
    49  	case x < 1<<50:
    50  		scaled = float64(x) / (1 << 40)
    51  		suffix = "T"
    52  	default:
    53  		scaled = float64(x) / (1 << 50)
    54  		suffix = "P"
    55  	}
    56  	if math.Floor(scaled) == scaled {
    57  		return fmt.Sprintf("%.0f", scaled), suffix
    58  	}
    59  	return fmt.Sprintf("%.3f", scaled), suffix
    60  }
    61  
    62  // String turns SizeSuffix into a string
    63  func (x SizeSuffix) String() string {
    64  	val, suffix := x.string()
    65  	return val + suffix
    66  }
    67  
    68  // Unit turns SizeSuffix into a string with a unit
    69  func (x SizeSuffix) Unit(unit string) string {
    70  	val, suffix := x.string()
    71  	if val == "off" {
    72  		return val
    73  	}
    74  	return val + " " + suffix + unit
    75  }
    76  
    77  // Set a SizeSuffix
    78  func (x *SizeSuffix) Set(s string) error {
    79  	if len(s) == 0 {
    80  		return errors.New("empty string")
    81  	}
    82  	if strings.ToLower(s) == "off" {
    83  		*x = -1
    84  		return nil
    85  	}
    86  	suffix := s[len(s)-1]
    87  	suffixLen := 1
    88  	var multiplier float64
    89  	switch suffix {
    90  	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.':
    91  		suffixLen = 0
    92  		multiplier = 1 << 10
    93  	case 'b', 'B':
    94  		multiplier = 1
    95  	case 'k', 'K':
    96  		multiplier = 1 << 10
    97  	case 'm', 'M':
    98  		multiplier = 1 << 20
    99  	case 'g', 'G':
   100  		multiplier = 1 << 30
   101  	case 't', 'T':
   102  		multiplier = 1 << 40
   103  	case 'p', 'P':
   104  		multiplier = 1 << 50
   105  	default:
   106  		return errors.Errorf("bad suffix %q", suffix)
   107  	}
   108  	s = s[:len(s)-suffixLen]
   109  	value, err := strconv.ParseFloat(s, 64)
   110  	if err != nil {
   111  		return err
   112  	}
   113  	if value < 0 {
   114  		return errors.Errorf("size can't be negative %q", s)
   115  	}
   116  	value *= multiplier
   117  	*x = SizeSuffix(value)
   118  	return nil
   119  }
   120  
   121  // Type of the value
   122  func (x *SizeSuffix) Type() string {
   123  	return "SizeSuffix"
   124  }
   125  
   126  // Scan implements the fmt.Scanner interface
   127  func (x *SizeSuffix) Scan(s fmt.ScanState, ch rune) error {
   128  	token, err := s.Token(true, nil)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	return x.Set(string(token))
   133  }
   134  
   135  // SizeSuffixList is a slice SizeSuffix values
   136  type SizeSuffixList []SizeSuffix
   137  
   138  func (l SizeSuffixList) Len() int           { return len(l) }
   139  func (l SizeSuffixList) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
   140  func (l SizeSuffixList) Less(i, j int) bool { return l[i] < l[j] }
   141  
   142  // Sort sorts the list
   143  func (l SizeSuffixList) Sort() {
   144  	sort.Sort(l)
   145  }