git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/toml/internal/tag/add.go (about)

     1  package tag
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"time"
     7  
     8  	"git.sr.ht/~pingoo/stdx/toml/internal"
     9  )
    10  
    11  // Add JSON tags to a data structure as expected by toml-test.
    12  func Add(key string, tomlData interface{}) interface{} {
    13  	// Switch on the data type.
    14  	switch orig := tomlData.(type) {
    15  	default:
    16  		panic(fmt.Sprintf("Unknown type: %T", tomlData))
    17  
    18  	// A table: we don't need to add any tags, just recurse for every table
    19  	// entry.
    20  	case map[string]interface{}:
    21  		typed := make(map[string]interface{}, len(orig))
    22  		for k, v := range orig {
    23  			typed[k] = Add(k, v)
    24  		}
    25  		return typed
    26  
    27  	// An array: we don't need to add any tags, just recurse for every table
    28  	// entry.
    29  	case []map[string]interface{}:
    30  		typed := make([]map[string]interface{}, len(orig))
    31  		for i, v := range orig {
    32  			typed[i] = Add("", v).(map[string]interface{})
    33  		}
    34  		return typed
    35  	case []interface{}:
    36  		typed := make([]interface{}, len(orig))
    37  		for i, v := range orig {
    38  			typed[i] = Add("", v)
    39  		}
    40  		return typed
    41  
    42  	// Datetime: tag as datetime.
    43  	case time.Time:
    44  		switch orig.Location() {
    45  		default:
    46  			return tag("datetime", orig.Format("2006-01-02T15:04:05.999999999Z07:00"))
    47  		case internal.LocalDatetime:
    48  			return tag("datetime-local", orig.Format("2006-01-02T15:04:05.999999999"))
    49  		case internal.LocalDate:
    50  			return tag("date-local", orig.Format("2006-01-02"))
    51  		case internal.LocalTime:
    52  			return tag("time-local", orig.Format("15:04:05.999999999"))
    53  		}
    54  
    55  	// Tag primitive values: bool, string, int, and float64.
    56  	case bool:
    57  		return tag("bool", fmt.Sprintf("%v", orig))
    58  	case string:
    59  		return tag("string", orig)
    60  	case int64:
    61  		return tag("integer", fmt.Sprintf("%d", orig))
    62  	case float64:
    63  		// Special case for nan since NaN == NaN is false.
    64  		if math.IsNaN(orig) {
    65  			return tag("float", "nan")
    66  		}
    67  		return tag("float", fmt.Sprintf("%v", orig))
    68  	}
    69  }
    70  
    71  func tag(typeName string, data interface{}) map[string]interface{} {
    72  	return map[string]interface{}{
    73  		"type":  typeName,
    74  		"value": data,
    75  	}
    76  }