gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/unit/size.go (about) 1 package unit 2 3 import ( 4 "bytes" 5 "fmt" 6 sliceUnsafe "gitee.com/sy_183/go-common/slice/unsafe" 7 stringUnsafe "gitee.com/sy_183/go-common/strings/unsafe" 8 "gopkg.in/yaml.v3" 9 "reflect" 10 "strconv" 11 "strings" 12 ) 13 14 type UnknownSizeUnitError struct { 15 Unit string 16 } 17 18 func (e *UnknownSizeUnitError) Error() string { 19 if e == nil { 20 return "<nil>" 21 } 22 return fmt.Sprintf("unknown size unit '%s'", e.Unit) 23 } 24 25 const ( 26 Bit = 0.125 27 BitDiv = 8 28 Byte = 1 29 KiloByte = 1000 30 KiBiByte = 1 << 10 31 KiloBit = KiloByte / 8 32 KiBiBit = KiBiByte / 8 33 MegaByte = 1000 * 1000 34 MeBiByte = 1 << 20 35 MegaBit = MegaByte / 8 36 MeBiBit = MeBiByte / 8 37 GigaByte = 1000 * 1000 * 1000 38 GiBiByte = 1 << 30 39 GigaBit = GigaByte / 8 40 GiBiBit = GiBiByte / 8 41 TeraByte = 1000 * 1000 * 1000 * 1000 42 TeBiByte = 1 << 40 43 TeraBit = TeraByte / 8 44 TeBiBit = TeBiByte / 8 45 PetaByte = 1000 * 1000 * 1000 * 1000 * 1000 46 PeBiByte = 1 << 50 47 PetaBit = PetaByte / 8 48 PeBiBit = PeBiByte / 8 49 ExaByte = 1000 * 1000 * 1000 * 1000 * 1000 * 1000 50 EbiByte = 1 << 60 51 ExaBit = ExaByte / 8 52 EbiBit = EbiByte / 8 53 ) 54 55 type Size uint64 56 57 func (s Size) Uint64() uint64 { 58 return uint64(s) 59 } 60 61 func (s Size) Uint() uint { 62 return uint(s) 63 } 64 65 func (s Size) Int64() int64 { 66 return int64(s) 67 } 68 69 func (s Size) Int() int { 70 return int(s) 71 } 72 73 func (s Size) Float64() float64 { 74 return float64(s) 75 } 76 77 func (s *Size) UnmarshalText(text []byte) error { 78 text = bytes.TrimSpace(text) 79 if len(text) == 0 { 80 return nil 81 } 82 ns := sliceUnsafe.String(text) 83 nsu := strings.ToUpper(ns) 84 us, usu := "", "" 85 i := strings.IndexAny(nsu, "BKMGTPE") 86 if i >= 0 { 87 us = strings.TrimSpace(ns[i:]) 88 usu = strings.TrimSpace(nsu[i:]) 89 ns = strings.TrimSpace(nsu[:i]) 90 } 91 mul := uint64(1) 92 div := uint64(1) 93 if usu != "" { 94 switch usu[0] { 95 case 'B': 96 switch usu[1:] { 97 case "", "YTE": 98 case "IT": 99 div = 8 100 default: 101 return &UnknownSizeUnitError{Unit: us} 102 } 103 case 'K': 104 switch usu[1:] { 105 case "", "B", "BYTE", "ILOBYTE": 106 mul = 1000 107 case "IB", "IBYTE", "IBIBYTE": 108 mul = 1 << 10 109 case "BIT", "ILOBIT": 110 mul, div = 1000, 8 111 case "IBIT", "IBIBIT": 112 mul, div = 1<<10, 8 113 default: 114 return &UnknownSizeUnitError{Unit: us} 115 } 116 case 'M': 117 switch usu[1:] { 118 case "", "B", "BYTE", "EGABYTE": 119 mul = 1000 * 1000 120 case "IB", "IBYTE", "EBIBYTE": 121 mul = 1 << 20 122 case "BIT", "EGABIT": 123 mul, div = 1000*1000, 8 124 case "IBIT", "EBIBIT": 125 mul, div = 1<<20, 8 126 default: 127 return &UnknownSizeUnitError{Unit: us} 128 } 129 case 'G': 130 switch usu[1:] { 131 case "", "B", "BYTE", "IGABYTE": 132 mul = 1000 * 1000 * 1000 133 case "IB", "IBYTE", "IBIBYTE": 134 mul = 1 << 30 135 case "BIT", "IGABIT": 136 mul, div = 1000*1000*1000, 8 137 case "IBIT", "IBIBIT": 138 mul, div = 1<<20, 8 139 default: 140 return &UnknownSizeUnitError{Unit: us} 141 } 142 case 'T': 143 switch usu[1:] { 144 case "", "B", "BYTE", "ERABYTE": 145 mul = 1000 * 1000 * 1000 * 1000 146 case "IB", "IBYTE", "EBIBYTE": 147 mul = 1 << 40 148 case "BIT", "ERABIT": 149 mul, div = 1000*1000*1000*1000, 8 150 case "IBIT", "EBIBIT": 151 mul, div = 1<<40, 8 152 default: 153 return &UnknownSizeUnitError{Unit: us} 154 } 155 case 'P': 156 switch usu[1:] { 157 case "", "B", "BYTE", "ETABYTE": 158 mul = 1000 * 1000 * 1000 * 1000 * 1000 159 case "IB", "IBYTE", "EBIBYTE": 160 mul = 1 << 50 161 case "BIT", "ETABIT": 162 mul, div = 1000*1000*1000*1000*1000, 8 163 case "IBIT", "EBIBIT": 164 mul, div = 1<<50, 8 165 default: 166 return &UnknownSizeUnitError{Unit: us} 167 } 168 case 'E': 169 switch usu[1:] { 170 case "", "B", "BYTE", "XABYTE": 171 mul = 1000 * 1000 * 1000 * 1000 * 1000 * 1000 172 case "IB", "IBYTE", "BIBYTE": 173 mul = 1 << 60 174 case "BIT", "XABIT": 175 mul, div = 1000*1000*1000*1000*1000*1000, 8 176 case "IBIT", "BIBIT": 177 mul, div = 1<<60, 8 178 default: 179 return &UnknownSizeUnitError{Unit: us} 180 } 181 default: 182 panic("impossible") 183 } 184 } 185 n, err := strconv.ParseUint(ns, 10, 64) 186 if err != nil { 187 f, err := strconv.ParseFloat(ns, 64) 188 if err != nil { 189 return err 190 } 191 *s = (Size)(f * float64(mul) / float64(div)) 192 return nil 193 } 194 *s = (Size)(n * mul / div) 195 return nil 196 } 197 198 func (s *Size) yamlTypeError(value *yaml.Node, err error) error { 199 v := value.Value 200 if value.Tag != "!!seq" && value.Tag != "!!map" { 201 if len(v) > 10 { 202 v = " `" + v[:7] + "...`" 203 } else { 204 v = " `" + v + "`" 205 } 206 } 207 return &yaml.TypeError{Errors: []string{ 208 fmt.Sprintf("line %d: cannot unmarshal %s%s into %s, cause: %s", value.Line, value.Tag, v, reflect.TypeOf(s).Elem(), err.Error()), 209 }} 210 } 211 212 func (s *Size) UnmarshalYAML(value *yaml.Node) error { 213 if value.Kind == yaml.ScalarNode { 214 if err := s.UnmarshalText(stringUnsafe.Bytes(value.Value)); err != nil { 215 return s.yamlTypeError(value, err) 216 } 217 return nil 218 } 219 return s.yamlTypeError(value, nil) 220 } 221 222 func (s *Size) UnmarshalJSON(bytes []byte) error { 223 return s.UnmarshalText(bytes) 224 } 225 226 func (s Size) String() string { 227 switch { 228 case s < KiloByte: 229 return fmt.Sprintf("%dB", s) 230 case s < MegaByte: 231 return fmt.Sprintf("%fKB", float64(s)/KiloByte) 232 case s < GigaByte: 233 return fmt.Sprintf("%fMB", float64(s)/MegaByte) 234 case s < TeraByte: 235 return fmt.Sprintf("%fGB", float64(s)/GigaByte) 236 case s < PetaByte: 237 return fmt.Sprintf("%fTB", float64(s)/TeraByte) 238 case s < ExaByte: 239 return fmt.Sprintf("%fPB", float64(s)/PetaByte) 240 default: 241 return fmt.Sprintf("%fEB", float64(s)/ExaByte) 242 } 243 }