« Back to Index

Go: custom toml unmarshal wrapper for string to int

View original Gist on GitHub

Tags: #go #serialization

custom toml unmarshal wrapper for string to int.go

package main

import (
	"fmt"
	"strconv"
	"strings"

	toml "github.com/pelletier/go-toml"
)

type StringInt struct {
	int
}

func (si *StringInt) UnmarshalText(text []byte) error {
	var err error

	s := string(text)

	if si.int, err = strconv.Atoi(s); err == nil {
		return nil
	}

	if f, err := strconv.ParseFloat(s, 32); err == nil {
		intfl := int(f)
		if intfl == 0 {
			si.int = 1
		} else {
			si.int = intfl
		}
		return nil
	}

	if strings.Contains(s, ".") {
		segs := strings.Split(s, ".")
		if len(segs) == 3 {
			// yes this could be more robust but for now I'm trusting a string with a "." means semver :grimace:
			if segs[0] != "0" {
				if si.int, err = strconv.Atoi(segs[0]); err == nil {
					return nil
				}
			} else {
				si.int = 1
				return nil
			}

		}
	}

	return fmt.Errorf("unsupported: %s", text)
}

type FileTest struct {
	Version1 StringInt `toml:"version1"`
	Version2 StringInt `toml:"version2"`
	Version3 StringInt `toml:"version3"`
	Version4 StringInt `toml:"version4"`
	Version5 StringInt `toml:"version5"`
	Version6 StringInt `toml:"version6"`
	Version7 StringInt `toml:"version7"`
}

func main() {
	data := []byte(`
	version1 = "1"
	version2 = 1
	version3 = "0.1.0"
	version4 = "1.0.0"
	version5 = 0.1
	version6 = "0.2.0"
	version7 = "2.0.0"
	`)

	file := FileTest{}
	toml.Unmarshal(data, &file)
	format := "version1 (\"1\"):\n\t%d\nversion2 (1):\n\t%d\nversion3 (\"0.1.0\"):\n\t%d\nversion4 (\"1.0.0\"):\n\t%d\nversion5 (0.1):\n\t%d\nversion6 (\"0.2.0\"):\n\t%d\nversion7 (\"2.0.0\"):\n\t%d\n"
	fmt.Printf(format, file.Version1.int, file.Version2.int, file.Version3.int, file.Version4.int, file.Version5.int, file.Version6.int, file.Version7.int)
}