package entity import ( "fmt" "strconv" "strings" ) var DefaultLocale = DimensionLocalRU type DimensionLocale uint8 const ( DimensionLocalUnspecified DimensionLocale = iota DimensionLocalRU dimensionLocalEnd ) type DimensionKind uint8 func (k DimensionKind) GetPos() float64 { switch k { case DimensionKindMilimeter: return 1 case DimensionKindCentimeter: return 10 case DimensionKindMeter: return 1000 default: return 0 } } func (k DimensionKind) String() string { m := getLocaleKindToStringMap()[DefaultLocale] return m[k] } const ( DimensionKindUnspecified DimensionKind = iota DimensionKindMilimeter DimensionKindCentimeter DimensionKindMeter ) type Dimension struct { Value float64 Kind DimensionKind } func (d Dimension) MarshalText() ([]byte, error) { value := strconv.FormatFloat(d.Value, 'f', 4, 64) + " " + d.Kind.String() return []byte(value), nil } func (d *Dimension) UnmarshalText(data []byte) (err error) { *d, err = ParseDimention(string(data), DefaultLocale) return err } func (d Dimension) AdjustTo(kind DimensionKind) Dimension { from := d.Kind.GetPos() to := kind.GetPos() switch { case from < to: mult := to / from return Dimension{ Kind: kind, Value: d.Value / float64(mult), } case from > to: mult := from / to return Dimension{ Kind: kind, Value: d.Value * float64(mult), } } return d } func ParseDimention(value string, locale DimensionLocale) (Dimension, error) { switch locale { case DimensionLocalRU: default: return Dimension{}, SimpleError("unknown locale for parse") } dimensionStrToKind := getLocaleToKindMap()[locale] lastSpaceIdx := strings.LastIndex(value, " ") if lastSpaceIdx == -1 { return Dimension{}, SimpleError("expected 2 values after split for value " + value) } var splitted [2]string splitted[0] = strings.ReplaceAll(value[:lastSpaceIdx], " ", "") splitted[1] = value[lastSpaceIdx+1:] var out Dimension var ok bool out.Kind, ok = dimensionStrToKind[splitted[1]] if !ok { return Dimension{}, SimpleError("dimension map not found for kind " + splitted[1]) } var err error out.Value, err = strconv.ParseFloat(splitted[0], 64) if err != nil { return Dimension{}, fmt.Errorf("parsing value: %w", err) } return out, nil } func NewMilimeterDimension(value float64) Dimension { return Dimension{ Value: value, Kind: DimensionKindMilimeter, } } func getLocaleToKindMap() map[DimensionLocale]map[string]DimensionKind { return map[DimensionLocale]map[string]DimensionKind{ DimensionLocalRU: { "мм": DimensionKindMilimeter, "см": DimensionKindCentimeter, "м": DimensionKindMeter, }, } } func getLocaleKindToStringMap() map[DimensionLocale]map[DimensionKind]string { return map[DimensionLocale]map[DimensionKind]string{ DimensionLocalRU: { DimensionKindMilimeter: "мм", DimensionKindCentimeter: "см", DimensionKindMeter: "м", }, } }