package fin /* writer.go Copyright 2025 Sharkk, sharkk.net Authors: Sky Johnson */ import ( "fmt" "io" "strconv" ) // Write serializes the data to the provided writer func (d *Data) Write(w io.Writer) error { return writeMap(w, d.data, 0) } func Save(w io.Writer, d *Data) error { return d.Write(w) } // Helper for writing indentation func writeIndent(w io.Writer, level int) error { for range level { if _, err := w.Write([]byte{'\t'}); err != nil { return err } } return nil } // Helper for writing numbers using pooled buffers func writeNumber(w io.Writer, val any) error { buffer := GetByteSlice() defer PutByteSlice(buffer) switch v := val.(type) { case int: *buffer = strconv.AppendInt((*buffer)[:0], int64(v), 10) case float64: *buffer = strconv.AppendFloat((*buffer)[:0], v, 'g', -1, 64) default: return fmt.Errorf("not a number type") } _, err := w.Write(*buffer) return err } // Consolidated string writing with escaping func writeString(w io.Writer, s string, quote bool) error { if quote { if _, err := io.WriteString(w, "\""); err != nil { return err } } for i := range len(s) { c := s[i] var escaped string switch c { case '"': escaped = "\\\"" case '\\': escaped = "\\\\" case '\n': escaped = "\\n" case '\t': escaped = "\\t" default: if _, err := w.Write([]byte{c}); err != nil { return err } continue } if _, err := io.WriteString(w, escaped); err != nil { return err } } if quote { if _, err := io.WriteString(w, "\""); err != nil { return err } } return nil } // Unified value writing logic func writeValue(w io.Writer, value any, level int, addSpace, addNewline bool) error { if addSpace { if _, err := w.Write([]byte{' '}); err != nil { return err } } switch v := value.(type) { case nil: // Do nothing for nil case string: if err := writeString(w, v, true); err != nil { return err } case int, float64: if err := writeNumber(w, v); err != nil { return err } case bool: val := "false" if v { val = "true" } if _, err := io.WriteString(w, val); err != nil { return err } case map[string]any: if _, err := io.WriteString(w, "{\n"); err != nil { return err } if err := writeMap(w, v, level+1); err != nil { return err } if err := writeIndent(w, level); err != nil { return err } if _, err := io.WriteString(w, "}"); err != nil { return err } case []any: if _, err := io.WriteString(w, "{\n"); err != nil { return err } if err := writeArray(w, v, level+1); err != nil { return err } if err := writeIndent(w, level); err != nil { return err } if _, err := io.WriteString(w, "}"); err != nil { return err } } if addNewline { if _, err := io.WriteString(w, "\n"); err != nil { return err } } return nil } func writeMap(w io.Writer, data map[string]any, level int) error { for key, value := range data { if err := writeIndent(w, level); err != nil { return err } if _, err := io.WriteString(w, key); err != nil { return err } // Handle combined value+object case if m, ok := value.(map[string]any); ok && len(m) > 1 { if simpleValue, hasValue := m["value"]; hasValue { if err := writeValue(w, simpleValue, level, true, false); err != nil { return err } if _, err := io.WriteString(w, " {\n"); err != nil { return err } for k, v := range m { if k != "value" { if err := writeIndent(w, level+1); err != nil { return err } if _, err := io.WriteString(w, k); err != nil { return err } if err := writeValue(w, v, level+1, true, true); err != nil { return err } } } if err := writeIndent(w, level); err != nil { return err } if _, err := io.WriteString(w, "}\n"); err != nil { return err } continue } } if err := writeValue(w, value, level, true, true); err != nil { return err } } return nil } func writeArray(w io.Writer, array []any, level int) error { for _, item := range array { if err := writeIndent(w, level); err != nil { return err } if err := writeValue(w, item, level, true, true); err != nil { return err } } return nil }