package models import ( "bytes" "encoding/json" "errors" "fmt" "regexp" "strconv" "time" "codeberg.org/danjones000/my-log/tools" ) type Meta struct { Key string Value any } func (m Meta) MarshalText() ([]byte, error) { if regexp.MustCompile(`\s`).MatchString(m.Key) { return []byte{}, fmt.Errorf("whitespace is not allowed in key: %s", m.Key) } buff := &bytes.Buffer{} buff.WriteRune('@') buff.WriteString(m.Key) buff.WriteRune(' ') switch v := m.Value.(type) { default: return nil, fmt.Errorf("Unknown type %T", v) case nil: return []byte{}, nil case string: buff.WriteString(v) case int: buff.WriteString(strconv.Itoa(v)) case int64: buff.WriteString(strconv.FormatInt(v, 10)) case float64: buff.WriteString(strconv.FormatFloat(v, 'f', -1, 64)) case json.Number: buff.WriteString(v.String()) case json.RawMessage: buff.Write(v) case []byte: buff.Write(v) case byte: buff.WriteByte(v) case rune: buff.WriteString(string(v)) case bool: buff.WriteString(strconv.FormatBool(v)) case time.Time: buff.WriteString(v.Format(time.RFC3339)) } return buff.Bytes(), nil } func (m *Meta) UnmarshalText(in []byte) error { if len(in) == 0 { return newParsingError(errors.New("Unable to Unmarshal empty string")) } re := regexp.MustCompile("(?s)^@([^ ]+) (.*)( @end)?$") match := re.FindSubmatch(in) if len(match) == 0 { return newParsingError(fmt.Errorf("Failed to match %s", in)) } m.Key = string(match[1]) return m.processMeta(match[2]) } func (m *Meta) processMeta(in []byte) error { if len(in) == 0 { return newParsingError(errors.New("No value found")) } v := tools.ParseBytes(in) if v == "" { return newParsingError(errors.New("No value found")) } m.Value = v return nil }