package datasizeunit import ( "errors" "fmt" "math" "regexp" "strconv" "strings" ) type Bits struct { bits float64 } func (b Bits) ToBits() float64 { return b.bits } func (b Bits) ToBytes() float64 { return b.bits / 8 } func FromBytesInt64(i int64) Bits { return Bits{float64(i) * 8} } var datarateRegex = regexp.MustCompile(`^([-0-9\.]*)\s*(bit|(|K|Ki|M|Mi|G|Gi|T|Ti)([bB]))$`) func (r *Bits) UnmarshalYAML(u func(interface{}, bool) error) (_ error) { var s string err := u(&s, false) if err != nil { return err } genericErr := func(err error) error { var buf strings.Builder fmt.Fprintf(&buf, "cannot parse %q using regex %s", s, datarateRegex) if err != nil { fmt.Fprintf(&buf, ": %s", err) } return errors.New(buf.String()) } match := datarateRegex.FindStringSubmatch(s) if match == nil { return genericErr(nil) } bps, err := strconv.ParseFloat(match[1], 64) if err != nil { return genericErr(err) } if match[2] == "bit" { if math.Round(bps) != bps { return genericErr(fmt.Errorf("unit bit must be an integer value")) } r.bits = bps return nil } factorMap := map[string]uint64{ "": 1, "K": 1e3, "M": 1e6, "G": 1e9, "T": 1e12, "Ki": 1 << 10, "Mi": 1 << 20, "Gi": 1 << 30, "Ti": 1 << 40, } factor, ok := factorMap[match[3]] if !ok { panic(match) } baseUnitFactorMap := map[string]uint64{ "b": 1, "B": 8, } baseUnitFactor, ok := baseUnitFactorMap[match[4]] if !ok { panic(match) } r.bits = bps * float64(factor) * float64(baseUnitFactor) return nil }